397e1f2e83822688a9ec1e60ef0b05ffe0d54cc9
[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 #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 #ifdef EINA_HAVE_DEBUG_THREADS
32 #include <execinfo.h>
33 #define EINA_LOCK_DEBUG_BT_NUM 64
34 typedef void (*Eina_Lock_Bt_Func) ();
35 #endif
36
37 typedef struct _Eina_Lock Eina_Lock;
38
39 struct _Eina_Lock
40 {
41    pthread_mutex_t  mutex;
42 #ifdef EINA_HAVE_DEBUG_THREADS
43    pthread_t         lock_thread_id;
44    Eina_Lock_Bt_Func lock_bt[EINA_LOCK_DEBUG_BT_NUM];
45    int               lock_bt_num;
46    Eina_Bool         locked : 1;
47 #endif
48 };
49
50 EAPI extern Eina_Bool _eina_threads_activated;
51
52 #ifdef EINA_HAVE_DEBUG_THREADS
53 # include <sys/time.h>
54
55 EAPI extern int _eina_threads_debug;
56 EAPI extern pthread_t _eina_main_loop;
57 #endif
58
59 static inline Eina_Bool
60 eina_lock_new(Eina_Lock *mutex)
61 {
62    pthread_mutexattr_t attr;
63
64 #ifdef EINA_HAVE_DEBUG_THREADS
65    assert(pthread_equal(_eina_main_loop, pthread_self()));
66 #endif
67
68    if (pthread_mutexattr_init(&attr) != 0)
69      return EINA_FALSE;
70 /* use errorcheck locks. detect deadlocks.
71 #ifdef PTHREAD_MUTEX_RECURSIVE
72    if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
73      return EINA_FALSE;
74 #endif
75  */
76    if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0)
77      return EINA_FALSE;
78 #ifdef EINA_HAVE_DEBUG_THREADS
79    memset(mutex, 0, sizeof(Eina_Lock));
80 #endif
81    if (pthread_mutex_init(&(mutex->mutex), &attr) != 0)
82      return EINA_FALSE;
83
84    pthread_mutexattr_destroy(&attr);
85
86    return EINA_TRUE;
87 }
88
89 static inline void
90 eina_lock_free(Eina_Lock *mutex)
91 {
92 #ifdef EINA_HAVE_DEBUG_THREADS
93    assert(pthread_equal(_eina_main_loop, pthread_self()));
94 #endif
95
96    pthread_mutex_destroy(&(mutex->mutex));
97 #ifdef EINA_HAVE_DEBUG_THREADS
98    memset(mutex, 0, sizeof(Eina_Lock));
99 #endif
100 }
101
102 static inline Eina_Lock_Result
103 eina_lock_take(Eina_Lock *mutex)
104 {
105    Eina_Lock_Result ret = EINA_LOCK_FAIL;
106    int ok;
107
108 #ifdef EINA_HAVE_ON_OFF_THREADS
109    if (!_eina_threads_activated)
110      {
111 #ifdef EINA_HAVE_DEBUG_THREADS
112         assert(pthread_equal(_eina_main_loop, pthread_self()));
113 #endif
114         return EINA_LOCK_FAIL;
115      }
116 #endif
117
118 #ifdef EINA_HAVE_DEBUG_THREADS
119    if (_eina_threads_debug)
120      {
121         struct timeval t0, t1;
122         int dt;
123
124         gettimeofday(&t0, NULL);
125         pthread_mutex_lock(&(x));
126         gettimeofday(&t1, NULL);
127
128         dt = (t1.tv_sec - t0.tv_sec) * 1000000;
129         if (t1.tv_usec > t0.tv_usec)
130            dt += (t1.tv_usec - t0.tv_usec);
131         else
132            dt -= t0.tv_usec - t1.tv_usec;
133         dt /= 1000;
134
135         if (dt > _eina_threads_debug) abort();
136      }
137 #endif
138    ok = pthread_mutex_lock(&(mutex->mutex));
139    if (ok == 0) ret = EINA_LOCK_SUCCEED;
140    else if (ok == EDEADLK)
141      {
142         printf("ERROR ERROR: DEADLOCK on lock %p\n", mutex);
143         ret = EINA_LOCK_DEADLOCK; // magic
144      }
145 #ifdef EINA_HAVE_DEBUG_THREADS
146    mutex->locked = 1;
147    mutex->lock_thread_id = pthread_self();
148    mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
149 #endif
150    return ret;
151 }
152
153 static inline Eina_Lock_Result
154 eina_lock_take_try(Eina_Lock *mutex)
155 {
156    Eina_Lock_Result ret = EINA_LOCK_FAIL;
157    int ok;
158
159 #ifdef EINA_HAVE_ON_OFF_THREADS
160    if (!_eina_threads_activated)
161      {
162 #ifdef EINA_HAVE_DEBUG_THREADS
163         assert(pthread_equal(_eina_main_loop, pthread_self()));
164 #endif
165         return EINA_LOCK_FAIL;
166      }
167 #endif
168
169 #ifdef EINA_HAVE_DEBUG_THREADS
170    if (!_eina_threads_activated)
171      assert(pthread_equal(_eina_main_loop, pthread_self()));
172 #endif
173
174    ok = pthread_mutex_trylock(&(mutex->mutex));
175    if (ok == 0) ret = EINA_LOCK_SUCCEED;
176    else if (ok == EDEADLK)
177      {
178         printf("ERROR ERROR: DEADLOCK on trylock %p\n", mutex);
179         ret = EINA_LOCK_DEADLOCK; // magic
180      }
181 #ifdef EINA_HAVE_DEBUG_THREADS
182    if (ret == EINA_LOCK_SUCCEED)
183      {
184         mutex->locked = 1;
185         mutex->lock_thread_id = pthread_self();
186         mutex->lock_bt_num = backtrace((void **)(mutex->lock_bt), EINA_LOCK_DEBUG_BT_NUM);
187      }
188 #endif
189    return ret;
190 }
191
192 static inline Eina_Lock_Result
193 eina_lock_release(Eina_Lock *mutex)
194 {
195    Eina_Lock_Result ret;
196
197 #ifdef EINA_HAVE_ON_OFF_THREADS
198    if (!_eina_threads_activated)
199      {
200 #ifdef EINA_HAVE_DEBUG_THREADS
201         assert(pthread_equal(_eina_main_loop, pthread_self()));
202 #endif
203         return EINA_LOCK_FAIL;
204      }
205 #endif
206
207 #ifdef EINA_HAVE_DEBUG_THREADS
208    mutex->locked = 0;
209    mutex->lock_thread_id = 0;
210    memset(mutex->lock_bt, 0, EINA_LOCK_DEBUG_BT_NUM * sizeof(Eina_Lock_Bt_Func));
211    mutex->lock_bt_num = 0;
212 #endif
213    ret = (pthread_mutex_unlock(&(mutex->mutex)) == 0) ?
214       EINA_LOCK_SUCCEED : EINA_LOCK_FAIL;
215    return ret;
216 }
217
218 static inline void
219 eina_lock_debug(Eina_Lock *mutex)
220 {
221 #ifdef EINA_HAVE_DEBUG_THREADS
222    printf("lock %p, locked: %i, by %i\n",
223           mutex, (int)mutex->locked, (int)mutex->lock_thread_id);
224    backtrace_symbols_fd((void **)mutex->lock_bt, mutex->lock_bt_num, 1);
225 #else
226    (void) mutex;
227 #endif
228 }
229
230 #endif