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 _XOPEN_SOURCE
23 # define EINA_XOPEN_SOURCE _XOPEN_SOURCE
24 # undef _XOPEN_SOURCE
25 #endif
26 #define _XOPEN_SOURCE 600
27
28 #ifdef EINA_HAVE_POSIX_SPINLOCK
29 # include <sched.h>
30 #endif
31
32 #include <errno.h>
33 #ifndef __USE_UNIX98
34 # define __USE_UNIX98
35 # include <pthread.h>
36 # undef __USE_UNIX98
37 #else
38 # include <pthread.h>
39 #endif
40
41 #ifdef EINA_HAVE_OSX_SEMAPHORE
42 # include <mach/mach.h>
43 #endif
44
45 #include <semaphore.h>
46
47 #include <sys/time.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51
52 #include <sys/types.h>
53 #include <unistd.h>
54
55 #ifdef EINA_HAVE_DEBUG_THREADS
56 #include <assert.h>
57 #include <execinfo.h>
58 #define EINA_LOCK_DEBUG_BT_NUM 64
59 typedef void (*Eina_Lock_Bt_Func) ();
60
61 #include "eina_inlist.h"
62 #endif
63
64 EAPI void _eina_lock_debug_abort(int err, const char *fn, const volatile void *ptr);
65 EAPI void _eina_lock_debug_deadlock(const char *fn, const volatile void *ptr);
66
67 #define EINA_LOCK_ABORT_DEBUG(err, fn, ptr) \
68 _eina_lock_debug_abort(err, #fn, ptr)
69 #define EINA_LOCK_DEADLOCK_DEBUG(fn, ptr) \
70 _eina_lock_debug_deadlock(#fn, ptr)
71
72 /* For cond_timedwait */
73 #include <time.h>
74 #include <sys/time.h>
75
76 #include <eina_error.h>
77
78 typedef struct _Eina_Lock Eina_Lock;
79 typedef struct _Eina_RWLock Eina_RWLock;
80 typedef struct _Eina_Condition Eina_Condition;
81 typedef pthread_key_t Eina_TLS;
82
83 #if defined(EINA_HAVE_POSIX_SPINLOCK)
84 typedef pthread_spinlock_t Eina_Spinlock;
85 #elif defined(EINA_HAVE_OSX_SPINLOCK)
86 typedef uintptr_t Eina_Spinlock;
87 #else
88 typedef Eina_Lock Eina_Spinlock;
89 #endif
90
91 #if defined(EINA_HAVE_OSX_SEMAPHORE)
92 typedef semaphore_t Eina_Semaphore;
93 #else
94 typedef sem_t Eina_Semaphore;
95 #endif
96
97 EAPI void eina_lock_debug(const Eina_Lock *mutex);
98
99 /** @privatesection @{ */
100 struct _Eina_Lock
101 {
102 #ifdef EINA_HAVE_DEBUG_THREADS
103 EINA_INLIST; /**< Keeps track of the threads waiting for the lock */
104 #endif
105 pthread_mutex_t mutex; /**< The mutex that handles the locking */
106 #ifdef EINA_HAVE_DEBUG_THREADS
107 pthread_t lock_thread_id; /**< The ID of the thread that currently has the lock */
108 Eina_Lock_Bt_Func lock_bt[EINA_LOCK_DEBUG_BT_NUM]; /**< The function that will produce a backtrace on the thread that has the lock */
109 int lock_bt_num; /**< Number of addresses in the backtrace */
110 Eina_Bool locked : 1; /**< Indicates locked or not locked */
111 Eina_Bool recursive : 1; /**< Indicates recursive lock */
112 #endif
113 };
114
115 struct _Eina_Condition
116 {
117 Eina_Lock *lock; /**< The lock for this condition */
118 pthread_cond_t condition; /**< The condition variable */
119 #if defined(__clockid_t_defined)
120 clockid_t clkid; /**< The attached clock for timedwait */
121 #endif
122 };
123
124 struct _Eina_RWLock
125 {
126 pthread_rwlock_t mutex; /**< The mutex that handles the locking */
127 #ifdef EINA_HAVE_DEBUG_THREADS
128 pthread_t lock_thread_wid; /**< The ID of the thread that currently has the lock */
129 #endif
130 };
131 /** @} privatesection */
132
133 EAPI extern Eina_Bool _eina_threads_activated;
134
135 #ifdef EINA_HAVE_DEBUG_THREADS
136 EAPI extern int _eina_threads_debug;
137 EAPI extern pthread_t _eina_main_loop;
138 EAPI extern pthread_mutex_t _eina_tracking_lock;
139 EAPI extern Eina_Inlist *_eina_tracking;
140 #endif
141
142
143 EAPI Eina_Bool _eina_lock_new(Eina_Lock *mutex, Eina_Bool recursive);
144 EAPI void _eina_lock_free(Eina_Lock *mutex);
145 EAPI Eina_Bool _eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex);
146 EAPI void _eina_condition_free(Eina_Condition *cond);
147 EAPI Eina_Bool _eina_rwlock_new(Eina_RWLock *mutex);
148 EAPI void _eina_rwlock_free(Eina_RWLock *mutex);
149 EAPI Eina_Bool _eina_spinlock_new(Eina_Spinlock *spinlock);
150 EAPI void _eina_spinlock_free(Eina_Spinlock *spinlock);
151 EAPI Eina_Bool _eina_semaphore_new(Eina_Semaphore *sem, int count_init);
152 EAPI Eina_Bool _eina_semaphore_free(Eina_Semaphore *sem);
153 #ifdef EINA_HAVE_OSX_SPINLOCK
154 EAPI Eina_Lock_Result _eina_spinlock_macos_take(Eina_Spinlock *spinlock);
155 EAPI Eina_Lock_Result _eina_spinlock_macos_take_try(Eina_Spinlock *spinlock);
156 EAPI Eina_Lock_Result _eina_spinlock_macos_release(Eina_Spinlock *spinlock);
157 #endif
158
159 static inline Eina_Bool
eina_lock_new(Eina_Lock * mutex)160 eina_lock_new(Eina_Lock *mutex)
161 {
162 Eina_Bool ret = _eina_lock_new(mutex, EINA_FALSE);
163 #ifdef EINA_HAVE_DEBUG_THREADS
164 mutex->recursive = EINA_FALSE;
165 mutex->lock_thread_id = 0;
166 mutex->lock_bt_num = 0;
167 mutex->locked = 0;
168 #endif
169 return ret;
170 }
171
172 static inline Eina_Bool
eina_lock_recursive_new(Eina_Lock * mutex)173 eina_lock_recursive_new(Eina_Lock *mutex)
174 {
175 Eina_Bool ret = _eina_lock_new(mutex, EINA_TRUE);
176 #ifdef EINA_HAVE_DEBUG_THREADS
177 mutex->recursive = EINA_TRUE;
178 mutex->lock_thread_id = 0;
179 mutex->lock_bt_num = 0;
180 mutex->locked = 0;
181 #endif
182 return ret;
183 }
184
185 static inline void
eina_lock_free(Eina_Lock * mutex)186 eina_lock_free(Eina_Lock *mutex)
187 {
188 #ifdef EINA_HAVE_DEBUG_THREADS
189 if (mutex->locked)
190 {
191 pthread_mutex_lock(&_eina_tracking_lock);
192 _eina_tracking = eina_inlist_remove(_eina_tracking,
193 EINA_INLIST_GET(mutex));
194 pthread_mutex_unlock(&_eina_tracking_lock);
195 }
196 #endif
197 _eina_lock_free(mutex);
198 }
199
200 static inline Eina_Lock_Result
eina_lock_take_try(Eina_Lock * mutex)201 eina_lock_take_try(Eina_Lock *mutex)
202 {
203 Eina_Lock_Result ret = EINA_LOCK_FAIL;
204 int ok;
205
206 #ifdef EINA_HAVE_ON_OFF_THREADS
207 if (!_eina_threads_activated)
208 {
209 return EINA_LOCK_SUCCEED;
210 }
211 #endif
212
213 ok = pthread_mutex_trylock(&(mutex->mutex));
214 if (ok == 0) ret = EINA_LOCK_SUCCEED;
215 else if (ok == EDEADLK)
216 {
217 eina_lock_debug(mutex);
218 ret = EINA_LOCK_DEADLOCK;
219 }
220 else if (ok != EBUSY) EINA_LOCK_ABORT_DEBUG(ok, trylock, mutex);
221 #ifdef EINA_HAVE_DEBUG_THREADS
222 if (ret == EINA_LOCK_SUCCEED)
223 {
224 /* recursive locks can't make use of any of this */
225 if (mutex->recursive) return ret;
226 mutex->locked = 1;
227 mutex->lock_thread_id = pthread_self();
228 /* backtrace() can somehow generate EINVAL even though this is not documented anywhere? */
229 int err = errno;
230 mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
231 errno = err;
232
233 pthread_mutex_lock(&_eina_tracking_lock);
234 _eina_tracking = eina_inlist_append(_eina_tracking,
235 EINA_INLIST_GET(mutex));
236 pthread_mutex_unlock(&_eina_tracking_lock);
237 }
238 #endif
239 return ret;
240 }
241
242 static inline Eina_Lock_Result
eina_lock_take(Eina_Lock * mutex)243 eina_lock_take(Eina_Lock *mutex)
244 {
245 Eina_Lock_Result ret = EINA_LOCK_FAIL;
246 int ok;
247
248 #ifdef EINA_HAVE_ON_OFF_THREADS
249 if (!_eina_threads_activated)
250 {
251 return EINA_LOCK_SUCCEED;
252 }
253 #endif
254
255 #ifdef EINA_HAVE_DEBUG_THREADS
256 if (eina_lock_take_try(mutex) == EINA_LOCK_SUCCEED) return EINA_LOCK_SUCCEED;
257 #endif
258
259 #ifdef EINA_HAVE_DEBUG_THREADS
260 if (_eina_threads_debug >= 100)
261 {
262 struct timeval t0, t1;
263 int dt;
264
265 gettimeofday(&t0, NULL);
266 ok = pthread_mutex_lock(&(mutex->mutex));
267 gettimeofday(&t1, NULL);
268
269 dt = (t1.tv_sec - t0.tv_sec) * 1000000;
270 if (t1.tv_usec > t0.tv_usec)
271 dt += (t1.tv_usec - t0.tv_usec);
272 else
273 dt -= t0.tv_usec - t1.tv_usec;
274
275 if (dt > _eina_threads_debug) abort();
276 }
277 else
278 {
279 #endif
280 ok = pthread_mutex_lock(&(mutex->mutex));
281 #ifdef EINA_HAVE_DEBUG_THREADS
282 }
283 #endif
284
285 if (ok == 0) ret = EINA_LOCK_SUCCEED;
286 else if (ok == EDEADLK)
287 {
288 eina_lock_debug(mutex);
289 ret = EINA_LOCK_DEADLOCK;
290 #ifdef EINA_HAVE_DEBUG_THREADS
291 if (_eina_threads_debug) abort();
292 #endif
293 }
294 else EINA_LOCK_ABORT_DEBUG(ok, lock, mutex);
295
296 #ifdef EINA_HAVE_DEBUG_THREADS
297 /* recursive locks can't make use of any of this */
298 if (mutex->recursive) return ret;
299 mutex->locked = 1;
300 mutex->lock_thread_id = pthread_self();
301 /* backtrace() can somehow generate EINVAL even though this is not documented anywhere? */
302 int err = errno;
303 mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
304 errno = err;
305
306 pthread_mutex_lock(&_eina_tracking_lock);
307 _eina_tracking = eina_inlist_append(_eina_tracking,
308 EINA_INLIST_GET(mutex));
309 pthread_mutex_unlock(&_eina_tracking_lock);
310 #endif
311
312 return ret;
313 }
314
315 static inline Eina_Lock_Result
eina_lock_release(Eina_Lock * mutex)316 eina_lock_release(Eina_Lock *mutex)
317 {
318 Eina_Lock_Result ret = EINA_LOCK_FAIL;
319 int ok;
320
321 #ifdef EINA_HAVE_ON_OFF_THREADS
322 if (!_eina_threads_activated)
323 {
324 return EINA_LOCK_SUCCEED;
325 }
326 #endif
327
328 #ifdef EINA_HAVE_DEBUG_THREADS
329 /* recursive locks can't make use of any of this */
330 if (!mutex->recursive)
331 {
332 mutex->locked = 0;
333 mutex->lock_thread_id = 0;
334 memset(mutex->lock_bt, 0, EINA_LOCK_DEBUG_BT_NUM * sizeof(Eina_Lock_Bt_Func));
335 mutex->lock_bt_num = 0;
336 pthread_mutex_lock(&_eina_tracking_lock);
337 _eina_tracking = eina_inlist_remove(_eina_tracking,
338 EINA_INLIST_GET(mutex));
339 pthread_mutex_unlock(&_eina_tracking_lock);
340 }
341 #endif
342 ok = pthread_mutex_unlock(&(mutex->mutex));
343 if (ok == 0) ret = EINA_LOCK_SUCCEED;
344 else if (ok == EPERM) ret = EINA_LOCK_FAIL;
345 else EINA_LOCK_ABORT_DEBUG(ok, unlock, mutex);
346 return ret;
347 }
348
349 static inline Eina_Bool
eina_condition_new(Eina_Condition * cond,Eina_Lock * mutex)350 eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
351 {
352 return _eina_condition_new(cond, mutex);
353 }
354
355 static inline void
eina_condition_free(Eina_Condition * cond)356 eina_condition_free(Eina_Condition *cond)
357 {
358 _eina_condition_free(cond);
359 }
360
361 static inline Eina_Bool
eina_condition_wait(Eina_Condition * cond)362 eina_condition_wait(Eina_Condition *cond)
363 {
364 Eina_Bool r = EINA_FALSE;
365 int ok;
366
367 #ifdef EINA_HAVE_DEBUG_THREADS
368 assert(_eina_threads_activated);
369 assert(cond->lock != NULL);
370
371 pthread_mutex_lock(&_eina_tracking_lock);
372 _eina_tracking = eina_inlist_remove(_eina_tracking,
373 EINA_INLIST_GET(cond->lock));
374 pthread_mutex_unlock(&_eina_tracking_lock);
375 #endif
376
377 ok = pthread_cond_wait(&(cond->condition), &(cond->lock->mutex));
378 if (ok == 0) r = EINA_TRUE;
379 else if (ok == EPERM) r = EINA_FALSE;
380 else EINA_LOCK_ABORT_DEBUG(ok, cond_wait, cond);
381
382 #ifdef EINA_HAVE_DEBUG_THREADS
383 pthread_mutex_lock(&_eina_tracking_lock);
384 _eina_tracking = eina_inlist_append(_eina_tracking,
385 EINA_INLIST_GET(cond->lock));
386 pthread_mutex_unlock(&_eina_tracking_lock);
387 #endif
388
389 return r;
390 }
391
392 static inline Eina_Bool
eina_condition_timedwait(Eina_Condition * cond,double t)393 eina_condition_timedwait(Eina_Condition *cond, double t)
394 {
395 struct timespec ts;
396 time_t sec;
397 long nsec;
398 int err;
399 Eina_Bool r = EINA_FALSE;
400
401 if (t >= 0.0)
402 {
403 #if defined(__clockid_t_defined)
404 if (cond->clkid)
405 {
406 if (clock_gettime(cond->clkid, &ts) != 0) return EINA_FALSE;
407 }
408 else
409 #endif
410 {
411 /* Obsolete for Linux.
412 * TODO: use pthread_cond_timedwait_relative_np for OSX. */
413 struct timeval tv;
414 if (gettimeofday(&tv, NULL) != 0) return EINA_FALSE;
415 ts.tv_sec = tv.tv_sec;
416 ts.tv_nsec = tv.tv_usec * 1000L;
417 }
418
419 #ifdef EINA_HAVE_DEBUG_THREADS
420 assert(_eina_threads_activated);
421 assert(cond->lock != NULL);
422
423 pthread_mutex_lock(&_eina_tracking_lock);
424 _eina_tracking = eina_inlist_remove(_eina_tracking,
425 EINA_INLIST_GET(cond->lock));
426 pthread_mutex_unlock(&_eina_tracking_lock);
427 #endif
428
429 sec = (time_t)t;
430 nsec = (t - (double)sec) * 1000000000L;
431 ts.tv_sec += sec;
432 ts.tv_nsec += nsec;
433 if (ts.tv_nsec > 1000000000L)
434 {
435 ts.tv_sec++;
436 ts.tv_nsec -= 1000000000L;
437 }
438
439 err = pthread_cond_timedwait(&(cond->condition),
440 &(cond->lock->mutex),
441 &ts);
442 if (err == 0) r = EINA_TRUE;
443 else if (err == EPERM) eina_error_set(EPERM);
444 else if (err == ETIMEDOUT) eina_error_set(ETIMEDOUT);
445 else EINA_LOCK_ABORT_DEBUG(err, cond_timedwait, cond);
446
447 #ifdef EINA_HAVE_DEBUG_THREADS
448 pthread_mutex_lock(&_eina_tracking_lock);
449 _eina_tracking = eina_inlist_append(_eina_tracking,
450 EINA_INLIST_GET(cond->lock));
451 pthread_mutex_unlock(&_eina_tracking_lock);
452 #endif
453 }
454 errno = EINVAL;
455 return r;
456 }
457
458 static inline Eina_Bool
eina_condition_broadcast(Eina_Condition * cond)459 eina_condition_broadcast(Eina_Condition *cond)
460 {
461 int ok;
462
463 #ifdef EINA_HAVE_DEBUG_THREADS
464 assert(cond->lock != NULL);
465 #endif
466
467 ok = pthread_cond_broadcast(&(cond->condition));
468 if (ok == 0) return EINA_TRUE;
469
470 EINA_LOCK_ABORT_DEBUG(ok, cond_broadcast, cond);
471 return EINA_FALSE;
472 }
473
474 static inline Eina_Bool
eina_condition_signal(Eina_Condition * cond)475 eina_condition_signal(Eina_Condition *cond)
476 {
477 int ok;
478
479 #ifdef EINA_HAVE_DEBUG_THREADS
480 assert(cond->lock != NULL);
481 #endif
482
483 ok = pthread_cond_signal(&(cond->condition));
484 if (ok == 0) return EINA_TRUE;
485
486 EINA_LOCK_ABORT_DEBUG(ok, cond_signal, cond);
487 return EINA_FALSE;
488 }
489
490 static inline Eina_Bool
eina_rwlock_new(Eina_RWLock * mutex)491 eina_rwlock_new(Eina_RWLock *mutex)
492 {
493 return _eina_rwlock_new(mutex);
494 }
495
496 static inline void
eina_rwlock_free(Eina_RWLock * mutex)497 eina_rwlock_free(Eina_RWLock *mutex)
498 {
499 _eina_rwlock_free(mutex);
500 }
501
502 static inline Eina_Lock_Result
eina_rwlock_take_read(Eina_RWLock * mutex)503 eina_rwlock_take_read(Eina_RWLock *mutex)
504 {
505 int ok;
506
507 #ifdef EINA_HAVE_ON_OFF_THREADS
508 if (!_eina_threads_activated)
509 {
510 return EINA_LOCK_SUCCEED;
511 }
512 #endif
513
514 ok = pthread_rwlock_rdlock(&(mutex->mutex));
515 if (ok == 0) return EINA_LOCK_SUCCEED;
516 else if (ok == EAGAIN || ok == ENOMEM) return EINA_LOCK_FAIL;
517 else if (ok == EDEADLK) EINA_LOCK_DEADLOCK_DEBUG(rwlock_rdlock, mutex);
518 else EINA_LOCK_ABORT_DEBUG(ok, rwlock_rdlock, mutex);
519 return EINA_LOCK_FAIL;
520 }
521
522 static inline Eina_Lock_Result
eina_rwlock_take_write(Eina_RWLock * mutex)523 eina_rwlock_take_write(Eina_RWLock *mutex)
524 {
525 int ok;
526
527 #ifdef EINA_HAVE_ON_OFF_THREADS
528 if (!_eina_threads_activated)
529 {
530 return EINA_LOCK_SUCCEED;
531 }
532 #endif
533
534 ok = pthread_rwlock_wrlock(&(mutex->mutex));
535 if (ok == 0) return EINA_LOCK_SUCCEED;
536 else if (ok == ENOMEM) return EINA_LOCK_FAIL;
537 else if (ok == EDEADLK) EINA_LOCK_DEADLOCK_DEBUG(rwlock_wrlock, mutex);
538 else EINA_LOCK_ABORT_DEBUG(ok, rwlock_wrlock, mutex);
539 return EINA_LOCK_FAIL;
540 }
541
542 static inline Eina_Lock_Result
eina_rwlock_release(Eina_RWLock * mutex)543 eina_rwlock_release(Eina_RWLock *mutex)
544 {
545 int ok;
546
547 #ifdef EINA_HAVE_ON_OFF_THREADS
548 if (!_eina_threads_activated)
549 {
550 return EINA_LOCK_SUCCEED;
551 }
552 #endif
553
554 ok = pthread_rwlock_unlock(&(mutex->mutex));
555 if (ok == 0) return EINA_LOCK_SUCCEED;
556 else if (ok == EPERM) return EINA_LOCK_FAIL;
557 else EINA_LOCK_ABORT_DEBUG(ok, rwlock_unlock, mutex);
558 return EINA_LOCK_FAIL;
559 }
560
561 static inline Eina_Bool
eina_tls_cb_new(Eina_TLS * key,Eina_TLS_Delete_Cb delete_cb)562 eina_tls_cb_new(Eina_TLS *key, Eina_TLS_Delete_Cb delete_cb)
563 {
564 if (pthread_key_create(key, delete_cb) == 0) return EINA_TRUE;
565 return EINA_FALSE;
566 }
567
568 static inline Eina_Bool
eina_tls_new(Eina_TLS * key)569 eina_tls_new(Eina_TLS *key)
570 {
571 return eina_tls_cb_new(key, NULL);
572 }
573
574 static inline void
eina_tls_free(Eina_TLS key)575 eina_tls_free(Eina_TLS key)
576 {
577 pthread_key_delete(key);
578 }
579
580 static inline void *
eina_tls_get(Eina_TLS key)581 eina_tls_get(Eina_TLS key)
582 {
583 return pthread_getspecific(key);
584 }
585
586 static inline Eina_Bool
eina_tls_set(Eina_TLS key,const void * data)587 eina_tls_set(Eina_TLS key, const void *data)
588 {
589 if (pthread_setspecific(key, data) == 0) return EINA_TRUE;
590 return EINA_FALSE;
591 }
592
593
594 #ifdef EINA_HAVE_PTHREAD_BARRIER
595 typedef struct _Eina_Barrier Eina_Barrier;
596
597 struct _Eina_Barrier
598 {
599 pthread_barrier_t barrier;
600 };
601
602 static inline Eina_Bool
eina_barrier_wait(Eina_Barrier * barrier)603 eina_barrier_wait(Eina_Barrier *barrier)
604 {
605 int ok = pthread_barrier_wait(&(barrier->barrier));
606 if (ok == 0) return EINA_TRUE;
607 else if (ok == PTHREAD_BARRIER_SERIAL_THREAD) return EINA_TRUE;
608 else EINA_LOCK_ABORT_DEBUG(ok, barrier_wait, barrier);
609 return EINA_TRUE;
610 }
611
612 #else
613 #include "eina_inline_lock_barrier.x"
614 #endif
615
616 EAPI Eina_Bool _eina_barrier_new(Eina_Barrier *barrier, int needed);
617 EAPI void _eina_barrier_free(Eina_Barrier *barrier);
618
619 static inline Eina_Bool
eina_barrier_new(Eina_Barrier * barrier,int needed)620 eina_barrier_new(Eina_Barrier *barrier, int needed)
621 {
622 return _eina_barrier_new(barrier, needed);
623 }
624
625 static inline void
eina_barrier_free(Eina_Barrier * barrier)626 eina_barrier_free(Eina_Barrier *barrier)
627 {
628 _eina_barrier_free(barrier);
629 }
630
631
632 static inline Eina_Bool
eina_spinlock_new(Eina_Spinlock * spinlock)633 eina_spinlock_new(Eina_Spinlock *spinlock)
634 {
635 return _eina_spinlock_new(spinlock);
636 }
637
638 static inline void
eina_spinlock_free(Eina_Spinlock * spinlock)639 eina_spinlock_free(Eina_Spinlock *spinlock)
640 {
641 _eina_spinlock_free(spinlock);
642 }
643
644 static inline Eina_Lock_Result
eina_spinlock_take_try(Eina_Spinlock * spinlock)645 eina_spinlock_take_try(Eina_Spinlock *spinlock)
646 {
647 #if defined(EINA_HAVE_POSIX_SPINLOCK)
648 int t = pthread_spin_trylock(spinlock);
649 if (t == 0) return EINA_LOCK_SUCCEED;
650 else if (t == EBUSY) return EINA_LOCK_FAIL;
651 else EINA_LOCK_ABORT_DEBUG(t, spin_trylock, spinlock);
652 return EINA_LOCK_FAIL;
653 #elif defined(EINA_HAVE_OSX_SPINLOCK)
654 return _eina_spinlock_macos_take_try(spinlock);
655 #else
656 return eina_lock_take_try(spinlock);
657 #endif
658 }
659
660 static inline Eina_Lock_Result
eina_spinlock_take(Eina_Spinlock * spinlock)661 eina_spinlock_take(Eina_Spinlock *spinlock)
662 {
663 #if defined(EINA_HAVE_POSIX_SPINLOCK)
664 int t;
665
666 #ifdef EINA_HAVE_DEBUG_THREADS
667 if (eina_spinlock_take_try(spinlock) == EINA_LOCK_SUCCEED) return EINA_LOCK_SUCCEED;
668 #endif
669
670 for (;;)
671 {
672 t = pthread_spin_lock(spinlock);
673 if (t == 0) break;
674 else EINA_LOCK_ABORT_DEBUG(t, spin_lock, spinlock);
675 }
676
677 return EINA_LOCK_SUCCEED;
678 #elif defined(EINA_HAVE_OSX_SPINLOCK)
679 return _eina_spinlock_macos_take(spinlock);
680 #else
681 return eina_lock_take(spinlock);
682 #endif
683 }
684
685 static inline Eina_Lock_Result
eina_spinlock_release(Eina_Spinlock * spinlock)686 eina_spinlock_release(Eina_Spinlock *spinlock)
687 {
688 #if defined(EINA_HAVE_POSIX_SPINLOCK)
689 int ok = pthread_spin_unlock(spinlock);
690 if (ok == 0) return EINA_LOCK_SUCCEED;
691 else if (ok == EPERM) return EINA_LOCK_FAIL;
692 else EINA_LOCK_ABORT_DEBUG(ok, spin_unlock, spinlock);
693 return EINA_LOCK_FAIL;
694 #elif defined(EINA_HAVE_OSX_SPINLOCK)
695 return _eina_spinlock_macos_release(spinlock);
696 #else
697 return eina_lock_release(spinlock);
698 #endif
699 }
700
701 static inline Eina_Bool
eina_semaphore_new(Eina_Semaphore * sem,int count_init)702 eina_semaphore_new(Eina_Semaphore *sem, int count_init)
703 {
704 return _eina_semaphore_new(sem, count_init);
705 }
706
707 static inline Eina_Bool
eina_semaphore_free(Eina_Semaphore * sem)708 eina_semaphore_free(Eina_Semaphore *sem)
709 {
710 return _eina_semaphore_free(sem);
711 }
712
713 static inline Eina_Bool
eina_semaphore_lock(Eina_Semaphore * sem)714 eina_semaphore_lock(Eina_Semaphore *sem)
715 {
716 if (sem)
717 {
718 for (;;)
719 {
720 if (
721 #if defined(EINA_HAVE_OSX_SEMAPHORE)
722 semaphore_wait(*sem)
723 #else
724 sem_wait(sem)
725 #endif
726 == 0)
727 return EINA_TRUE;
728 else if (errno != EINTR) goto err;
729 }
730 }
731 return EINA_FALSE;
732 err:
733 if (errno == EDEADLK) EINA_LOCK_DEADLOCK_DEBUG(sem_wait, sem);
734 return EINA_FALSE;
735 }
736
737 static inline Eina_Bool
eina_semaphore_release(Eina_Semaphore * sem,int count_release EINA_UNUSED)738 eina_semaphore_release(Eina_Semaphore *sem, int count_release EINA_UNUSED)
739 {
740 if (sem)
741 #if defined(EINA_HAVE_OSX_SEMAPHORE)
742 return (semaphore_signal(*sem) == KERN_SUCCESS) ? EINA_TRUE : EINA_FALSE;
743 #else
744 return (sem_post(sem) == 0) ? EINA_TRUE : EINA_FALSE;
745 #endif
746 return EINA_FALSE;
747 }
748
749 #undef _XOPEN_SOURCE
750 // This is necessary to let third party still define this macro
751 #ifdef EINA_XOPEN_SOURCE
752 # define _XOPEN_SOURCE EINA_XOPEN_SOURCE
753 #endif
754
755 #endif
756