2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, 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 * \brief Asterisk locking-related definitions:
21 * - ast_mutext_t, ast_rwlock_t and related functions;
22 * - atomic arithmetic instructions;
23 * - wrappers for channel locking.
28 /*! \page LockDef Asterisk thread locking models
30 * This file provides different implementation of the functions,
31 * depending on the platform, the use of DEBUG_THREADS, and the way
32 * module-level mutexes are initialized.
34 * - \b static: the mutex is assigned the value AST_MUTEX_INIT_VALUE
35 * this is done at compile time, and is the way used on Linux.
36 * This method is not applicable to all platforms e.g. when the
37 * initialization needs that some code is run.
39 * - \b through constructors: for each mutex, a constructor function is
40 * defined, which then runs when the program (or the module)
41 * starts. The problem with this approach is that there is a
42 * lot of code duplication (a new block of code is created for
43 * each mutex). Also, it does not prevent a user from declaring
44 * a global mutex without going through the wrapper macros,
45 * so sane programming practices are still required.
48 #ifndef _ASTERISK_LOCK_H
49 #define _ASTERISK_LOCK_H
52 #include <sys/param.h>
54 #include "asterisk/logger.h"
56 /* internal macro to profile mutexes. Only computes the delay on
59 #ifndef HAVE_MTX_PROFILE
60 #define __MTX_PROF(a) return pthread_mutex_lock((a))
62 #define __MTX_PROF(a) do { \
64 /* profile only non-blocking events */ \
65 ast_mark(mtx_prof, 1); \
66 i = pthread_mutex_trylock((a)); \
67 ast_mark(mtx_prof, 0); \
71 return pthread_mutex_lock((a)); \
73 #endif /* HAVE_MTX_PROFILE */
75 #define AST_PTHREADT_NULL (pthread_t) -1
76 #define AST_PTHREADT_STOP (pthread_t) -2
78 #if defined(SOLARIS) || defined(BSD)
79 #define AST_MUTEX_INIT_W_CONSTRUCTORS
80 #endif /* SOLARIS || BSD */
82 /* Asterisk REQUIRES recursive (not error checking) mutexes
83 and will not run without them. */
84 #if defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(HAVE_PTHREAD_MUTEX_RECURSIVE_NP)
85 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
86 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE_NP
88 #define PTHREAD_MUTEX_INIT_VALUE PTHREAD_MUTEX_INITIALIZER
89 #define AST_MUTEX_KIND PTHREAD_MUTEX_RECURSIVE
90 #endif /* PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
93 * Definition of ast_mutex_t, ast_cont_d and related functions with/without debugging
94 * (search for DEBUG_THREADS to find the start/end of the sections).
96 * The non-debug code contains just wrappers for the corresponding pthread functions.
97 * The debug code tracks usage and tries to identify deadlock situations.
101 #define __ast_mutex_logger(...) do { if (canlog) ast_log(LOG_ERROR, __VA_ARGS__); else fprintf(stderr, __VA_ARGS__); } while (0)
104 #define DO_THREAD_CRASH do { *((int *)(0)) = 1; } while(0)
106 #define DO_THREAD_CRASH do { } while (0)
111 #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
112 #define AST_MUTEX_INIT_VALUE_NOTRACKING \
113 { PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
115 #define AST_MAX_REENTRANCY 10
117 struct ast_mutex_info {
118 pthread_mutex_t mutex;
119 /*! Track which thread holds this lock */
120 unsigned int track:1;
121 const char *file[AST_MAX_REENTRANCY];
122 int lineno[AST_MAX_REENTRANCY];
124 const char *func[AST_MAX_REENTRANCY];
125 pthread_t thread[AST_MAX_REENTRANCY];
126 pthread_mutex_t reentr_mutex;
129 typedef struct ast_mutex_info ast_mutex_t;
131 typedef pthread_cond_t ast_cond_t;
133 static pthread_mutex_t empty_mutex;
142 * \brief Store lock info for the current thread
144 * This function gets called in ast_mutex_lock() and ast_mutex_trylock() so
145 * that information about this lock can be stored in this thread's
146 * lock info struct. The lock is marked as pending as the thread is waiting
147 * on the lock. ast_mark_lock_acquired() will mark it as held by this thread.
149 void ast_store_lock_info(enum ast_lock_type type, const char *filename,
150 int line_num, const char *func, const char *lock_name, void *lock_addr);
153 * \brief Mark the last lock as acquired
155 void ast_mark_lock_acquired(void);
158 * \brief Mark the last lock as failed (trylock)
160 void ast_mark_lock_failed(void);
163 * \brief remove lock info for the current thread
165 * this gets called by ast_mutex_unlock so that information on the lock can
166 * be removed from the current thread's lock info struct.
168 void ast_remove_lock_info(void *lock_addr);
170 static void __attribute__((constructor)) init_empty_mutex(void)
172 memset(&empty_mutex, 0, sizeof(empty_mutex));
175 static inline void ast_reentrancy_lock(ast_mutex_t *p_ast_mutex)
177 pthread_mutex_lock(&p_ast_mutex->reentr_mutex);
180 static inline void ast_reentrancy_unlock(ast_mutex_t *p_ast_mutex)
182 pthread_mutex_unlock(&p_ast_mutex->reentr_mutex);
185 static inline void ast_reentrancy_init(ast_mutex_t *p_ast_mutex)
188 static pthread_mutexattr_t reentr_attr;
190 for (i = 0; i < AST_MAX_REENTRANCY; i++) {
191 p_ast_mutex->file[i] = NULL;
192 p_ast_mutex->lineno[i] = 0;
193 p_ast_mutex->func[i] = NULL;
194 p_ast_mutex->thread[i] = 0;
197 p_ast_mutex->reentrancy = 0;
199 pthread_mutexattr_init(&reentr_attr);
200 pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
201 pthread_mutex_init(&p_ast_mutex->reentr_mutex, &reentr_attr);
202 pthread_mutexattr_destroy(&reentr_attr);
205 static inline void delete_reentrancy_cs(ast_mutex_t * p_ast_mutex)
207 pthread_mutex_destroy(&p_ast_mutex->reentr_mutex);
210 static inline int __ast_pthread_mutex_init(int track, const char *filename, int lineno, const char *func,
211 const char *mutex_name, ast_mutex_t *t)
214 static pthread_mutexattr_t attr;
216 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
218 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
220 int canlog = strcmp(filename, "logger.c") & track;
221 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
222 filename, lineno, func, mutex_name);
228 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
230 ast_reentrancy_init(t);
233 pthread_mutexattr_init(&attr);
234 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
236 res = pthread_mutex_init(&t->mutex, &attr);
237 pthread_mutexattr_destroy(&attr);
241 #define ast_mutex_init(pmutex) __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
242 #define ast_mutex_init_notracking(pmutex) \
243 __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
245 static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
246 const char *mutex_name, ast_mutex_t *t)
249 int canlog = strcmp(filename, "logger.c") & t->track;
251 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
252 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
253 /* Don't try to uninitialize non initialized mutex
254 * This may no effect on linux
255 * And always ganerate core on *BSD with
257 * This not error condition if the mutex created on the fly.
259 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
260 filename, lineno, func, mutex_name);
265 res = pthread_mutex_trylock(&t->mutex);
268 pthread_mutex_unlock(&t->mutex);
271 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
272 filename, lineno, func, mutex_name);
275 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
276 filename, lineno, func, mutex_name);
277 ast_reentrancy_lock(t);
278 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
279 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
280 ast_reentrancy_unlock(t);
284 if ((res = pthread_mutex_destroy(&t->mutex)))
285 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
286 filename, lineno, func, mutex_name, strerror(res));
287 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
289 t->mutex = PTHREAD_MUTEX_INIT_VALUE;
291 ast_reentrancy_lock(t);
292 t->file[0] = filename;
293 t->lineno[0] = lineno;
297 ast_reentrancy_unlock(t);
298 delete_reentrancy_cs(t);
303 static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
304 const char* mutex_name, ast_mutex_t *t)
307 int canlog = strcmp(filename, "logger.c") & t->track;
309 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
310 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
311 /* Don't warn abount uninitialized mutex.
312 * Simple try to initialize it.
313 * May be not needed in linux system.
315 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
316 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
317 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
318 filename, lineno, func, mutex_name);
322 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
325 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
327 #ifdef DETECT_DEADLOCKS
329 time_t seconds = time(NULL);
332 #ifdef HAVE_MTX_PROFILE
333 ast_mark(mtx_prof, 1);
335 res = pthread_mutex_trylock(&t->mutex);
336 #ifdef HAVE_MTX_PROFILE
337 ast_mark(mtx_prof, 0);
340 current = time(NULL);
341 if ((current - seconds) && (!((current - seconds) % 5))) {
342 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
343 filename, lineno, func, (int)(current - seconds), mutex_name);
344 ast_reentrancy_lock(t);
345 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
346 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
347 t->func[t->reentrancy-1], mutex_name);
348 ast_reentrancy_unlock(t);
352 } while (res == EBUSY);
355 #ifdef HAVE_MTX_PROFILE
356 ast_mark(mtx_prof, 1);
357 res = pthread_mutex_trylock(&t->mutex);
358 ast_mark(mtx_prof, 0);
361 res = pthread_mutex_lock(&t->mutex);
362 #endif /* DETECT_DEADLOCKS */
365 ast_reentrancy_lock(t);
366 if (t->reentrancy < AST_MAX_REENTRANCY) {
367 t->file[t->reentrancy] = filename;
368 t->lineno[t->reentrancy] = lineno;
369 t->func[t->reentrancy] = func;
370 t->thread[t->reentrancy] = pthread_self();
373 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
374 filename, lineno, func, mutex_name);
376 ast_reentrancy_unlock(t);
378 ast_mark_lock_acquired();
381 ast_remove_lock_info(&t->mutex);
382 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
383 filename, lineno, func, strerror(res));
390 static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
391 const char* mutex_name, ast_mutex_t *t)
394 int canlog = strcmp(filename, "logger.c") & t->track;
396 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
397 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
398 /* Don't warn abount uninitialized mutex.
399 * Simple try to initialize it.
400 * May be not needed in linux system.
402 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
403 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
404 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
405 filename, lineno, func, mutex_name);
409 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
412 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
414 if (!(res = pthread_mutex_trylock(&t->mutex))) {
415 ast_reentrancy_lock(t);
416 if (t->reentrancy < AST_MAX_REENTRANCY) {
417 t->file[t->reentrancy] = filename;
418 t->lineno[t->reentrancy] = lineno;
419 t->func[t->reentrancy] = func;
420 t->thread[t->reentrancy] = pthread_self();
423 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
424 filename, lineno, func, mutex_name);
426 ast_reentrancy_unlock(t);
428 ast_mark_lock_acquired();
429 } else if (t->track) {
430 ast_mark_lock_failed();
436 static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
437 const char *mutex_name, ast_mutex_t *t)
440 int canlog = strcmp(filename, "logger.c") & t->track;
442 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
443 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
444 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
445 filename, lineno, func, mutex_name);
446 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
447 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
448 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
449 filename, lineno, func, mutex_name);
453 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
455 ast_reentrancy_lock(t);
456 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
457 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
458 filename, lineno, func, mutex_name);
459 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
460 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
464 if (--t->reentrancy < 0) {
465 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
466 filename, lineno, func, mutex_name);
470 if (t->reentrancy < AST_MAX_REENTRANCY) {
471 t->file[t->reentrancy] = NULL;
472 t->lineno[t->reentrancy] = 0;
473 t->func[t->reentrancy] = NULL;
474 t->thread[t->reentrancy] = 0;
476 ast_reentrancy_unlock(t);
479 ast_remove_lock_info(&t->mutex);
481 if ((res = pthread_mutex_unlock(&t->mutex))) {
482 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
483 filename, lineno, func, strerror(res));
490 static inline int __ast_cond_init(const char *filename, int lineno, const char *func,
491 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
493 return pthread_cond_init(cond, cond_attr);
496 static inline int __ast_cond_signal(const char *filename, int lineno, const char *func,
497 const char *cond_name, ast_cond_t *cond)
499 return pthread_cond_signal(cond);
502 static inline int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
503 const char *cond_name, ast_cond_t *cond)
505 return pthread_cond_broadcast(cond);
508 static inline int __ast_cond_destroy(const char *filename, int lineno, const char *func,
509 const char *cond_name, ast_cond_t *cond)
511 return pthread_cond_destroy(cond);
514 static inline int __ast_cond_wait(const char *filename, int lineno, const char *func,
515 const char *cond_name, const char *mutex_name,
516 ast_cond_t *cond, ast_mutex_t *t)
519 int canlog = strcmp(filename, "logger.c") & t->track;
521 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
522 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
523 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
524 filename, lineno, func, mutex_name);
525 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
526 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
527 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
528 filename, lineno, func, mutex_name);
532 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
534 ast_reentrancy_lock(t);
535 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
536 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
537 filename, lineno, func, mutex_name);
538 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
539 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
543 if (--t->reentrancy < 0) {
544 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
545 filename, lineno, func, mutex_name);
549 if (t->reentrancy < AST_MAX_REENTRANCY) {
550 t->file[t->reentrancy] = NULL;
551 t->lineno[t->reentrancy] = 0;
552 t->func[t->reentrancy] = NULL;
553 t->thread[t->reentrancy] = 0;
555 ast_reentrancy_unlock(t);
558 ast_remove_lock_info(&t->mutex);
560 if ((res = pthread_cond_wait(cond, &t->mutex))) {
561 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
562 filename, lineno, func, strerror(res));
565 ast_reentrancy_lock(t);
566 if (t->reentrancy < AST_MAX_REENTRANCY) {
567 t->file[t->reentrancy] = filename;
568 t->lineno[t->reentrancy] = lineno;
569 t->func[t->reentrancy] = func;
570 t->thread[t->reentrancy] = pthread_self();
573 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
574 filename, lineno, func, mutex_name);
576 ast_reentrancy_unlock(t);
579 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
585 static inline int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
586 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
587 ast_mutex_t *t, const struct timespec *abstime)
590 int canlog = strcmp(filename, "logger.c") & t->track;
592 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
593 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
594 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
595 filename, lineno, func, mutex_name);
596 res = __ast_pthread_mutex_init(t->track, filename, lineno, func, mutex_name, t);
597 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
598 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
599 filename, lineno, func, mutex_name);
603 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
605 ast_reentrancy_lock(t);
606 if (t->reentrancy && (t->thread[t->reentrancy-1] != pthread_self())) {
607 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
608 filename, lineno, func, mutex_name);
609 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
610 t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name);
614 if (--t->reentrancy < 0) {
615 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
616 filename, lineno, func, mutex_name);
620 if (t->reentrancy < AST_MAX_REENTRANCY) {
621 t->file[t->reentrancy] = NULL;
622 t->lineno[t->reentrancy] = 0;
623 t->func[t->reentrancy] = NULL;
624 t->thread[t->reentrancy] = 0;
626 ast_reentrancy_unlock(t);
629 ast_remove_lock_info(&t->mutex);
631 if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
632 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
633 filename, lineno, func, strerror(res));
636 ast_reentrancy_lock(t);
637 if (t->reentrancy < AST_MAX_REENTRANCY) {
638 t->file[t->reentrancy] = filename;
639 t->lineno[t->reentrancy] = lineno;
640 t->func[t->reentrancy] = func;
641 t->thread[t->reentrancy] = pthread_self();
644 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
645 filename, lineno, func, mutex_name);
647 ast_reentrancy_unlock(t);
650 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
656 #define ast_mutex_destroy(a) __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
657 #define ast_mutex_lock(a) __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
658 #define ast_mutex_unlock(a) __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
659 #define ast_mutex_trylock(a) __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
660 #define ast_cond_init(cond, attr) __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
661 #define ast_cond_destroy(cond) __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
662 #define ast_cond_signal(cond) __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
663 #define ast_cond_broadcast(cond) __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
664 #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
665 #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
667 #else /* !DEBUG_THREADS */
670 typedef pthread_mutex_t ast_mutex_t;
672 #define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
673 #define AST_MUTEX_INIT_VALUE_NOTRACKING ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE)
675 #define ast_mutex_init_notracking(m) ast_mutex_init(m)
677 static inline int ast_mutex_init(ast_mutex_t *pmutex)
680 pthread_mutexattr_t attr;
682 pthread_mutexattr_init(&attr);
683 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
685 res = pthread_mutex_init(pmutex, &attr);
686 pthread_mutexattr_destroy(&attr);
690 #define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a)
692 static inline int ast_mutex_unlock(ast_mutex_t *pmutex)
694 return pthread_mutex_unlock(pmutex);
697 static inline int ast_mutex_destroy(ast_mutex_t *pmutex)
699 return pthread_mutex_destroy(pmutex);
702 static inline int ast_mutex_lock(ast_mutex_t *pmutex)
707 static inline int ast_mutex_trylock(ast_mutex_t *pmutex)
709 return pthread_mutex_trylock(pmutex);
712 typedef pthread_cond_t ast_cond_t;
714 static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr)
716 return pthread_cond_init(cond, cond_attr);
719 static inline int ast_cond_signal(ast_cond_t *cond)
721 return pthread_cond_signal(cond);
724 static inline int ast_cond_broadcast(ast_cond_t *cond)
726 return pthread_cond_broadcast(cond);
729 static inline int ast_cond_destroy(ast_cond_t *cond)
731 return pthread_cond_destroy(cond);
734 static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t)
736 return pthread_cond_wait(cond, t);
739 static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
741 return pthread_cond_timedwait(cond, t, abstime);
744 #endif /* !DEBUG_THREADS */
746 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
748 * If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope constructors
749 * and destructors to create/destroy global mutexes.
751 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
752 scope ast_mutex_t mutex = init_val; \
753 static void __attribute__ ((constructor)) init_##mutex(void) \
756 ast_mutex_init(&mutex); \
758 ast_mutex_init_notracking(&mutex); \
761 static void __attribute__ ((destructor)) fini_##mutex(void) \
763 ast_mutex_destroy(&mutex); \
765 #else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
766 /* By default, use static initialization of mutexes. */
767 #define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) scope ast_mutex_t mutex = init_val
768 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
770 #ifndef __CYGWIN__ /* temporary disabled for cygwin */
771 #define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
772 #define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
774 #define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
775 #define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
776 #define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
777 #define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
778 #define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
779 #define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
780 #define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
781 #define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
782 #define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
783 #define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
784 #define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
786 #define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
787 #define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
789 #define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
791 #define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
794 #define pthread_create __use_ast_pthread_create_instead__
798 * Same as above, definitions of ast_rwlock_t for the various cases:
799 * simple wrappers for the pthread equivalent in the non-debug case,
800 * more sophisticated tracking in the debug case.
803 typedef pthread_rwlock_t ast_rwlock_t;
805 #ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER
806 #define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER
808 #define AST_RWLOCK_INIT_VALUE { 0 }
813 #define ast_rwlock_init(rwlock) __ast_rwlock_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
814 #define ast_rwlock_destroy(rwlock) __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
815 #define ast_rwlock_unlock(a) _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
816 #define ast_rwlock_rdlock(a) _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
817 #define ast_rwlock_wrlock(a) _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
818 #define ast_rwlock_tryrdlock(a) _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
819 #define ast_rwlock_trywrlock(a) _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
822 static inline int __ast_rwlock_init(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
825 pthread_rwlockattr_t attr;
826 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
827 int canlog = strcmp(filename, "logger.c");
829 if (*prwlock != ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
830 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
831 filename, lineno, func, rwlock_name);
834 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
835 pthread_rwlockattr_init(&attr);
837 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
838 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
841 res = pthread_rwlock_init(prwlock, &attr);
842 pthread_rwlockattr_destroy(&attr);
847 static inline int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
850 int canlog = strcmp(filename, "logger.c");
852 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
853 if (*prwlock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
854 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
855 filename, lineno, func, rwlock_name);
858 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
860 if ((res = pthread_rwlock_destroy(prwlock)))
861 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
862 filename, lineno, func, rwlock_name, strerror(res));
868 static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name,
869 const char *file, int line, const char *func)
872 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
873 int canlog = strcmp(file, "logger.c");
875 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
876 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
877 file, line, func, name);
878 res = __ast_rwlock_init(file, line, func, name, lock);
879 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
880 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
881 file, line, func, name);
885 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
887 res = pthread_rwlock_unlock(lock);
888 ast_remove_lock_info(lock);
893 static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name,
894 const char *file, int line, const char *func)
897 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
898 int canlog = strcmp(file, "logger.c");
900 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
901 /* Don't warn abount uninitialized lock.
902 * Simple try to initialize it.
903 * May be not needed in linux system.
905 res = __ast_rwlock_init(file, line, func, name, lock);
906 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
907 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
908 file, line, func, name);
912 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
914 ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
915 res = pthread_rwlock_rdlock(lock);
917 ast_mark_lock_acquired();
919 ast_remove_lock_info(lock);
924 static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name,
925 const char *file, int line, const char *func)
928 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
929 int canlog = strcmp(file, "logger.c");
931 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
932 /* Don't warn abount uninitialized lock.
933 * Simple try to initialize it.
934 * May be not needed in linux system.
936 res = __ast_rwlock_init(file, line, func, name, lock);
937 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
938 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
939 file, line, func, name);
943 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
945 ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
946 res = pthread_rwlock_wrlock(lock);
948 ast_mark_lock_acquired();
950 ast_remove_lock_info(lock);
955 static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name,
956 const char *file, int line, const char *func)
959 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
960 int canlog = strcmp(file, "logger.c");
962 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
963 /* Don't warn abount uninitialized lock.
964 * Simple try to initialize it.
965 * May be not needed in linux system.
967 res = __ast_rwlock_init(file, line, func, name, lock);
968 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
969 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
970 file, line, func, name);
974 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
976 ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
977 res = pthread_rwlock_tryrdlock(lock);
979 ast_mark_lock_acquired();
981 ast_remove_lock_info(lock);
986 static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name,
987 const char *file, int line, const char *func)
990 #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
991 int canlog = strcmp(file, "logger.c");
993 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
994 /* Don't warn abount uninitialized lock.
995 * Simple try to initialize it.
996 * May be not needed in linux system.
998 res = __ast_rwlock_init(file, line, func, name, lock);
999 if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
1000 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1001 file, line, func, name);
1005 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1007 ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
1008 res = pthread_rwlock_trywrlock(lock);
1010 ast_mark_lock_acquired();
1012 ast_remove_lock_info(lock);
1016 #else /* !DEBUG_THREADS */
1018 static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
1021 pthread_rwlockattr_t attr;
1023 pthread_rwlockattr_init(&attr);
1025 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
1026 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
1029 res = pthread_rwlock_init(prwlock, &attr);
1030 pthread_rwlockattr_destroy(&attr);
1034 static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
1036 return pthread_rwlock_destroy(prwlock);
1039 static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
1041 return pthread_rwlock_unlock(prwlock);
1044 static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
1046 return pthread_rwlock_rdlock(prwlock);
1049 static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
1051 return pthread_rwlock_tryrdlock(prwlock);
1054 static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
1056 return pthread_rwlock_wrlock(prwlock);
1059 static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
1061 return pthread_rwlock_trywrlock(prwlock);
1063 #endif /* !DEBUG_THREADS */
1065 /* Statically declared read/write locks */
1067 #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
1068 #define __AST_RWLOCK_DEFINE(scope, rwlock) \
1069 scope ast_rwlock_t rwlock; \
1070 static void __attribute__ ((constructor)) init_##rwlock(void) \
1072 ast_rwlock_init(&rwlock); \
1075 static void __attribute__ ((destructor)) fini_##rwlock(void) \
1077 ast_rwlock_destroy(&rwlock); \
1080 #define __AST_RWLOCK_DEFINE(scope, rwlock) scope ast_rwlock_t rwlock = AST_RWLOCK_INIT_VALUE
1083 #define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock)
1086 * Support for atomic instructions.
1087 * For platforms that have it, use the native cpu instruction to
1088 * implement them. For other platforms, resort to a 'slow' version
1089 * (defined in utils.c) that protects the atomic instruction with
1091 * The slow versions is always available, for testing purposes,
1092 * as ast_atomic_fetchadd_int_slow()
1095 int ast_atomic_fetchadd_int_slow(volatile int *p, int v);
1097 #include "asterisk/inline_api.h"
1099 #if defined(HAVE_OSX_ATOMICS)
1100 #include "libkern/OSAtomic.h"
1103 /*! \brief Atomically add v to *p and return * the previous value of *p.
1104 * This can be used to handle reference counts, and the return value
1105 * can be used to generate unique identifiers.
1108 #if defined(HAVE_GCC_ATOMICS)
1109 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1111 return __sync_fetch_and_add(p, v);
1113 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
1114 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1116 return OSAtomicAdd32(v, (int32_t *) p);
1118 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
1119 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1121 return OSAtomicAdd64(v, (int64_t *) p);
1122 #elif defined (__i386__) || defined(__x86_64__)
1124 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1127 " lock; xaddl %0, %1 ; "
1128 : "+r" (v), /* 0 (result) */
1130 : "m" (*p)); /* 2 */
1133 #else /* ifndef sun */
1134 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1137 " lock xaddl %0, %1 ; "
1138 : "+r" (v), /* 0 (result) */
1140 : "m" (*p)); /* 2 */
1144 #else /* low performance version in utils.c */
1145 AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
1147 return ast_atomic_fetchadd_int_slow(p, v);
1151 /*! \brief decrement *p by 1 and return true if the variable has reached 0.
1152 * Useful e.g. to check if a refcount has reached 0.
1154 #if defined(HAVE_GCC_ATOMICS)
1155 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1157 return __sync_sub_and_fetch(p, 1) == 0;
1159 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 4)
1160 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1162 return OSAtomicAdd32( -1, (int32_t *) p) == 0;
1164 #elif defined(HAVE_OSX_ATOMICS) && (SIZEOF_INT == 8)
1165 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1167 return OSAtomicAdd64( -1, (int64_t *) p) == 0;
1169 AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
1171 int a = ast_atomic_fetchadd_int(p, -1);
1172 return a == 1; /* true if the value is 0 now (so it was 1 previously) */
1176 #ifndef DEBUG_CHANNEL_LOCKS
1177 /*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined
1178 in the Makefile, print relevant output for debugging */
1179 #define ast_channel_lock(x) ast_mutex_lock(&x->lock_dont_use)
1180 /*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined
1181 in the Makefile, print relevant output for debugging */
1182 #define ast_channel_unlock(x) ast_mutex_unlock(&x->lock_dont_use)
1183 /*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined
1184 in the Makefile, print relevant output for debugging */
1185 #define ast_channel_trylock(x) ast_mutex_trylock(&x->lock_dont_use)
1188 /*! \brief Lock AST channel (and print debugging output)
1189 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
1190 int ast_channel_lock(struct ast_channel *chan);
1192 /*! \brief Unlock AST channel (and print debugging output)
1193 \note You need to enable DEBUG_CHANNEL_LOCKS for this function
1195 int ast_channel_unlock(struct ast_channel *chan);
1197 /*! \brief Lock AST channel (and print debugging output)
1198 \note You need to enable DEBUG_CHANNEL_LOCKS for this function */
1199 int ast_channel_trylock(struct ast_channel *chan);
1202 #endif /* _ASTERISK_LOCK_H */