EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / include / eina_inline_lock_posix.x
1 /* EINA - EFL data type library
2  * Copyright (C) 2011 Vincent Torri
3  *
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.
8  *
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.
13  *
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/>.
17  */
18
19 #ifndef EINA_INLINE_LOCK_POSIX_X_
20 #define EINA_INLINE_LOCK_POSIX_X_
21
22 #ifdef EINA_UNUSED
23 # undef EINA_UNUSED
24 #endif
25 #ifdef __GNUC__
26 # define EINA_UNUSED __attribute__((unused))
27 #else
28 # define EINA_UNUSED
29 #endif
30
31 #include <errno.h>
32 #ifndef __USE_UNIX98
33 # define __USE_UNIX98
34 # include <pthread.h>
35 # undef __USE_UNIX98
36 #else
37 # include <pthread.h>
38 #endif
39
40 #include <semaphore.h>
41
42 #include <sys/time.h>
43 #include <stdio.h>
44
45 #ifdef EINA_HAVE_DEBUG_THREADS
46 #include <stdlib.h>
47 #include <string.h>
48 #include <assert.h>
49 #include <execinfo.h>
50 #define EINA_LOCK_DEBUG_BT_NUM 64
51 typedef void (*Eina_Lock_Bt_Func) ();
52
53 #include "eina_inlist.h"
54 #endif
55
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;
61
62 struct _Eina_Lock
63 {
64 #ifdef EINA_HAVE_DEBUG_THREADS
65    EINA_INLIST;
66 #endif
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];
71    int               lock_bt_num;
72    Eina_Bool         locked : 1;
73 #endif
74 };
75
76 struct _Eina_Condition
77 {
78    Eina_Lock      *lock;
79    pthread_cond_t  condition;
80 };
81
82 struct _Eina_RWLock
83 {
84    pthread_rwlock_t mutex;
85 #ifdef EINA_HAVE_DEBUG_THREADS
86    pthread_t        lock_thread_wid;
87 #endif
88 };
89
90 EAPI extern Eina_Bool _eina_threads_activated;
91
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;
97 #endif
98
99 static inline void
100 eina_lock_debug(const Eina_Lock *mutex)
101 {
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);
106 #else
107    (void) mutex;
108 #endif
109 }
110
111 static inline Eina_Bool
112 eina_lock_new(Eina_Lock *mutex)
113 {
114    pthread_mutexattr_t attr;
115
116 #ifdef EINA_HAVE_DEBUG_THREADS
117    if (!_eina_threads_activated)
118      assert(pthread_equal(_eina_main_loop, pthread_self()));
119 #endif
120
121    if (pthread_mutexattr_init(&attr) != 0)
122      return EINA_FALSE;
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)
127      return EINA_FALSE;
128    memset(mutex, 0, sizeof(Eina_Lock));
129 #endif
130    if (pthread_mutex_init(&(mutex->mutex), &attr) != 0)
131      return EINA_FALSE;
132
133    pthread_mutexattr_destroy(&attr);
134
135    return EINA_TRUE;
136 }
137
138 static inline void
139 eina_lock_free(Eina_Lock *mutex)
140 {
141 #ifdef EINA_HAVE_DEBUG_THREADS
142    if (!_eina_threads_activated)
143      assert(pthread_equal(_eina_main_loop, pthread_self()));
144 #endif
145
146    pthread_mutex_destroy(&(mutex->mutex));
147 #ifdef EINA_HAVE_DEBUG_THREADS
148    memset(mutex, 0, sizeof(Eina_Lock));
149 #endif
150 }
151
152 static inline Eina_Lock_Result
153 eina_lock_take(Eina_Lock *mutex)
154 {
155    Eina_Lock_Result ret = EINA_LOCK_FAIL;
156    int ok;
157
158 #ifdef EINA_HAVE_ON_OFF_THREADS
159    if (!_eina_threads_activated)
160      {
161 #ifdef EINA_HAVE_DEBUG_THREADS
162         assert(pthread_equal(_eina_main_loop, pthread_self()));
163 #endif
164         return EINA_LOCK_SUCCEED;
165      }
166 #endif
167
168 #ifdef EINA_HAVE_DEBUG_THREADS
169    if (_eina_threads_debug)
170      {
171         struct timeval t0, t1;
172         int dt;
173
174         gettimeofday(&t0, NULL);
175         ok = pthread_mutex_lock(&(mutex->mutex));
176         gettimeofday(&t1, NULL);
177
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);
181         else
182            dt -= t0.tv_usec - t1.tv_usec;
183         dt /= 1000;
184
185         if (dt > _eina_threads_debug) abort();
186      }
187    else
188      {
189 #endif
190         ok = pthread_mutex_lock(&(mutex->mutex));
191 #ifdef EINA_HAVE_DEBUG_THREADS
192      }
193 #endif
194
195    if (ok == 0) ret = EINA_LOCK_SUCCEED;
196    else if (ok == EDEADLK)
197      {
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();
203 #endif
204      }
205
206 #ifdef EINA_HAVE_DEBUG_THREADS
207    mutex->locked = 1;
208    mutex->lock_thread_id = pthread_self();
209    mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
210
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);
215 #endif
216
217    return ret;
218 }
219
220 static inline Eina_Lock_Result
221 eina_lock_take_try(Eina_Lock *mutex)
222 {
223    Eina_Lock_Result ret = EINA_LOCK_FAIL;
224    int ok;
225
226 #ifdef EINA_HAVE_ON_OFF_THREADS
227    if (!_eina_threads_activated)
228      {
229 #ifdef EINA_HAVE_DEBUG_THREADS
230         assert(pthread_equal(_eina_main_loop, pthread_self()));
231 #endif
232         return EINA_LOCK_SUCCEED;
233      }
234 #endif
235
236 #ifdef EINA_HAVE_DEBUG_THREADS
237    if (!_eina_threads_activated)
238      assert(pthread_equal(_eina_main_loop, pthread_self()));
239 #endif
240
241    ok = pthread_mutex_trylock(&(mutex->mutex));
242    if (ok == 0) ret = EINA_LOCK_SUCCEED;
243    else if (ok == EDEADLK)
244      {
245         printf("ERROR ERROR: DEADLOCK on trylock %p\n", mutex);
246         ret = EINA_LOCK_DEADLOCK; // magic
247      }
248 #ifdef EINA_HAVE_DEBUG_THREADS
249    if (ret == EINA_LOCK_SUCCEED)
250      {
251         mutex->locked = 1;
252         mutex->lock_thread_id = pthread_self();
253         mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
254
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);
259      }
260 #endif
261    return ret;
262 }
263
264 static inline Eina_Lock_Result
265 eina_lock_release(Eina_Lock *mutex)
266 {
267    Eina_Lock_Result ret;
268
269 #ifdef EINA_HAVE_ON_OFF_THREADS
270    if (!_eina_threads_activated)
271      {
272 #ifdef EINA_HAVE_DEBUG_THREADS
273         assert(pthread_equal(_eina_main_loop, pthread_self()));
274 #endif
275         return EINA_LOCK_SUCCEED;
276      }
277 #endif
278
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);
284
285    mutex->locked = 0;
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;
289 #endif
290    ret = (pthread_mutex_unlock(&(mutex->mutex)) == 0) ?
291       EINA_LOCK_SUCCEED : EINA_LOCK_FAIL;
292    return ret;
293 }
294
295 static inline Eina_Bool
296 eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
297 {
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));
303 #endif
304
305    cond->lock = mutex;
306    if (pthread_cond_init(&cond->condition, NULL) != 0)
307      {
308 #ifdef EINA_HAVE_DEBUG_THREADS
309         if (errno == EBUSY)
310           printf("eina_condition_new on already initialized Eina_Condition\n");
311 #endif
312         return EINA_FALSE;
313      }
314
315    return EINA_TRUE;
316 }
317
318 static inline void
319 eina_condition_free(Eina_Condition *cond)
320 {
321 #ifdef EINA_HAVE_DEBUG_THREADS
322    if (!_eina_threads_activated)
323      assert(pthread_equal(_eina_main_loop, pthread_self()));
324 #endif
325
326    pthread_cond_destroy(&(cond->condition));
327 #ifdef EINA_HAVE_DEBUG_THREADS
328    memset(cond, 0, sizeof (Eina_Condition));
329 #endif
330 }
331
332 static inline Eina_Bool
333 eina_condition_wait(Eina_Condition *cond)
334 {
335    Eina_Bool r;
336
337 #ifdef EINA_HAVE_DEBUG_THREADS
338    assert(_eina_threads_activated);
339    assert(cond->lock != NULL);
340
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);
345 #endif
346
347    r = pthread_cond_wait(&(cond->condition),
348                          &(cond->lock->mutex)) == 0 ? EINA_TRUE : EINA_FALSE;
349
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);
355 #endif
356
357    return r;
358 }
359
360 static inline Eina_Bool
361 eina_condition_timedwait(Eina_Condition *cond, double t)
362 {
363    struct timespec tv;
364    Eina_Bool r;
365
366 #ifdef EINA_HAVE_DEBUG_THREADS
367    assert(_eina_threads_activated);
368    assert(cond->lock != NULL);
369
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);
374 #endif
375
376    tv.tv_sec = t;
377    tv.tv_nsec = (t - (double) tv.tv_sec) * 1000000000;
378
379    r = pthread_cond_timedwait(&(cond->condition),
380                               &(cond->lock->mutex),
381                               &tv) == 0 ?
382      EINA_TRUE : EINA_FALSE;
383
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);
389 #endif
390
391    return r;
392 }
393
394 static inline Eina_Bool
395 eina_condition_broadcast(Eina_Condition *cond)
396 {
397 #ifdef EINA_HAVE_DEBUG_THREADS
398    assert(cond->lock != NULL);
399 #endif
400
401    return pthread_cond_broadcast(&(cond->condition)) == 0 ? EINA_TRUE : EINA_FALSE;
402 }
403
404 static inline Eina_Bool
405 eina_condition_signal(Eina_Condition *cond)
406 {
407 #ifdef EINA_HAVE_DEBUG_THREADS
408    assert(cond->lock != NULL);
409 #endif
410
411    return pthread_cond_signal(&(cond->condition)) == 0 ? EINA_TRUE : EINA_FALSE;
412 }
413
414 static inline Eina_Bool
415 eina_rwlock_new(Eina_RWLock *mutex)
416 {
417 #ifdef EINA_HAVE_DEBUG_THREADS
418    if (!_eina_threads_activated)
419      assert(pthread_equal(_eina_main_loop, pthread_self()));
420 #endif
421
422    if (pthread_rwlock_init(&(mutex->mutex), NULL) != 0)
423      return EINA_FALSE;
424    return EINA_TRUE;
425 }
426
427 static inline void
428 eina_rwlock_free(Eina_RWLock *mutex)
429 {
430 #ifdef EINA_HAVE_DEBUG_THREADS
431    if (!_eina_threads_activated)
432      assert(pthread_equal(_eina_main_loop, pthread_self()));
433 #endif
434
435    pthread_rwlock_destroy(&(mutex->mutex));
436 }
437
438 static inline Eina_Lock_Result
439 eina_rwlock_take_read(Eina_RWLock *mutex)
440 {
441 #ifdef EINA_HAVE_ON_OFF_THREADS
442    if (!_eina_threads_activated)
443      {
444 #ifdef EINA_HAVE_DEBUG_THREADS
445         assert(pthread_equal(_eina_main_loop, pthread_self()));
446 #endif
447         return EINA_LOCK_SUCCEED;
448      }
449 #endif
450
451    if (pthread_rwlock_rdlock(&(mutex->mutex)) != 0)
452      return EINA_LOCK_FAIL;
453    return EINA_LOCK_SUCCEED;
454 }
455
456 static inline Eina_Lock_Result
457 eina_rwlock_take_write(Eina_RWLock *mutex)
458 {
459 #ifdef EINA_HAVE_ON_OFF_THREADS
460    if (!_eina_threads_activated)
461      {
462 #ifdef EINA_HAVE_DEBUG_THREADS
463         assert(pthread_equal(_eina_main_loop, pthread_self()));
464 #endif
465         return EINA_LOCK_SUCCEED;
466      }
467 #endif
468
469    if (pthread_rwlock_wrlock(&(mutex->mutex)) != 0)
470      return EINA_LOCK_FAIL;
471    return EINA_LOCK_SUCCEED;
472 }
473
474 static inline Eina_Lock_Result
475 eina_rwlock_release(Eina_RWLock *mutex)
476 {
477 #ifdef EINA_HAVE_ON_OFF_THREADS
478    if (!_eina_threads_activated)
479      {
480 #ifdef EINA_HAVE_DEBUG_THREADS
481         assert(pthread_equal(_eina_main_loop, pthread_self()));
482 #endif
483         return EINA_LOCK_SUCCEED;
484      }
485 #endif
486
487    if (pthread_rwlock_unlock(&(mutex->mutex)) != 0)
488      return EINA_LOCK_FAIL;
489    return EINA_LOCK_SUCCEED;
490 }
491
492 static inline Eina_Bool 
493 eina_tls_new(Eina_TLS *key)
494 {
495    if (pthread_key_create(key, NULL) != 0)
496       return EINA_FALSE;
497    return EINA_TRUE;
498 }
499
500 static inline void 
501 eina_tls_free(Eina_TLS key)
502 {
503    pthread_key_delete(key);
504 }
505
506 static inline void * 
507 eina_tls_get(Eina_TLS key)
508 {
509    return pthread_getspecific(key);
510 }
511
512 static inline Eina_Bool 
513 eina_tls_set(Eina_TLS key, const void *data)
514 {
515    if (pthread_setspecific(key, data) != 0)
516       return EINA_FALSE;
517    return EINA_TRUE;
518 }
519
520 static inline Eina_Bool
521 eina_semaphore_new(Eina_Semaphore *sem, int count_init)
522 {
523    if (!sem || (count_init <= 0))
524      return EINA_FALSE;
525
526    return (sem_init(sem, count_init, 1) == 0) ? EINA_TRUE : EINA_FALSE;
527 }
528
529 static inline Eina_Bool
530 eina_semaphore_free(Eina_Semaphore *sem)
531 {
532    if (!sem)
533      return EINA_FALSE;
534
535    return (sem_destroy(sem) == 0) ? EINA_TRUE : EINA_FALSE;
536 }
537
538 static inline Eina_Bool
539 eina_semaphore_lock(Eina_Semaphore *sem)
540 {
541    if (!sem)
542      return EINA_FALSE;
543
544    return (sem_wait(sem) == 0) ? EINA_TRUE : EINA_FALSE;
545 }
546
547 static inline Eina_Bool
548 eina_semaphore_release(Eina_Semaphore *sem, int count_release EINA_UNUSED)
549 {
550    if (!sem)
551      return EINA_FALSE;
552
553    return (sem_post(sem) == 0) ? EINA_TRUE : EINA_FALSE;
554 }
555
556 #endif