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_
26 # define EINA_UNUSED __attribute__((unused))
40 #include <semaphore.h>
45 #ifdef EINA_HAVE_DEBUG_THREADS
50 #define EINA_LOCK_DEBUG_BT_NUM 64
51 typedef void (*Eina_Lock_Bt_Func) ();
53 #include "eina_inlist.h"
56 typedef struct _Eina_Lock Eina_Lock;
57 typedef struct _Eina_RWLock Eina_RWLock;
58 typedef struct _Eina_Condition Eina_Condition;
59 typedef pthread_key_t Eina_TLS;
60 typedef sem_t Eina_Semaphore;
64 #ifdef EINA_HAVE_DEBUG_THREADS
67 pthread_mutex_t mutex;
68 #ifdef EINA_HAVE_DEBUG_THREADS
69 pthread_t lock_thread_id;
70 Eina_Lock_Bt_Func lock_bt[EINA_LOCK_DEBUG_BT_NUM];
76 struct _Eina_Condition
79 pthread_cond_t condition;
84 pthread_rwlock_t mutex;
85 #ifdef EINA_HAVE_DEBUG_THREADS
86 pthread_t lock_thread_wid;
90 EAPI extern Eina_Bool _eina_threads_activated;
92 #ifdef EINA_HAVE_DEBUG_THREADS
93 EAPI extern int _eina_threads_debug;
94 EAPI extern pthread_t _eina_main_loop;
95 EAPI extern pthread_mutex_t _eina_tracking_lock;
96 EAPI extern Eina_Inlist *_eina_tracking;
100 eina_lock_debug(const Eina_Lock *mutex)
102 #ifdef EINA_HAVE_DEBUG_THREADS
103 printf("lock %p, locked: %i, by %i\n",
104 mutex, (int)mutex->locked, (int)mutex->lock_thread_id);
105 backtrace_symbols_fd((void **)mutex->lock_bt, mutex->lock_bt_num, 1);
111 static inline Eina_Bool
112 eina_lock_new(Eina_Lock *mutex)
114 pthread_mutexattr_t attr;
116 #ifdef EINA_HAVE_DEBUG_THREADS
117 if (!_eina_threads_activated)
118 assert(pthread_equal(_eina_main_loop, pthread_self()));
121 if (pthread_mutexattr_init(&attr) != 0)
123 /* NOTE: PTHREAD_MUTEX_RECURSIVE is not allowed at all, you will break on/off
124 feature for sure with that change. */
125 #ifdef EINA_HAVE_DEBUG_THREADS
126 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0)
128 memset(mutex, 0, sizeof(Eina_Lock));
130 if (pthread_mutex_init(&(mutex->mutex), &attr) != 0)
133 pthread_mutexattr_destroy(&attr);
139 eina_lock_free(Eina_Lock *mutex)
141 #ifdef EINA_HAVE_DEBUG_THREADS
142 if (!_eina_threads_activated)
143 assert(pthread_equal(_eina_main_loop, pthread_self()));
146 pthread_mutex_destroy(&(mutex->mutex));
147 #ifdef EINA_HAVE_DEBUG_THREADS
148 memset(mutex, 0, sizeof(Eina_Lock));
152 static inline Eina_Lock_Result
153 eina_lock_take(Eina_Lock *mutex)
155 Eina_Lock_Result ret = EINA_LOCK_FAIL;
158 #ifdef EINA_HAVE_ON_OFF_THREADS
159 if (!_eina_threads_activated)
161 #ifdef EINA_HAVE_DEBUG_THREADS
162 assert(pthread_equal(_eina_main_loop, pthread_self()));
164 return EINA_LOCK_SUCCEED;
168 #ifdef EINA_HAVE_DEBUG_THREADS
169 if (_eina_threads_debug)
171 struct timeval t0, t1;
174 gettimeofday(&t0, NULL);
175 ok = pthread_mutex_lock(&(mutex->mutex));
176 gettimeofday(&t1, NULL);
178 dt = (t1.tv_sec - t0.tv_sec) * 1000000;
179 if (t1.tv_usec > t0.tv_usec)
180 dt += (t1.tv_usec - t0.tv_usec);
182 dt -= t0.tv_usec - t1.tv_usec;
185 if (dt > _eina_threads_debug) abort();
190 ok = pthread_mutex_lock(&(mutex->mutex));
191 #ifdef EINA_HAVE_DEBUG_THREADS
195 if (ok == 0) ret = EINA_LOCK_SUCCEED;
196 else if (ok == EDEADLK)
198 printf("ERROR ERROR: DEADLOCK on lock %p\n", mutex);
199 eina_lock_debug(mutex);
200 ret = EINA_LOCK_DEADLOCK; // magic
201 #ifdef EINA_HAVE_DEBUG_THREADS
202 if (_eina_threads_debug) abort();
206 #ifdef EINA_HAVE_DEBUG_THREADS
208 mutex->lock_thread_id = pthread_self();
209 mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
211 pthread_mutex_lock(&_eina_tracking_lock);
212 _eina_tracking = eina_inlist_append(_eina_tracking,
213 EINA_INLIST_GET(mutex));
214 pthread_mutex_unlock(&_eina_tracking_lock);
220 static inline Eina_Lock_Result
221 eina_lock_take_try(Eina_Lock *mutex)
223 Eina_Lock_Result ret = EINA_LOCK_FAIL;
226 #ifdef EINA_HAVE_ON_OFF_THREADS
227 if (!_eina_threads_activated)
229 #ifdef EINA_HAVE_DEBUG_THREADS
230 assert(pthread_equal(_eina_main_loop, pthread_self()));
232 return EINA_LOCK_SUCCEED;
236 #ifdef EINA_HAVE_DEBUG_THREADS
237 if (!_eina_threads_activated)
238 assert(pthread_equal(_eina_main_loop, pthread_self()));
241 ok = pthread_mutex_trylock(&(mutex->mutex));
242 if (ok == 0) ret = EINA_LOCK_SUCCEED;
243 else if (ok == EDEADLK)
245 printf("ERROR ERROR: DEADLOCK on trylock %p\n", mutex);
246 ret = EINA_LOCK_DEADLOCK; // magic
248 #ifdef EINA_HAVE_DEBUG_THREADS
249 if (ret == EINA_LOCK_SUCCEED)
252 mutex->lock_thread_id = pthread_self();
253 mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
255 pthread_mutex_lock(&_eina_tracking_lock);
256 _eina_tracking = eina_inlist_append(_eina_tracking,
257 EINA_INLIST_GET(mutex));
258 pthread_mutex_unlock(&_eina_tracking_lock);
264 static inline Eina_Lock_Result
265 eina_lock_release(Eina_Lock *mutex)
267 Eina_Lock_Result ret;
269 #ifdef EINA_HAVE_ON_OFF_THREADS
270 if (!_eina_threads_activated)
272 #ifdef EINA_HAVE_DEBUG_THREADS
273 assert(pthread_equal(_eina_main_loop, pthread_self()));
275 return EINA_LOCK_SUCCEED;
279 #ifdef EINA_HAVE_DEBUG_THREADS
280 pthread_mutex_lock(&_eina_tracking_lock);
281 _eina_tracking = eina_inlist_remove(_eina_tracking,
282 EINA_INLIST_GET(mutex));
283 pthread_mutex_unlock(&_eina_tracking_lock);
286 mutex->lock_thread_id = 0;
287 memset(mutex->lock_bt, 0, EINA_LOCK_DEBUG_BT_NUM * sizeof(Eina_Lock_Bt_Func));
288 mutex->lock_bt_num = 0;
290 ret = (pthread_mutex_unlock(&(mutex->mutex)) == 0) ?
291 EINA_LOCK_SUCCEED : EINA_LOCK_FAIL;
295 static inline Eina_Bool
296 eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
298 #ifdef EINA_HAVE_DEBUG_THREADS
299 assert(mutex != NULL);
300 if (!_eina_threads_activated)
301 assert(pthread_equal(_eina_main_loop, pthread_self()));
302 memset(cond, 0, sizeof (Eina_Condition));
306 if (pthread_cond_init(&cond->condition, NULL) != 0)
308 #ifdef EINA_HAVE_DEBUG_THREADS
310 printf("eina_condition_new on already initialized Eina_Condition\n");
319 eina_condition_free(Eina_Condition *cond)
321 #ifdef EINA_HAVE_DEBUG_THREADS
322 if (!_eina_threads_activated)
323 assert(pthread_equal(_eina_main_loop, pthread_self()));
326 pthread_cond_destroy(&(cond->condition));
327 #ifdef EINA_HAVE_DEBUG_THREADS
328 memset(cond, 0, sizeof (Eina_Condition));
332 static inline Eina_Bool
333 eina_condition_wait(Eina_Condition *cond)
337 #ifdef EINA_HAVE_DEBUG_THREADS
338 assert(_eina_threads_activated);
339 assert(cond->lock != NULL);
341 pthread_mutex_lock(&_eina_tracking_lock);
342 _eina_tracking = eina_inlist_remove(_eina_tracking,
343 EINA_INLIST_GET(cond->lock));
344 pthread_mutex_unlock(&_eina_tracking_lock);
347 r = pthread_cond_wait(&(cond->condition),
348 &(cond->lock->mutex)) == 0 ? EINA_TRUE : EINA_FALSE;
350 #ifdef EINA_HAVE_DEBUG_THREADS
351 pthread_mutex_lock(&_eina_tracking_lock);
352 _eina_tracking = eina_inlist_append(_eina_tracking,
353 EINA_INLIST_GET(cond->lock));
354 pthread_mutex_unlock(&_eina_tracking_lock);
360 static inline Eina_Bool
361 eina_condition_timedwait(Eina_Condition *cond, double t)
366 #ifdef EINA_HAVE_DEBUG_THREADS
367 assert(_eina_threads_activated);
368 assert(cond->lock != NULL);
370 pthread_mutex_lock(&_eina_tracking_lock);
371 _eina_tracking = eina_inlist_remove(_eina_tracking,
372 EINA_INLIST_GET(cond->lock));
373 pthread_mutex_unlock(&_eina_tracking_lock);
377 tv.tv_nsec = (t - (double) tv.tv_sec) * 1000000000;
379 r = pthread_cond_timedwait(&(cond->condition),
380 &(cond->lock->mutex),
382 EINA_TRUE : EINA_FALSE;
384 #ifdef EINA_HAVE_DEBUG_THREADS
385 pthread_mutex_lock(&_eina_tracking_lock);
386 _eina_tracking = eina_inlist_append(_eina_tracking,
387 EINA_INLIST_GET(cond->lock));
388 pthread_mutex_unlock(&_eina_tracking_lock);
394 static inline Eina_Bool
395 eina_condition_broadcast(Eina_Condition *cond)
397 #ifdef EINA_HAVE_DEBUG_THREADS
398 assert(cond->lock != NULL);
401 return pthread_cond_broadcast(&(cond->condition)) == 0 ? EINA_TRUE : EINA_FALSE;
404 static inline Eina_Bool
405 eina_condition_signal(Eina_Condition *cond)
407 #ifdef EINA_HAVE_DEBUG_THREADS
408 assert(cond->lock != NULL);
411 return pthread_cond_signal(&(cond->condition)) == 0 ? EINA_TRUE : EINA_FALSE;
414 static inline Eina_Bool
415 eina_rwlock_new(Eina_RWLock *mutex)
417 #ifdef EINA_HAVE_DEBUG_THREADS
418 if (!_eina_threads_activated)
419 assert(pthread_equal(_eina_main_loop, pthread_self()));
422 if (pthread_rwlock_init(&(mutex->mutex), NULL) != 0)
428 eina_rwlock_free(Eina_RWLock *mutex)
430 #ifdef EINA_HAVE_DEBUG_THREADS
431 if (!_eina_threads_activated)
432 assert(pthread_equal(_eina_main_loop, pthread_self()));
435 pthread_rwlock_destroy(&(mutex->mutex));
438 static inline Eina_Lock_Result
439 eina_rwlock_take_read(Eina_RWLock *mutex)
441 #ifdef EINA_HAVE_ON_OFF_THREADS
442 if (!_eina_threads_activated)
444 #ifdef EINA_HAVE_DEBUG_THREADS
445 assert(pthread_equal(_eina_main_loop, pthread_self()));
447 return EINA_LOCK_SUCCEED;
451 if (pthread_rwlock_rdlock(&(mutex->mutex)) != 0)
452 return EINA_LOCK_FAIL;
453 return EINA_LOCK_SUCCEED;
456 static inline Eina_Lock_Result
457 eina_rwlock_take_write(Eina_RWLock *mutex)
459 #ifdef EINA_HAVE_ON_OFF_THREADS
460 if (!_eina_threads_activated)
462 #ifdef EINA_HAVE_DEBUG_THREADS
463 assert(pthread_equal(_eina_main_loop, pthread_self()));
465 return EINA_LOCK_SUCCEED;
469 if (pthread_rwlock_wrlock(&(mutex->mutex)) != 0)
470 return EINA_LOCK_FAIL;
471 return EINA_LOCK_SUCCEED;
474 static inline Eina_Lock_Result
475 eina_rwlock_release(Eina_RWLock *mutex)
477 #ifdef EINA_HAVE_ON_OFF_THREADS
478 if (!_eina_threads_activated)
480 #ifdef EINA_HAVE_DEBUG_THREADS
481 assert(pthread_equal(_eina_main_loop, pthread_self()));
483 return EINA_LOCK_SUCCEED;
487 if (pthread_rwlock_unlock(&(mutex->mutex)) != 0)
488 return EINA_LOCK_FAIL;
489 return EINA_LOCK_SUCCEED;
492 static inline Eina_Bool
493 eina_tls_new(Eina_TLS *key)
495 if (pthread_key_create(key, NULL) != 0)
501 eina_tls_free(Eina_TLS key)
503 pthread_key_delete(key);
507 eina_tls_get(Eina_TLS key)
509 return pthread_getspecific(key);
512 static inline Eina_Bool
513 eina_tls_set(Eina_TLS key, const void *data)
515 if (pthread_setspecific(key, data) != 0)
520 static inline Eina_Bool
521 eina_semaphore_new(Eina_Semaphore *sem, int count_init)
523 if (!sem || (count_init <= 0))
526 return (sem_init(sem, count_init, 1) == 0) ? EINA_TRUE : EINA_FALSE;
529 static inline Eina_Bool
530 eina_semaphore_free(Eina_Semaphore *sem)
535 return (sem_destroy(sem) == 0) ? EINA_TRUE : EINA_FALSE;
538 static inline Eina_Bool
539 eina_semaphore_lock(Eina_Semaphore *sem)
544 return (sem_wait(sem) == 0) ? EINA_TRUE : EINA_FALSE;
547 static inline Eina_Bool
548 eina_semaphore_release(Eina_Semaphore *sem, int count_release EINA_UNUSED)
553 return (sem_post(sem) == 0) ? EINA_TRUE : EINA_FALSE;