2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
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.
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.
20 * General Asterisk channel definitions.
23 #ifndef _ASTERISK_LOCK_H
24 #define _ASTERISK_LOCK_H
29 #include <sys/param.h>
31 #include "asterisk/logger.h"
33 #define AST_PTHREADT_NULL (pthread_t) -1
34 #define AST_PTHREADT_STOP (pthread_t) -2
37 /* Provide the Linux initializers for MacOS X */
38 #define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
39 #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP { 0x4d555458, \
40 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
46 #define AST_MUTEX_INIT_W_CONSTRUCTORS
48 #define AST_MUTEX_INIT_ON_FIRST_USE
52 /* From now on, Asterisk REQUIRES Recursive (not error checking) mutexes
53 and will not run without them. */
54 #ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
55 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
56 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP
58 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
59 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE
60 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
63 #define AST_MUTEX_INIT_W_CONSTRUCTORS
68 #define __ast_mutex_logger(...) { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); }
71 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
79 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, NULL, 0, 0, NULL, 0 }
81 struct ast_mutex_info {
82 pthread_mutex_t mutex;
90 typedef struct ast_mutex_info ast_mutex_t;
92 static inline int __ast_pthread_mutex_init_attr(const char *filename, int lineno, const char *func,
93 const char *mutex_name, ast_mutex_t *t,
94 pthread_mutexattr_t *attr)
96 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
97 int canlog = strcmp(filename, "logger.c");
99 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
100 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is already initialized.\n",
101 filename, lineno, func, mutex_name);
102 __ast_mutex_logger("%s line %d (%s): Error: previously initialization of mutex '%s'.\n",
103 t->file, t->lineno, t->func, mutex_name);
117 return pthread_mutex_init(&t->mutex, attr);
120 static inline int __ast_pthread_mutex_init(const char *filename, int lineno, const char *func,
121 const char *mutex_name, ast_mutex_t *t)
123 static pthread_mutexattr_t attr;
125 pthread_mutexattr_init(&attr);
126 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
128 return __ast_pthread_mutex_init_attr(filename, lineno, func, mutex_name, t, &attr);
131 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
132 const char *mutex_name, ast_mutex_t *t)
135 int canlog = strcmp(filename, "logger.c");
137 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
138 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
139 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
140 filename, lineno, func, mutex_name);
144 res = pthread_mutex_trylock(&t->mutex);
147 pthread_mutex_unlock(&t->mutex);
150 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
151 filename, lineno, func, mutex_name);
154 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
155 filename, lineno, func, mutex_name);
156 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
157 t->file, t->lineno, t->func, mutex_name);
161 if ((res = pthread_mutex_destroy(&t->mutex)))
162 __ast_mutex_logger("%s line %d (%s): Error destroying mutex: %s\n",
163 filename, lineno, func, strerror(res));
164 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
166 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
175 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
176 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
177 constrictors/destructors to create/destroy mutexes. */
178 #define __AST_MUTEX_DEFINE(scope,mutex) \
179 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
180 static void __attribute__ ((constructor)) init_##mutex(void) \
182 ast_mutex_init(&mutex); \
184 static void __attribute__ ((destructor)) fini_##mutex(void) \
186 ast_mutex_destroy(&mutex); \
188 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
189 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
190 first use. The performance impact on FreeBSD should be small since
191 the pthreads library does this itself to initialize errror checking
192 (defaulty type) mutexes. If nither is defined, the pthreads librariy
193 does the initialization itself on first use. */
194 #define __AST_MUTEX_DEFINE(scope,mutex) \
195 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
196 #else /* AST_MUTEX_INIT_W_CONSTRUCTORS */
197 /* By default, use static initialization of mutexes.*/
198 #define __AST_MUTEX_DEFINE(scope,mutex) \
199 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
200 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
202 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
203 const char* mutex_name, ast_mutex_t *t)
206 int canlog = strcmp(filename, "logger.c");
208 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
209 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
210 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
211 ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
212 filename, lineno, func, mutex_name);
216 #endif /* defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
218 #ifdef DETECT_DEADLOCKS
220 time_t seconds = time(NULL);
223 res = pthread_mutex_trylock(&t->mutex);
225 current = time(NULL);
226 if ((current - seconds) && (!((current - seconds) % 5))) {
227 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
228 filename, lineno, func, (int)(current - seconds), mutex_name);
229 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
230 t->file, t->lineno, t->func, mutex_name);
234 } while (res == EBUSY);
237 res = pthread_mutex_lock(&t->mutex);
238 #endif /* DETECT_DEADLOCKS */
245 t->thread = pthread_self();
247 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
248 filename, lineno, func, strerror(errno));
257 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
258 const char* mutex_name, ast_mutex_t *t)
262 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE)
263 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
264 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
265 int canlog = strcmp(filename, "logger.c");
267 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
268 filename, lineno, func, mutex_name);
272 #endif /* defined(AST_MUTEX_INIT_W_CONSTRUCTORS) || defined(AST_MUTEX_INIT_ON_FIRST_USE) */
274 if (!(res = pthread_mutex_trylock(&t->mutex))) {
279 t->thread = pthread_self();
285 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
286 const char *mutex_name, ast_mutex_t *t)
289 int canlog = strcmp(filename, "logger.c");
291 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
292 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
293 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
294 filename, lineno, func, mutex_name);
298 if (t->reentrancy && (t->thread != pthread_self())) {
299 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
300 filename, lineno, func, mutex_name);
301 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
302 t->file, t->lineno, t->func, mutex_name);
308 if (--t->reentrancy < 0) {
309 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
310 filename, lineno, func, mutex_name);
314 if (!t->reentrancy) {
321 if ((res = pthread_mutex_unlock(&t->mutex))) {
322 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
323 filename, lineno, func, strerror(res));
332 static inline int __ast_pthread_cond_wait(const char *filename, int lineno, const char *func,
333 pthread_cond_t *cond, const char *mutex_name, ast_mutex_t *t)
336 int canlog = strcmp(filename, "logger.c");
338 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
339 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
340 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
341 filename, lineno, func, mutex_name);
345 if (t->reentrancy && (t->thread != pthread_self())) {
346 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
347 filename, lineno, func, mutex_name);
348 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
349 t->file, t->lineno, t->func, mutex_name);
355 if (--t->reentrancy < 0) {
356 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
357 filename, lineno, func, mutex_name);
361 if (!t->reentrancy) {
368 if ((res = pthread_cond_wait(cond, &t->mutex))) {
369 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
370 filename, lineno, func, strerror(res));
379 t->thread = pthread_self();
385 static inline int __ast_pthread_cond_timedwait(const char *filename, int lineno, const char *func,
386 pthread_cond_t *cond, const struct timespec *abstime,
387 const char *mutex_name, ast_mutex_t *t)
390 int canlog = strcmp(filename, "logger.c");
392 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
393 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
394 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
395 filename, lineno, func, mutex_name);
399 if (t->reentrancy && (t->thread != pthread_self())) {
400 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
401 filename, lineno, func, mutex_name);
402 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
403 t->file, t->lineno, t->func, mutex_name);
409 if (--t->reentrancy < 0) {
410 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
411 filename, lineno, func, mutex_name);
415 if (!t->reentrancy) {
422 if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime))) {
423 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
424 filename, lineno, func, strerror(res));
433 t->thread = pthread_self();
439 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
440 #define ast_pthread_mutex_init(pmutex,attr) __ast_pthread_mutex_init_attr(__FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex, attr)
441 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
442 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
443 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
444 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
445 #define ast_pthread_cond_wait(cond, a) __ast_pthread_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, cond, #a, a)
446 #define ast_pthread_cond_timedwait(cond, a, t) __ast_pthread_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, cond, t, #a, a)
448 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
449 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
450 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
451 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
452 #define pthread_mutex_init use_ast_pthread_mutex_init_instead_of_pthread_mutex_init
453 #define pthread_mutex_destroy use_ast_pthread_mutex_destroy_instead_of_pthread_mutex_destroy
454 #define pthread_cond_wait use_ast_pthread_cond_wait_instead_of_pthread_cond_wait
455 #define pthread_cond_timedwait use_ast_pthread_cond_wait_instead_of_pthread_cond_timedwait
457 #else /* !DEBUG_THREADS */
460 #define AST_MUTEX_INIT_VALUE PTHREAD_MUTEX_INIT_VALUE
463 typedef pthread_mutex_t ast_mutex_t;
465 static inline int ast_mutex_init(ast_mutex_t *pmutex)
467 pthread_mutexattr_t attr;
468 pthread_mutexattr_init(&attr);
469 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
470 return pthread_mutex_init(pmutex, &attr);
472 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
473 #define ast_mutex_unlock(pmutex) pthread_mutex_unlock(pmutex)
474 #define ast_mutex_destroy(pmutex) pthread_mutex_destroy(pmutex)
476 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
477 /* if AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope
478 constrictors/destructors to create/destroy mutexes. */
479 #define __AST_MUTEX_DEFINE(scope,mutex) \
480 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE; \
481 static void __attribute__ ((constructor)) init_##mutex(void) \
483 ast_mutex_init(&mutex); \
485 static void __attribute__ ((destructor)) fini_##mutex(void) \
487 ast_mutex_destroy(&mutex); \
490 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
491 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
493 #elif defined(AST_MUTEX_INIT_ON_FIRST_USE)
494 /* if AST_MUTEX_INIT_ON_FIRST_USE is defined, mutexes are created on
495 first use. The performance impact on FreeBSD should be small since
496 the pthreads library does this itself to initialize errror checking
497 (defaulty type) mutexes.*/
498 #define __AST_MUTEX_DEFINE(scope,mutex) \
499 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
501 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
503 if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
504 ast_mutex_init(pmutex);
505 return pthread_mutex_lock(pmutex);
507 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
509 if (*pmutex == (ast_mutex_t)AST_MUTEX_KIND)
510 ast_mutex_init(pmutex);
511 return pthread_mutex_trylock(pmutex);
514 /* By default, use static initialization of mutexes.*/
515 #define __AST_MUTEX_DEFINE(scope,mutex) \
516 scope ast_mutex_t mutex = AST_MUTEX_INIT_VALUE
517 #define ast_mutex_lock(pmutex) pthread_mutex_lock(pmutex)
518 #define ast_mutex_trylock(pmutex) pthread_mutex_trylock(pmutex)
519 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
521 #define ast_pthread_cond_wait pthread_cond_wait
522 #define ast_pthread_cond_timedwait pthread_cond_timedwait
524 #endif /* !DEBUG_THREADS */
526 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static,mutex)
527 #define AST_MUTEX_DEFINE_EXPORTED(mutex) __AST_MUTEX_DEFINE(/**/,mutex)
529 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
531 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
533 #define pthread_create __use_ast_pthread_create_instead__
536 #endif /* _ASTERISK_LOCK_H */