Minor deadlock detect fix (bug #3531)
[asterisk/asterisk.git] / include / asterisk / lock.h
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * General Asterisk channel definitions.
5  * 
6  * Copyright (C) 1999 - 2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #ifndef _ASTERISK_LOCK_H
15 #define _ASTERISK_LOCK_H
16
17 #include <pthread.h>
18 #include <netdb.h>
19 #include <time.h>
20 #include <sys/param.h>
21
22 #define AST_PTHREADT_NULL (pthread_t) -1
23 #define AST_PTHREADT_STOP (pthread_t) -2
24
25 #ifdef __APPLE__
26 /* Provide the Linux initializers for MacOS X */
27 #define PTHREAD_MUTEX_RECURSIVE_NP                                      PTHREAD_MUTEX_RECURSIVE
28 #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP           { 0x4d555458, \
29                                                                                                            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
30                                                                                                                  0x20 } }
31 #endif
32
33 #ifdef BSD
34 #ifdef __GNUC__
35 #define AST_MUTEX_INIT_W_CONSTRUCTORS
36 #else
37 #define AST_MUTEX_INIT_ON_FIRST_USE
38 #endif
39 #endif /* BSD */
40
41 /* From now on, Asterisk REQUIRES Recursive (not error checking) mutexes
42    and will not run without them. */
43 #ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
44 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
45 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE_NP
46 #else
47 #define PTHREAD_MUTEX_INIT_VALUE        PTHREAD_MUTEX_INITIALIZER
48 #define AST_MUTEX_KIND                  PTHREAD_MUTEX_RECURSIVE
49 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
50
51 #ifdef SOLARIS
52 #define AST_MUTEX_INIT_W_CONSTRUCTORS
53 #endif
54
55 #ifdef DEBUG_THREADS
56
57 #ifdef THREAD_CRASH
58 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
59 #endif
60
61 #include <errno.h>
62 #include <string.h>
63 #include <stdio.h>
64 #include <unistd.h>
65
66 #define AST_MUTEX_INIT_VALUE      { PTHREAD_MUTEX_INIT_VALUE, NULL, 0, 0, NULL, 0 }
67
68 struct ast_mutex_info {
69         pthread_mutex_t mutex;
70         char *file;
71         int lineno;
72         int reentrancy;
73         char *func;
74         pthread_t thread;
75 };
76
77 typedef struct ast_mutex_info ast_mutex_t;
78
79 static inline int __ast_pthread_mutex_init_attr(char *filename, int lineno, char *func,
80                                                 char* mutex_name, ast_mutex_t *t,
81                                                 pthread_mutexattr_t *attr) 
82 {
83 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
84         if ((t->mutex) != ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
85                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is already initialized.\n",
86                         filename, lineno, func, mutex_name);
87                 fprintf(stderr, "%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
88                         t->file, t->lineno, t->func, mutex_name);
89 #ifdef THREAD_CRASH
90                 DO_THREAD_CRASH;
91 #endif
92                 return 0;
93         }
94 #endif
95         t->file = filename;
96         t->lineno = lineno;
97         t->func = func;
98         t->thread  = 0;
99         t->reentrancy = 0;
100         return pthread_mutex_init(&t->mutex, attr);
101 }
102
103 static inline int __ast_pthread_mutex_init(char *filename, int lineno, char *func,
104                                                 char *mutex_name, ast_mutex_t *t)
105 {
106         static pthread_mutexattr_t  attr;
107         pthread_mutexattr_init(&attr);
108         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
109         return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
110 }
111
112 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
113 #define ast_pthread_mutex_init(pmutex,attr) __ast_pthread_mutex_init_attr(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex, attr)
114
115 static inline int __ast_pthread_mutex_destroy(char *filename, int lineno, char *func,
116                                                 char *mutex_name, ast_mutex_t *t)
117 {
118         int res;
119 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
120         if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
121                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
122                         filename, lineno, func, mutex_name);
123         }
124 #endif
125         res = pthread_mutex_trylock(&t->mutex);
126         switch (res) {
127         case 0:
128                 pthread_mutex_unlock(&t->mutex);
129                 break;
130         case EINVAL:
131                 fprintf(stderr, "%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
132                         filename, lineno, func, mutex_name);
133                 break;
134         case EBUSY:
135                 fprintf(stderr, "%s line %d (%s): Error: attemp to destroy locked mutex '%s'.\n",
136                         filename, lineno, func, mutex_name);
137                 fprintf(stderr, "%s line %d (%s): Error: '%s' was locked here.\n",
138                         t->file, t->lineno, t->func, mutex_name);
139                 break;
140         }
141         res = pthread_mutex_destroy(&t->mutex);
142         if (res) 
143                 fprintf(stderr, "%s line %d (%s): Error destroying mutex: %s\n",
144                                 filename, lineno, func, strerror(res));
145 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
146         else
147                 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
148 #endif
149         t->file = filename;
150         t->lineno = lineno;
151         t->func = func;
152         return res;
153 }
154
155 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
156
157 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
158 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
159  constrictors/destructors to create/destroy mutexes.  */
160 #define __AST_MUTEX_DEFINE(scope,mutex) \
161         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
162 static void  __attribute__ ((constructor)) init_##mutex(void) \
163 { \
164         ast_mutex_init(&mutex); \
165 } \
166 static void  __attribute__ ((destructor)) fini_##mutex(void) \
167 { \
168         ast_mutex_destroy(&mutex); \
169 }
170 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
171 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
172  first use.  The performance impact on FreeBSD should be small since
173  the pthreads library does this itself to initialize errror checking
174  (defaulty type) mutexes.  If nither is defined, the pthreads librariy
175  does the initialization itself on first use. */ 
176 #define __AST_MUTEX_DEFINE(scope,mutex) \
177         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
178 #else /* AST_MUTEX_INIT_W_CONSTRUCTORS */
179 /* By default, use static initialization of mutexes.*/ 
180 #define __AST_MUTEX_DEFINE(scope,mutex) \
181         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
182 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
183
184
185
186 static inline int __ast_pthread_mutex_lock(char *filename, int lineno, char *func,
187                                            char* mutex_name, ast_mutex_t *t)
188 {
189         int res;
190 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
191         if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
192 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
193                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
194                         filename, lineno, func, mutex_name);
195 #endif
196                 ast_mutex_init(t);
197         }
198 #endif /* definded(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
199 #ifdef DETECT_DEADLOCKS
200         {
201                 time_t seconds = time(NULL);
202                 time_t current;
203                 do {
204                         res = pthread_mutex_trylock(&t->mutex);
205                         if (res == EBUSY) {
206                                 current = time(NULL);
207                                 if ((current - seconds) && (!((current - seconds) % 5))) {
208                                         fprintf(stderr, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
209                                                 filename, lineno, func, (int)(current - seconds), mutex_name);
210                                         fprintf(stderr, "%s line %d (%s): '%s' was locked here.\n",
211                                                 t->file, t->lineno, t->func, mutex_name);
212                                 }
213                                 usleep(200);
214                         }
215                 } while (res == EBUSY);
216         }
217 #else
218         res = pthread_mutex_lock(&t->mutex);
219 #endif /*  DETECT_DEADLOCKS */
220         if (!res) {
221                 t->reentrancy++;
222                 t->file = filename;
223                 t->lineno = lineno;
224                 t->func = func;
225                 t->thread = pthread_self();
226         } else {
227                 fprintf(stderr, "%s line %d (%s): Error obtaining mutex: %s\n",
228                         filename, lineno, func, strerror(errno));
229 #ifdef THREAD_CRASH
230                 DO_THREAD_CRASH;
231 #endif
232         }
233         return res;
234 }
235
236 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
237
238 static inline int __ast_pthread_mutex_trylock(char *filename, int lineno, char *func,
239                                               char* mutex_name, ast_mutex_t *t)
240 {
241         int res;
242 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
243         if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
244 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
245                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
246                         filename, lineno, func, mutex_name);
247 #endif
248                 ast_mutex_init(t);
249         }
250 #endif /* definded(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
251         res = pthread_mutex_trylock(&t->mutex);
252         if (!res) {
253                 t->reentrancy++;
254                 t->file = filename;
255                 t->lineno = lineno;
256                 t->func = func;
257                 t->thread = pthread_self();
258         }
259         return res;
260 }
261
262 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
263
264 static inline int __ast_pthread_mutex_unlock(char *filename, int lineno, char *func,
265                         char* mutex_name, ast_mutex_t *t) {
266         int res;
267 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
268         if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
269                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
270                         filename, lineno, func, mutex_name);
271         }
272 #endif
273         --t->reentrancy;
274         if (t->reentrancy < 0) {
275                 fprintf(stderr, "%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
276                         filename, lineno, func, mutex_name);
277                 t->reentrancy = 0;
278         }
279         if (!t->reentrancy) {
280                 t->file = NULL;
281                 t->lineno = 0;
282                 t->func = NULL;
283                 t->thread = 0;
284         }
285         res = pthread_mutex_unlock(&t->mutex);
286         if (res) {
287                 fprintf(stderr, "%s line %d (%s): Error releasing mutex: %s\n", 
288                                 filename, lineno, func, strerror(res));
289 #ifdef THREAD_CRASH
290                 DO_THREAD_CRASH;
291 #endif
292         }
293         return res;
294 }
295
296 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
297
298 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
299 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
300 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
301 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
302 #define pthread_mutex_init use_ast_pthread_mutex_init_instead_of_pthread_mutex_init
303 #define pthread_mutex_destroy use_ast_pthread_mutex_destroy_instead_of_pthread_mutex_destroy
304
305 #else /* DEBUG_THREADS */
306
307
308 #define AST_MUTEX_INIT_VALUE    PTHREAD_MUTEX_INIT_VALUE
309
310
311 typedef pthread_mutex_t ast_mutex_t;
312
313 static inline int ast_mutex_init(ast_mutex_t *pmutex)
314 {
315         pthread_mutexattr_t attr;
316         pthread_mutexattr_init(&attr);
317         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
318         return pthread_mutex_init(pmutex, &attr);
319 }
320 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
321 #define ast_mutex_unlock(pmutex) pthread_mutex_unlock(pmutex)
322 #define ast_mutex_destroy(pmutex) pthread_mutex_destroy(pmutex)
323
324 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
325 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
326  constrictors/destructors to create/destroy mutexes.  */ 
327 #define __AST_MUTEX_DEFINE(scope,mutex) \
328         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
329 static void  __attribute__ ((constructor)) init_##mutex(void) \
330 { \
331         ast_mutex_init(&mutex); \
332 } \
333 static void  __attribute__ ((destructor)) fini_##mutex(void) \
334 { \
335         ast_mutex_destroy(&mutex); \
336 }
337
338 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
339 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
340
341 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
342 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
343  first use.  The performance impact on FreeBSD should be small since
344  the pthreads library does this itself to initialize errror checking
345  (defaulty type) mutexes.*/ 
346 #define __AST_MUTEX_DEFINE(scope,mutex) \
347         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
348
349 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
350 {
351         if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
352                 ast_mutex_init(pmutex);
353         return pthread_mutex_lock(pmutex);
354 }
355 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
356 {
357         if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
358                 ast_mutex_init(pmutex);
359         return pthread_mutex_trylock(pmutex);
360 }
361 #else
362 /* By default, use static initialization of mutexes.*/ 
363 #define __AST_MUTEX_DEFINE(scope,mutex) \
364         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
365 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
366 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
367 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
368
369 #endif /* DEBUG_THREADS */
370
371 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static,mutex)
372 #define AST_MUTEX_DEFINE_EXPORTED(mutex) __AST_MUTEX_DEFINE(/**/,mutex)
373
374 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
375
376 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
377 #ifndef __linux__
378 #define pthread_create __use_ast_pthread_create_instead__
379 #endif
380
381 #endif