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