69aaaeefdb15ae3037f5006449458da954aa743b
[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 seconds = time(NULL);
202                 do {
203                         res = pthread_mutex_trylock(&t->mutex);
204                         if (res == EBUSY) {
205                                 if ((time(NULL) - seconds) % 5) {
206                                         fprintf(stderr, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
207                                                 filename, lineno, func, (time(NULL) - seconds), mutex_name);
208                                         fprintf(stderr, "%s line %d (%s): '%s' was locked here.\n",
209                                                 t->file, t->lineno, t->func, mutex_name);
210                                 }
211                                 usleep(200);
212                         }
213                 } while (res == EBUSY);
214         }
215 #else
216         res = pthread_mutex_lock(&t->mutex);
217 #endif /*  DETECT_DEADLOCKS */
218         if (!res) {
219                 t->reentrancy++;
220                 t->file = filename;
221                 t->lineno = lineno;
222                 t->func = func;
223                 t->thread = pthread_self();
224         } else {
225                 fprintf(stderr, "%s line %d (%s): Error obtaining mutex: %s\n",
226                         filename, lineno, func, strerror(errno));
227 #ifdef THREAD_CRASH
228                 DO_THREAD_CRASH;
229 #endif
230         }
231         return res;
232 }
233
234 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
235
236 static inline int __ast_pthread_mutex_trylock(char *filename, int lineno, char *func,
237                                               char* mutex_name, ast_mutex_t *t)
238 {
239         int res;
240 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
241         if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
242 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
243                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
244                         filename, lineno, func, mutex_name);
245 #endif
246                 ast_mutex_init(t);
247         }
248 #endif /* definded(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
249         res = pthread_mutex_trylock(&t->mutex);
250         if (!res) {
251                 t->reentrancy++;
252                 t->file = filename;
253                 t->lineno = lineno;
254                 t->func = func;
255                 t->thread = pthread_self();
256         }
257         return res;
258 }
259
260 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
261
262 static inline int __ast_pthread_mutex_unlock(char *filename, int lineno, char *func,
263                         char* mutex_name, ast_mutex_t *t) {
264         int res;
265 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
266         if ((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
267                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
268                         filename, lineno, func, mutex_name);
269         }
270 #endif
271         --t->reentrancy;
272         if (t->reentrancy < 0) {
273                 fprintf(stderr, "%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
274                         filename, lineno, func, mutex_name);
275                 t->reentrancy = 0;
276         }
277         if (!t->reentrancy) {
278                 t->file = NULL;
279                 t->lineno = 0;
280                 t->func = NULL;
281                 t->thread = 0;
282         }
283         res = pthread_mutex_unlock(&t->mutex);
284         if (res) {
285                 fprintf(stderr, "%s line %d (%s): Error releasing mutex: %s\n", 
286                                 filename, lineno, func, strerror(res));
287 #ifdef THREAD_CRASH
288                 DO_THREAD_CRASH;
289 #endif
290         }
291         return res;
292 }
293
294 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
295
296 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
297 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
298 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
299 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
300 #define pthread_mutex_init use_ast_pthread_mutex_init_instead_of_pthread_mutex_init
301 #define pthread_mutex_destroy use_ast_pthread_mutex_destroy_instead_of_pthread_mutex_destroy
302
303 #else /* DEBUG_THREADS */
304
305
306 #define AST_MUTEX_INIT_VALUE    PTHREAD_MUTEX_INIT_VALUE
307
308
309 typedef pthread_mutex_t ast_mutex_t;
310
311 static inline int ast_mutex_init(ast_mutex_t *pmutex)
312 {
313         pthread_mutexattr_t attr;
314         pthread_mutexattr_init(&attr);
315         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
316         return pthread_mutex_init(pmutex, &attr);
317 }
318 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
319 #define ast_mutex_unlock(pmutex) pthread_mutex_unlock(pmutex)
320 #define ast_mutex_destroy(pmutex) pthread_mutex_destroy(pmutex)
321
322 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
323 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
324  constrictors/destructors to create/destroy mutexes.  */ 
325 #define __AST_MUTEX_DEFINE(scope,mutex) \
326         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
327 static void  __attribute__ ((constructor)) init_##mutex(void) \
328 { \
329         ast_mutex_init(&mutex); \
330 } \
331 static void  __attribute__ ((destructor)) fini_##mutex(void) \
332 { \
333         ast_mutex_destroy(&mutex); \
334 }
335
336 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
337 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
338
339 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
340 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
341  first use.  The performance impact on FreeBSD should be small since
342  the pthreads library does this itself to initialize errror checking
343  (defaulty type) mutexes.*/ 
344 #define __AST_MUTEX_DEFINE(scope,mutex) \
345         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
346
347 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
348 {
349         if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
350                 ast_mutex_init(pmutex);
351         return pthread_mutex_lock(pmutex);
352 }
353 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
354 {
355         if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
356                 ast_mutex_init(pmutex);
357         return pthread_mutex_trylock(pmutex);
358 }
359 #else
360 /* By default, use static initialization of mutexes.*/ 
361 #define __AST_MUTEX_DEFINE(scope,mutex) \
362         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
363 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
364 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
365 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
366
367 #endif /* DEBUG_THREADS */
368
369 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static,mutex)
370 #define AST_MUTEX_DEFINE_EXPORTED(mutex) __AST_MUTEX_DEFINE(/**/,mutex)
371
372 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
373
374 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
375 #ifndef __linux__
376 #define pthread_create __use_ast_pthread_create_instead__
377 #endif
378
379 #endif