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
36 #define EINA_LOCK_DEBUG_BT_NUM 64
37 typedef void (*Eina_Lock_Bt_Func) ();
39 #include "eina_inlist.h"
42 typedef struct _Eina_Lock Eina_Lock;
46 #ifdef EINA_HAVE_DEBUG_THREADS
49 pthread_mutex_t mutex;
50 #ifdef EINA_HAVE_DEBUG_THREADS
51 pthread_t lock_thread_id;
52 Eina_Lock_Bt_Func lock_bt[EINA_LOCK_DEBUG_BT_NUM];
58 EAPI extern Eina_Bool _eina_threads_activated;
60 #ifdef EINA_HAVE_DEBUG_THREADS
61 # include <sys/time.h>
63 EAPI extern int _eina_threads_debug;
64 EAPI extern pthread_t _eina_main_loop;
65 EAPI extern pthread_mutex_t _eina_tracking_lock;
66 EAPI extern Eina_Inlist *_eina_tracking;
69 static inline Eina_Bool
70 eina_lock_new(Eina_Lock *mutex)
72 pthread_mutexattr_t attr;
74 #ifdef EINA_HAVE_DEBUG_THREADS
75 assert(pthread_equal(_eina_main_loop, pthread_self()));
78 if (pthread_mutexattr_init(&attr) != 0)
80 /* NOTE: PTHREAD_MUTEX_RECURSIVE is not allowed at all, you will break on/off
81 feature for sure with that change. */
82 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0)
84 #ifdef EINA_HAVE_DEBUG_THREADS
85 memset(mutex, 0, sizeof(Eina_Lock));
87 if (pthread_mutex_init(&(mutex->mutex), &attr) != 0)
90 pthread_mutexattr_destroy(&attr);
96 eina_lock_free(Eina_Lock *mutex)
98 #ifdef EINA_HAVE_DEBUG_THREADS
99 assert(pthread_equal(_eina_main_loop, pthread_self()));
102 pthread_mutex_destroy(&(mutex->mutex));
103 #ifdef EINA_HAVE_DEBUG_THREADS
104 memset(mutex, 0, sizeof(Eina_Lock));
108 static inline Eina_Lock_Result
109 eina_lock_take(Eina_Lock *mutex)
111 Eina_Lock_Result ret = EINA_LOCK_FAIL;
114 #ifdef EINA_HAVE_ON_OFF_THREADS
115 if (!_eina_threads_activated)
117 #ifdef EINA_HAVE_DEBUG_THREADS
118 assert(pthread_equal(_eina_main_loop, pthread_self()));
120 return EINA_LOCK_SUCCEED;
124 #ifdef EINA_HAVE_DEBUG_THREADS
125 if (_eina_threads_debug)
127 struct timeval t0, t1;
130 gettimeofday(&t0, NULL);
131 ok = pthread_mutex_lock(&(mutex->mutex));
132 gettimeofday(&t1, NULL);
134 dt = (t1.tv_sec - t0.tv_sec) * 1000000;
135 if (t1.tv_usec > t0.tv_usec)
136 dt += (t1.tv_usec - t0.tv_usec);
138 dt -= t0.tv_usec - t1.tv_usec;
141 if (dt > _eina_threads_debug) abort();
146 ok = pthread_mutex_lock(&(mutex->mutex));
147 #ifdef EINA_HAVE_DEBUG_THREADS
151 if (ok == 0) ret = EINA_LOCK_SUCCEED;
152 else if (ok == EDEADLK)
154 printf("ERROR ERROR: DEADLOCK on lock %p\n", mutex);
155 ret = EINA_LOCK_DEADLOCK; // magic
158 #ifdef EINA_HAVE_DEBUG_THREADS
160 mutex->lock_thread_id = pthread_self();
161 mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
163 pthread_mutex_lock(&_eina_tracking_lock);
164 _eina_tracking = eina_inlist_append(_eina_tracking,
165 EINA_INLIST_GET(mutex));
166 pthread_mutex_unlock(&_eina_tracking_lock);
172 static inline Eina_Lock_Result
173 eina_lock_take_try(Eina_Lock *mutex)
175 Eina_Lock_Result ret = EINA_LOCK_FAIL;
178 #ifdef EINA_HAVE_ON_OFF_THREADS
179 if (!_eina_threads_activated)
181 #ifdef EINA_HAVE_DEBUG_THREADS
182 assert(pthread_equal(_eina_main_loop, pthread_self()));
184 return EINA_LOCK_SUCCEED;
188 #ifdef EINA_HAVE_DEBUG_THREADS
189 if (!_eina_threads_activated)
190 assert(pthread_equal(_eina_main_loop, pthread_self()));
193 ok = pthread_mutex_trylock(&(mutex->mutex));
194 if (ok == 0) ret = EINA_LOCK_SUCCEED;
195 else if (ok == EDEADLK)
197 printf("ERROR ERROR: DEADLOCK on trylock %p\n", mutex);
198 ret = EINA_LOCK_DEADLOCK; // magic
200 #ifdef EINA_HAVE_DEBUG_THREADS
201 if (ret == EINA_LOCK_SUCCEED)
204 mutex->lock_thread_id = pthread_self();
205 mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
207 pthread_mutex_lock(&_eina_tracking_lock);
208 _eina_tracking = eina_inlist_append(_eina_tracking,
209 EINA_INLIST_GET(mutex));
210 pthread_mutex_unlock(&_eina_tracking_lock);
216 static inline Eina_Lock_Result
217 eina_lock_release(Eina_Lock *mutex)
219 Eina_Lock_Result ret;
221 #ifdef EINA_HAVE_ON_OFF_THREADS
222 if (!_eina_threads_activated)
224 #ifdef EINA_HAVE_DEBUG_THREADS
225 assert(pthread_equal(_eina_main_loop, pthread_self()));
227 return EINA_LOCK_SUCCEED;
231 #ifdef EINA_HAVE_DEBUG_THREADS
232 pthread_mutex_lock(&_eina_tracking_lock);
233 _eina_tracking = eina_inlist_remove(_eina_tracking,
234 EINA_INLIST_GET(mutex));
235 pthread_mutex_unlock(&_eina_tracking_lock);
238 mutex->lock_thread_id = 0;
239 memset(mutex->lock_bt, 0, EINA_LOCK_DEBUG_BT_NUM * sizeof(Eina_Lock_Bt_Func));
240 mutex->lock_bt_num = 0;
242 ret = (pthread_mutex_unlock(&(mutex->mutex)) == 0) ?
243 EINA_LOCK_SUCCEED : EINA_LOCK_FAIL;
248 eina_lock_debug(const Eina_Lock *mutex)
250 #ifdef EINA_HAVE_DEBUG_THREADS
251 printf("lock %p, locked: %i, by %i\n",
252 mutex, (int)mutex->locked, (int)mutex->lock_thread_id);
253 backtrace_symbols_fd((void **)mutex->lock_bt, mutex->lock_bt_num, 1);