1 /* EINA - EFL data type library
2 * Copyright (C) 2011 Vincent Torri
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>.
19 #ifndef EINA_INLINE_LOCK_POSIX_X_
20 #define EINA_INLINE_LOCK_POSIX_X_
31 #ifdef EINA_HAVE_DEBUG_THREADS
33 #define EINA_LOCK_DEBUG_BT_NUM 64
34 typedef void (*Eina_Lock_Bt_Func) ();
37 typedef struct _Eina_Lock Eina_Lock;
41 pthread_mutex_t mutex;
42 #ifdef EINA_HAVE_DEBUG_THREADS
43 pthread_t lock_thread_id;
44 Eina_Lock_Bt_Func lock_bt[EINA_LOCK_DEBUG_BT_NUM];
50 EAPI extern Eina_Bool _eina_threads_activated;
52 #ifdef EINA_HAVE_DEBUG_THREADS
53 # include <sys/time.h>
55 EAPI extern int _eina_threads_debug;
56 EAPI extern pthread_t _eina_main_loop;
59 static inline Eina_Bool
60 eina_lock_new(Eina_Lock *mutex)
62 pthread_mutexattr_t attr;
64 #ifdef EINA_HAVE_DEBUG_THREADS
65 assert(pthread_equal(_eina_main_loop, pthread_self()));
68 if (pthread_mutexattr_init(&attr) != 0)
70 /* use errorcheck locks. detect deadlocks.
71 #ifdef PTHREAD_MUTEX_RECURSIVE
72 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
76 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0)
78 #ifdef EINA_HAVE_DEBUG_THREADS
79 memset(mutex, 0, sizeof(Eina_Lock));
81 if (pthread_mutex_init(&(mutex->mutex), &attr) != 0)
84 pthread_mutexattr_destroy(&attr);
90 eina_lock_free(Eina_Lock *mutex)
92 #ifdef EINA_HAVE_DEBUG_THREADS
93 assert(pthread_equal(_eina_main_loop, pthread_self()));
96 pthread_mutex_destroy(&(mutex->mutex));
97 #ifdef EINA_HAVE_DEBUG_THREADS
98 memset(mutex, 0, sizeof(Eina_Lock));
102 static inline Eina_Lock_Result
103 eina_lock_take(Eina_Lock *mutex)
105 Eina_Lock_Result ret = EINA_LOCK_FAIL;
108 #ifdef EINA_HAVE_ON_OFF_THREADS
109 if (!_eina_threads_activated)
111 #ifdef EINA_HAVE_DEBUG_THREADS
112 assert(pthread_equal(_eina_main_loop, pthread_self()));
114 return EINA_LOCK_FAIL;
118 #ifdef EINA_HAVE_DEBUG_THREADS
119 if (_eina_threads_debug)
121 struct timeval t0, t1;
124 gettimeofday(&t0, NULL);
125 pthread_mutex_lock(&(x));
126 gettimeofday(&t1, NULL);
128 dt = (t1.tv_sec - t0.tv_sec) * 1000000;
129 if (t1.tv_usec > t0.tv_usec)
130 dt += (t1.tv_usec - t0.tv_usec);
132 dt -= t0.tv_usec - t1.tv_usec;
135 if (dt > _eina_threads_debug) abort();
138 ok = pthread_mutex_lock(&(mutex->mutex));
139 if (ok == 0) ret = EINA_LOCK_SUCCEED;
140 else if (ok == EDEADLK)
142 printf("ERROR ERROR: DEADLOCK on lock %p\n", mutex);
143 ret = EINA_LOCK_DEADLOCK; // magic
145 #ifdef EINA_HAVE_DEBUG_THREADS
147 mutex->lock_thread_id = pthread_self();
148 mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
153 static inline Eina_Lock_Result
154 eina_lock_take_try(Eina_Lock *mutex)
156 Eina_Lock_Result ret = EINA_LOCK_FAIL;
159 #ifdef EINA_HAVE_ON_OFF_THREADS
160 if (!_eina_threads_activated)
162 #ifdef EINA_HAVE_DEBUG_THREADS
163 assert(pthread_equal(_eina_main_loop, pthread_self()));
165 return EINA_LOCK_FAIL;
169 #ifdef EINA_HAVE_DEBUG_THREADS
170 if (!_eina_threads_activated)
171 assert(pthread_equal(_eina_main_loop, pthread_self()));
174 ok = pthread_mutex_trylock(&(mutex->mutex));
175 if (ok == 0) ret = EINA_LOCK_SUCCEED;
176 else if (ok == EDEADLK)
178 printf("ERROR ERROR: DEADLOCK on trylock %p\n", mutex);
179 ret = EINA_LOCK_DEADLOCK; // magic
181 #ifdef EINA_HAVE_DEBUG_THREADS
182 if (ret == EINA_LOCK_SUCCEED)
185 mutex->lock_thread_id = pthread_self();
186 mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
192 static inline Eina_Lock_Result
193 eina_lock_release(Eina_Lock *mutex)
195 Eina_Lock_Result ret;
197 #ifdef EINA_HAVE_ON_OFF_THREADS
198 if (!_eina_threads_activated)
200 #ifdef EINA_HAVE_DEBUG_THREADS
201 assert(pthread_equal(_eina_main_loop, pthread_self()));
203 return EINA_LOCK_FAIL;
207 #ifdef EINA_HAVE_DEBUG_THREADS
209 mutex->lock_thread_id = 0;
210 memset(mutex->lock_bt, 0, EINA_LOCK_DEBUG_BT_NUM * sizeof(Eina_Lock_Bt_Func));
211 mutex->lock_bt_num = 0;
213 ret = (pthread_mutex_unlock(&(mutex->mutex)) == 0) ?
214 EINA_LOCK_SUCCEED : EINA_LOCK_FAIL;
219 eina_lock_debug(Eina_Lock *mutex)
221 #ifdef EINA_HAVE_DEBUG_THREADS
222 printf("lock %p, locked: %i, by %i\n",
223 mutex, (int)mutex->locked, (int)mutex->lock_thread_id);
224 backtrace_symbols_fd((void **)mutex->lock_bt, mutex->lock_bt_num, 1);