Merge major BSD mutex and symbol conflict patches (bug #1816) (link patch still pending)
[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, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
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 DEBUG_THREADS
52
53 #ifdef THREAD_CRASH
54 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
55 #endif
56
57 #include <errno.h>
58 #include <string.h>
59 #include <stdio.h>
60 #include <unistd.h>
61
62 #define AST_MUTEX_INIT_VALUE      { PTHREAD_MUTEX_INIT_VALUE, NULL, 0, NULL, 0 }
63
64 struct ast_mutex_info {
65         pthread_mutex_t mutex;
66         char *file;
67         int lineno;
68         char *func;
69         pthread_t thread;
70 };
71
72 typedef struct ast_mutex_info ast_mutex_t;
73
74 static inline int __ast_pthread_mutex_init_attr(char *filename, int lineno, char *func,
75                                          char* mutex_name, ast_mutex_t *t,
76                                          pthread_mutexattr_t *attr) 
77 {
78 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
79         if((t->mutex) != ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
80                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is already initialized.\n",
81                         filename, lineno, func, mutex_name);
82                 fprintf(stderr, "%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
83                         t->file, t->lineno, t->func, mutex_name);
84 #ifdef THREAD_CRASH
85                 DO_THREAD_CRASH;
86 #endif
87                 return 0;
88         }
89 #endif
90         t->file = filename;
91         t->lineno = lineno;
92         t->func = func;
93         t->thread  = 0;
94         return pthread_mutex_init(&t->mutex, attr);
95 }
96
97 static inline int __ast_pthread_mutex_init(char *filename, int lineno, char *func,
98                                            char* mutex_name, ast_mutex_t *t)
99 {
100         static pthread_mutexattr_t  attr;
101         pthread_mutexattr_init(&attr);
102         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
103         return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
104 }
105
106 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
107 #define ast_pthread_mutex_init(pmutex,attr) __ast_pthread_mutex_init_attr(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex, attr)
108
109 static inline int __ast_pthread_mutex_destroy(char *filename, int lineno, char *func,
110                                               char* mutex_name, ast_mutex_t *t)
111 {
112         int res;
113 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
114         if((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
115                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
116                         filename, lineno, func, mutex_name);
117         }
118 #endif
119         res = pthread_mutex_trylock(&t->mutex);
120         switch( res ) {
121         case 0:
122           pthread_mutex_unlock(&t->mutex);
123           break;
124         case EINVAL:
125           fprintf(stderr, "%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
126                   filename, lineno, func, mutex_name);
127           break;
128         case EBUSY:
129           fprintf(stderr, "%s line %d (%s): Error: attemp to destroy locked mutex '%s'.\n",
130                   filename, lineno, func, mutex_name);
131           fprintf(stderr, "%s line %d (%s): Error: '%s' was locked here.\n",
132                   t->file, t->lineno, t->func, mutex_name);
133           break;
134         }
135         res = pthread_mutex_destroy(&t->mutex);
136         if (res) 
137                 fprintf(stderr, "%s line %d (%s): Error destroying mutex: %s\n",
138                                 filename, lineno, func, strerror(res));
139 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
140         else
141                 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
142 #endif
143         t->file = filename;
144         t->lineno = lineno;
145         t->func = func;
146         return res;
147 }
148
149 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
150
151 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
152 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
153  constrictors/destructors to create/destroy mutexes.  */
154 #define __AST_MUTEX_DEFINE(scope,mutex) \
155         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
156 static void  __attribute__ ((constructor)) init_##mutex(void) \
157 { \
158         ast_mutex_init(&mutex); \
159 } \
160 static void  __attribute__ ((destructor)) fini_##mutex(void) \
161 { \
162         ast_mutex_destroy(&mutex); \
163 }
164 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
165 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
166  first use.  The performance impact on FreeBSD should be small since
167  the pthreads library does this itself to initialize errror checking
168  (defaulty type) mutexes.  If nither is defined, the pthreads librariy
169  does the initialization itself on first use. */ 
170 #define __AST_MUTEX_DEFINE(scope,mutex) \
171         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
172 #else /* AST_MUTEX_INIT_W_CONSTRUCTORS */
173 /* By default, use static initialization of mutexes.*/ 
174 #define __AST_MUTEX_DEFINE(scope,mutex) \
175         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
176 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
177
178
179
180 static inline int __ast_pthread_mutex_lock(char *filename, int lineno, char *func,
181                                            char* mutex_name, ast_mutex_t *t)
182 {
183         int res;
184 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
185         if((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
186 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
187                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
188                         filename, lineno, func, mutex_name);
189 #endif
190                 ast_mutex_init(t);
191         }
192 #endif /* definded(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
193 #ifdef DETECT_DEADLOCKS
194         {
195           time_t seconds seconds = time(NULL);
196           do {
197             res = pthread_mutex_trylock(&t->mutex);
198             if(res == EBUSY) {
199               if((time(NULL) - seconds) % 5) {
200                 fprintf(stderr, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
201                         filename, lineno, func, (time(NULL) - seconds), mutex_name);
202                 fprintf(stderr, "%s line %d (%s): '%s' was locked here.\n",
203                         t->file, t->lineno, t->func, mutex_name);
204               }
205               usleep(200);
206             }
207           } while (res == EBUSY);
208         }
209 #else
210         res = pthread_mutex_lock(&t->mutex);
211 #endif /*  DETECT_DEADLOCKS */
212         if (!res) {
213                 t->file = filename;
214                 t->lineno = lineno;
215                 t->func = func;
216                 t->thread = pthread_self();
217         } else {
218                 fprintf(stderr, "%s line %d (%s): Error obtaining mutex: %s\n",
219                         filename, lineno, func, strerror(errno));
220 #ifdef THREAD_CRASH
221                 DO_THREAD_CRASH;
222 #endif
223         }
224         return res;
225 }
226
227 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
228
229 static inline int __ast_pthread_mutex_trylock(char *filename, int lineno, char *func,
230                                               char* mutex_name, ast_mutex_t *t)
231 {
232         int res;
233 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
234         if((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
235 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
236                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
237                         filename, lineno, func, mutex_name);
238 #endif
239                 ast_mutex_init(t);
240         }
241 #endif /* definded(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
242         res = pthread_mutex_trylock(&t->mutex);
243         if (!res) {
244                 t->file = filename;
245                 t->lineno = lineno;
246                 t->func = func;
247                 t->thread = pthread_self();
248         }
249         return res;
250 }
251
252 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
253
254 static inline int __ast_pthread_mutex_unlock(char *filename, int lineno, char *func,
255                                              char* mutex_name, ast_mutex_t *t) {
256         int res;
257 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
258         if((t->mutex) == ((pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER)) {
259                 fprintf(stderr, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
260                         filename, lineno, func, mutex_name);
261         }
262 #endif
263         /* Assumes lock is actually held */
264         t->file = NULL;
265         t->lineno = 0;
266         t->func = NULL;
267         t->thread = 0;
268         res = pthread_mutex_unlock(&t->mutex);
269         if (res) {
270                 fprintf(stderr, "%s line %d (%s): Error releasing mutex: %s\n", 
271                                 filename, lineno, func, strerror(res));
272 #ifdef THREAD_CRASH
273                 DO_THREAD_CRASH;
274 #endif
275         }
276         return res;
277 }
278
279 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
280
281 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
282 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
283 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
284 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
285 #define pthread_mutex_init use_ast_pthread_mutex_init_instead_of_pthread_mutex_init
286 #define pthread_mutex_destroy use_ast_pthread_mutex_destroy_instead_of_pthread_mutex_destroy
287
288 #else /* DEBUG_THREADS */
289
290
291 #define AST_MUTEX_INIT_VALUE    PTHREAD_MUTEX_INIT_VALUE
292
293
294 typedef pthread_mutex_t ast_mutex_t;
295
296 static inline int ast_mutex_init(ast_mutex_t *pmutex)
297 {
298         pthread_mutexattr_t attr;
299         pthread_mutexattr_init(&attr);
300         pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
301         return pthread_mutex_init(pmutex, &attr);
302 }
303 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
304 #define ast_mutex_unlock(pmutex) pthread_mutex_unlock(pmutex)
305 #define ast_mutex_destroy(pmutex) pthread_mutex_destroy(pmutex)
306
307 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
308 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
309  constrictors/destructors to create/destroy mutexes.  */ 
310 #define __AST_MUTEX_DEFINE(scope,mutex) \
311         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
312 static void  __attribute__ ((constructor)) init_##mutex(void) \
313 { \
314         ast_mutex_init(&mutex); \
315 } \
316 static void  __attribute__ ((destructor)) fini_##mutex(void) \
317 { \
318         ast_mutex_destroy(&mutex); \
319 }
320
321 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
322 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
323
324 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
325 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
326  first use.  The performance impact on FreeBSD should be small since
327  the pthreads library does this itself to initialize errror checking
328  (defaulty type) mutexes.*/ 
329 #define __AST_MUTEX_DEFINE(scope,mutex) \
330         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
331
332 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
333 {
334   if(*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
335     ast_mutex_init(pmutex);
336   return pthread_mutex_lock(pmutex);
337 }
338 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
339 {
340   if(*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
341     ast_mutex_init(pmutex);
342   return pthread_mutex_trylock(pmutex);
343 }
344 #else
345 /* By default, use static initialization of mutexes.*/ 
346 #define __AST_MUTEX_DEFINE(scope,mutex) \
347         scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
348 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
349 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
350 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
351
352 #endif /* DEBUG_THREADS */
353
354 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static,mutex)
355 #define AST_MUTEX_DEFINE_EXPORTED(mutex) __AST_MUTEX_DEFINE(/**/,mutex)
356
357
358 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
359
360 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
361
362 #endif