aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/eina/src/include/eina_inline_lock_posix.x
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/eina/src/include/eina_inline_lock_posix.x')
-rw-r--r--libraries/eina/src/include/eina_inline_lock_posix.x509
1 files changed, 509 insertions, 0 deletions
diff --git a/libraries/eina/src/include/eina_inline_lock_posix.x b/libraries/eina/src/include/eina_inline_lock_posix.x
new file mode 100644
index 0000000..77f5b8b
--- /dev/null
+++ b/libraries/eina/src/include/eina_inline_lock_posix.x
@@ -0,0 +1,509 @@
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#include <errno.h>
23#ifndef __USE_UNIX98
24# define __USE_UNIX98
25# include <pthread.h>
26# undef __USE_UNIX98
27#else
28# include <pthread.h>
29#endif
30
31#include <sys/time.h>
32
33#ifdef EINA_HAVE_DEBUG_THREADS
34#include <stdlib.h>
35#include <string.h>
36#include <assert.h>
37#include <execinfo.h>
38#define EINA_LOCK_DEBUG_BT_NUM 64
39typedef void (*Eina_Lock_Bt_Func) ();
40
41#include "eina_inlist.h"
42#endif
43
44typedef struct _Eina_Lock Eina_Lock;
45typedef struct _Eina_RWLock Eina_RWLock;
46typedef struct _Eina_Condition Eina_Condition;
47typedef pthread_key_t Eina_TLS;
48
49struct _Eina_Lock
50{
51#ifdef EINA_HAVE_DEBUG_THREADS
52 EINA_INLIST;
53#endif
54 pthread_mutex_t mutex;
55#ifdef EINA_HAVE_DEBUG_THREADS
56 pthread_t lock_thread_id;
57 Eina_Lock_Bt_Func lock_bt[EINA_LOCK_DEBUG_BT_NUM];
58 int lock_bt_num;
59 Eina_Bool locked : 1;
60#endif
61};
62
63struct _Eina_Condition
64{
65 Eina_Lock *lock;
66 pthread_cond_t condition;
67};
68
69struct _Eina_RWLock
70{
71 pthread_rwlock_t mutex;
72#ifdef EINA_HAVE_DEBUG_THREADS
73 pthread_t lock_thread_wid;
74#endif
75};
76
77EAPI extern Eina_Bool _eina_threads_activated;
78
79#ifdef EINA_HAVE_DEBUG_THREADS
80# include <sys/time.h>
81
82EAPI extern int _eina_threads_debug;
83EAPI extern pthread_t _eina_main_loop;
84EAPI extern pthread_mutex_t _eina_tracking_lock;
85EAPI extern Eina_Inlist *_eina_tracking;
86#endif
87
88static inline void
89eina_lock_debug(const Eina_Lock *mutex)
90{
91#ifdef EINA_HAVE_DEBUG_THREADS
92 printf("lock %p, locked: %i, by %i\n",
93 mutex, (int)mutex->locked, (int)mutex->lock_thread_id);
94 backtrace_symbols_fd((void **)mutex->lock_bt, mutex->lock_bt_num, 1);
95#else
96 (void) mutex;
97#endif
98}
99
100static inline Eina_Bool
101eina_lock_new(Eina_Lock *mutex)
102{
103 pthread_mutexattr_t attr;
104
105#ifdef EINA_HAVE_DEBUG_THREADS
106 if (!_eina_threads_activated)
107 assert(pthread_equal(_eina_main_loop, pthread_self()));
108#endif
109
110 if (pthread_mutexattr_init(&attr) != 0)
111 return EINA_FALSE;
112 /* NOTE: PTHREAD_MUTEX_RECURSIVE is not allowed at all, you will break on/off
113 feature for sure with that change. */
114#ifdef EINA_HAVE_DEBUG_THREADS
115 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0)
116 return EINA_FALSE;
117 memset(mutex, 0, sizeof(Eina_Lock));
118#endif
119 if (pthread_mutex_init(&(mutex->mutex), &attr) != 0)
120 return EINA_FALSE;
121
122 pthread_mutexattr_destroy(&attr);
123
124 return EINA_TRUE;
125}
126
127static inline void
128eina_lock_free(Eina_Lock *mutex)
129{
130#ifdef EINA_HAVE_DEBUG_THREADS
131 if (!_eina_threads_activated)
132 assert(pthread_equal(_eina_main_loop, pthread_self()));
133#endif
134
135 pthread_mutex_destroy(&(mutex->mutex));
136#ifdef EINA_HAVE_DEBUG_THREADS
137 memset(mutex, 0, sizeof(Eina_Lock));
138#endif
139}
140
141static inline Eina_Lock_Result
142eina_lock_take(Eina_Lock *mutex)
143{
144 Eina_Lock_Result ret = EINA_LOCK_FAIL;
145 int ok;
146
147#ifdef EINA_HAVE_ON_OFF_THREADS
148 if (!_eina_threads_activated)
149 {
150#ifdef EINA_HAVE_DEBUG_THREADS
151 assert(pthread_equal(_eina_main_loop, pthread_self()));
152#endif
153 return EINA_LOCK_SUCCEED;
154 }
155#endif
156
157#ifdef EINA_HAVE_DEBUG_THREADS
158 if (_eina_threads_debug)
159 {
160 struct timeval t0, t1;
161 int dt;
162
163 gettimeofday(&t0, NULL);
164 ok = pthread_mutex_lock(&(mutex->mutex));
165 gettimeofday(&t1, NULL);
166
167 dt = (t1.tv_sec - t0.tv_sec) * 1000000;
168 if (t1.tv_usec > t0.tv_usec)
169 dt += (t1.tv_usec - t0.tv_usec);
170 else
171 dt -= t0.tv_usec - t1.tv_usec;
172 dt /= 1000;
173
174 if (dt > _eina_threads_debug) abort();
175 }
176 else
177 {
178#endif
179 ok = pthread_mutex_lock(&(mutex->mutex));
180#ifdef EINA_HAVE_DEBUG_THREADS
181 }
182#endif
183
184 if (ok == 0) ret = EINA_LOCK_SUCCEED;
185 else if (ok == EDEADLK)
186 {
187 printf("ERROR ERROR: DEADLOCK on lock %p\n", mutex);
188 eina_lock_debug(mutex);
189 ret = EINA_LOCK_DEADLOCK; // magic
190#ifdef EINA_HAVE_DEBUG_THREADS
191 if (_eina_threads_debug) abort();
192#endif
193 }
194
195#ifdef EINA_HAVE_DEBUG_THREADS
196 mutex->locked = 1;
197 mutex->lock_thread_id = pthread_self();
198 mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
199
200 pthread_mutex_lock(&_eina_tracking_lock);
201 _eina_tracking = eina_inlist_append(_eina_tracking,
202 EINA_INLIST_GET(mutex));
203 pthread_mutex_unlock(&_eina_tracking_lock);
204#endif
205
206 return ret;
207}
208
209static inline Eina_Lock_Result
210eina_lock_take_try(Eina_Lock *mutex)
211{
212 Eina_Lock_Result ret = EINA_LOCK_FAIL;
213 int ok;
214
215#ifdef EINA_HAVE_ON_OFF_THREADS
216 if (!_eina_threads_activated)
217 {
218#ifdef EINA_HAVE_DEBUG_THREADS
219 assert(pthread_equal(_eina_main_loop, pthread_self()));
220#endif
221 return EINA_LOCK_SUCCEED;
222 }
223#endif
224
225#ifdef EINA_HAVE_DEBUG_THREADS
226 if (!_eina_threads_activated)
227 assert(pthread_equal(_eina_main_loop, pthread_self()));
228#endif
229
230 ok = pthread_mutex_trylock(&(mutex->mutex));
231 if (ok == 0) ret = EINA_LOCK_SUCCEED;
232 else if (ok == EDEADLK)
233 {
234 printf("ERROR ERROR: DEADLOCK on trylock %p\n", mutex);
235 ret = EINA_LOCK_DEADLOCK; // magic
236 }
237#ifdef EINA_HAVE_DEBUG_THREADS
238 if (ret == EINA_LOCK_SUCCEED)
239 {
240 mutex->locked = 1;
241 mutex->lock_thread_id = pthread_self();
242 mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
243
244 pthread_mutex_lock(&_eina_tracking_lock);
245 _eina_tracking = eina_inlist_append(_eina_tracking,
246 EINA_INLIST_GET(mutex));
247 pthread_mutex_unlock(&_eina_tracking_lock);
248 }
249#endif
250 return ret;
251}
252
253static inline Eina_Lock_Result
254eina_lock_release(Eina_Lock *mutex)
255{
256 Eina_Lock_Result ret;
257
258#ifdef EINA_HAVE_ON_OFF_THREADS
259 if (!_eina_threads_activated)
260 {
261#ifdef EINA_HAVE_DEBUG_THREADS
262 assert(pthread_equal(_eina_main_loop, pthread_self()));
263#endif
264 return EINA_LOCK_SUCCEED;
265 }
266#endif
267
268#ifdef EINA_HAVE_DEBUG_THREADS
269 pthread_mutex_lock(&_eina_tracking_lock);
270 _eina_tracking = eina_inlist_remove(_eina_tracking,
271 EINA_INLIST_GET(mutex));
272 pthread_mutex_unlock(&_eina_tracking_lock);
273
274 mutex->locked = 0;
275 mutex->lock_thread_id = 0;
276 memset(mutex->lock_bt, 0, EINA_LOCK_DEBUG_BT_NUM * sizeof(Eina_Lock_Bt_Func));
277 mutex->lock_bt_num = 0;
278#endif
279 ret = (pthread_mutex_unlock(&(mutex->mutex)) == 0) ?
280 EINA_LOCK_SUCCEED : EINA_LOCK_FAIL;
281 return ret;
282}
283
284static inline Eina_Bool
285eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
286{
287#ifdef EINA_HAVE_DEBUG_THREADS
288 assert(mutex != NULL);
289 if (!_eina_threads_activated)
290 assert(pthread_equal(_eina_main_loop, pthread_self()));
291 memset(cond, 0, sizeof (Eina_Condition));
292#endif
293
294 cond->lock = mutex;
295 if (pthread_cond_init(&cond->condition, NULL) != 0)
296 {
297#ifdef EINA_HAVE_DEBUG_THREADS
298 if (errno == EBUSY)
299 printf("eina_condition_new on already initialized Eina_Condition\n");
300#endif
301 return EINA_FALSE;
302 }
303
304 return EINA_TRUE;
305}
306
307static inline void
308eina_condition_free(Eina_Condition *cond)
309{
310#ifdef EINA_HAVE_DEBUG_THREADS
311 if (!_eina_threads_activated)
312 assert(pthread_equal(_eina_main_loop, pthread_self()));
313#endif
314
315 pthread_cond_destroy(&(cond->condition));
316#ifdef EINA_HAVE_DEBUG_THREADS
317 memset(cond, 0, sizeof (Eina_Condition));
318#endif
319}
320
321static inline Eina_Bool
322eina_condition_wait(Eina_Condition *cond)
323{
324 Eina_Bool r;
325
326#ifdef EINA_HAVE_DEBUG_THREADS
327 assert(_eina_threads_activated);
328 assert(cond->lock != NULL);
329
330 pthread_mutex_lock(&_eina_tracking_lock);
331 _eina_tracking = eina_inlist_remove(_eina_tracking,
332 EINA_INLIST_GET(cond->lock));
333 pthread_mutex_unlock(&_eina_tracking_lock);
334#endif
335
336 r = pthread_cond_wait(&(cond->condition),
337 &(cond->lock->mutex)) == 0 ? EINA_TRUE : EINA_FALSE;
338
339#ifdef EINA_HAVE_DEBUG_THREADS
340 pthread_mutex_lock(&_eina_tracking_lock);
341 _eina_tracking = eina_inlist_append(_eina_tracking,
342 EINA_INLIST_GET(cond->lock));
343 pthread_mutex_unlock(&_eina_tracking_lock);
344#endif
345
346 return r;
347}
348
349static inline Eina_Bool
350eina_condition_timedwait(Eina_Condition *cond, double t)
351{
352 struct timespec tv;
353 Eina_Bool r;
354
355#ifdef EINA_HAVE_DEBUG_THREADS
356 assert(_eina_threads_activated);
357 assert(cond->lock != NULL);
358
359 pthread_mutex_lock(&_eina_tracking_lock);
360 _eina_tracking = eina_inlist_remove(_eina_tracking,
361 EINA_INLIST_GET(cond->lock));
362 pthread_mutex_unlock(&_eina_tracking_lock);
363#endif
364
365 tv.tv_sec = t;
366 tv.tv_nsec = (t - (double) tv.tv_sec) * 1000000000;
367
368 r = pthread_cond_timedwait(&(cond->condition),
369 &(cond->lock->mutex),
370 &tv) == 0 ?
371 EINA_TRUE : EINA_FALSE;
372
373#ifdef EINA_HAVE_DEBUG_THREADS
374 pthread_mutex_lock(&_eina_tracking_lock);
375 _eina_tracking = eina_inlist_append(_eina_tracking,
376 EINA_INLIST_GET(cond->lock));
377 pthread_mutex_unlock(&_eina_tracking_lock);
378#endif
379
380 return r;
381}
382
383static inline Eina_Bool
384eina_condition_broadcast(Eina_Condition *cond)
385{
386#ifdef EINA_HAVE_DEBUG_THREADS
387 assert(cond->lock != NULL);
388#endif
389
390 return pthread_cond_broadcast(&(cond->condition)) == 0 ? EINA_TRUE : EINA_FALSE;
391}
392
393static inline Eina_Bool
394eina_condition_signal(Eina_Condition *cond)
395{
396#ifdef EINA_HAVE_DEBUG_THREADS
397 assert(cond->lock != NULL);
398#endif
399
400 return pthread_cond_signal(&(cond->condition)) == 0 ? EINA_TRUE : EINA_FALSE;
401}
402
403static inline Eina_Bool
404eina_rwlock_new(Eina_RWLock *mutex)
405{
406#ifdef EINA_HAVE_DEBUG_THREADS
407 if (!_eina_threads_activated)
408 assert(pthread_equal(_eina_main_loop, pthread_self()));
409#endif
410
411 if (pthread_rwlock_init(&(mutex->mutex), NULL) != 0)
412 return EINA_FALSE;
413 return EINA_TRUE;
414}
415
416static inline void
417eina_rwlock_free(Eina_RWLock *mutex)
418{
419#ifdef EINA_HAVE_DEBUG_THREADS
420 if (!_eina_threads_activated)
421 assert(pthread_equal(_eina_main_loop, pthread_self()));
422#endif
423
424 pthread_rwlock_destroy(&(mutex->mutex));
425}
426
427static inline Eina_Lock_Result
428eina_rwlock_take_read(Eina_RWLock *mutex)
429{
430#ifdef EINA_HAVE_ON_OFF_THREADS
431 if (!_eina_threads_activated)
432 {
433#ifdef EINA_HAVE_DEBUG_THREADS
434 assert(pthread_equal(_eina_main_loop, pthread_self()));
435#endif
436 return EINA_LOCK_SUCCEED;
437 }
438#endif
439
440 if (pthread_rwlock_rdlock(&(mutex->mutex)) != 0)
441 return EINA_LOCK_FAIL;
442 return EINA_LOCK_SUCCEED;
443}
444
445static inline Eina_Lock_Result
446eina_rwlock_take_write(Eina_RWLock *mutex)
447{
448#ifdef EINA_HAVE_ON_OFF_THREADS
449 if (!_eina_threads_activated)
450 {
451#ifdef EINA_HAVE_DEBUG_THREADS
452 assert(pthread_equal(_eina_main_loop, pthread_self()));
453#endif
454 return EINA_LOCK_SUCCEED;
455 }
456#endif
457
458 if (pthread_rwlock_wrlock(&(mutex->mutex)) != 0)
459 return EINA_LOCK_FAIL;
460 return EINA_LOCK_SUCCEED;
461}
462
463static inline Eina_Lock_Result
464eina_rwlock_release(Eina_RWLock *mutex)
465{
466#ifdef EINA_HAVE_ON_OFF_THREADS
467 if (!_eina_threads_activated)
468 {
469#ifdef EINA_HAVE_DEBUG_THREADS
470 assert(pthread_equal(_eina_main_loop, pthread_self()));
471#endif
472 return EINA_LOCK_SUCCEED;
473 }
474#endif
475
476 if (pthread_rwlock_unlock(&(mutex->mutex)) != 0)
477 return EINA_LOCK_FAIL;
478 return EINA_LOCK_SUCCEED;
479}
480
481static inline Eina_Bool
482eina_tls_new(Eina_TLS *key)
483{
484 if (pthread_key_create(key, NULL) != 0)
485 return EINA_FALSE;
486 return EINA_TRUE;
487}
488
489static inline void
490eina_tls_free(Eina_TLS key)
491{
492 pthread_key_delete(key);
493}
494
495static inline void *
496eina_tls_get(Eina_TLS key)
497{
498 return pthread_getspecific(key);
499}
500
501static inline Eina_Bool
502eina_tls_set(Eina_TLS key, const void *data)
503{
504 if (pthread_setspecific(key, data) != 0)
505 return EINA_FALSE;
506 return EINA_TRUE;
507}
508
509#endif