2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2010, 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.
21 * \brief General Asterisk locking.
25 <support_level>core</support_level>
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32 #include "asterisk/utils.h"
33 #include "asterisk/lock.h"
35 /* Allow direct use of pthread_mutex_* / pthread_cond_* */
36 #undef pthread_mutex_init
37 #undef pthread_mutex_destroy
38 #undef pthread_mutex_lock
39 #undef pthread_mutex_trylock
40 #undef pthread_mutex_t
41 #undef pthread_mutex_unlock
42 #undef pthread_cond_init
43 #undef pthread_cond_signal
44 #undef pthread_cond_broadcast
45 #undef pthread_cond_destroy
46 #undef pthread_cond_wait
47 #undef pthread_cond_timedwait
49 #if defined(DEBUG_THREADS) && defined(HAVE_BKTR)
50 static void __dump_backtrace(struct ast_bt *bt, int canlog)
55 strings = backtrace_symbols(bt->addresses, bt->num_frames);
57 for (i = 0; i < bt->num_frames; i++) {
58 __ast_mutex_logger("%s\n", strings[i]);
61 ast_std_free(strings);
63 #endif /* defined(DEBUG_THREADS) && defined(HAVE_BKTR) */
65 int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func,
66 const char *mutex_name, ast_mutex_t *t)
69 pthread_mutexattr_t attr;
73 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
74 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
76 int canlog = strcmp(filename, "logger.c") & track;
77 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
78 filename, lineno, func, mutex_name);
84 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
86 if ((t->tracking = tracking)) {
87 ast_reentrancy_init(&t->track);
89 #endif /* DEBUG_THREADS */
91 pthread_mutexattr_init(&attr);
92 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
94 res = pthread_mutex_init(&t->mutex, &attr);
95 pthread_mutexattr_destroy(&attr);
99 int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
100 const char *mutex_name, ast_mutex_t *t)
105 struct ast_lock_track *lt;
106 int canlog = strcmp(filename, "logger.c") & t->tracking;
108 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
109 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
110 /* Don't try to uninitialize non initialized mutex
111 * This may no effect on linux
112 * And always ganerate core on *BSD with
114 * This not error condition if the mutex created on the fly.
116 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
117 filename, lineno, func, mutex_name);
122 if (t->tracking && !t->track) {
123 ast_reentrancy_init(&t->track);
127 res = pthread_mutex_trylock(&t->mutex);
130 pthread_mutex_unlock(&t->mutex);
133 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
134 filename, lineno, func, mutex_name);
137 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
138 filename, lineno, func, mutex_name);
140 ast_reentrancy_lock(lt);
141 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
142 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
144 __dump_backtrace(<->backtrace[ROFFSET], canlog);
146 ast_reentrancy_unlock(lt);
150 #endif /* DEBUG_THREADS */
152 res = pthread_mutex_destroy(&t->mutex);
156 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
157 filename, lineno, func, mutex_name, strerror(res));
160 ast_reentrancy_lock(lt);
161 lt->file[0] = filename;
162 lt->lineno[0] = lineno;
167 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
169 ast_reentrancy_unlock(lt);
170 delete_reentrancy_cs(&t->track);
172 #endif /* DEBUG_THREADS */
177 int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
178 const char* mutex_name, ast_mutex_t *t)
183 struct ast_lock_track *lt;
184 int canlog = strcmp(filename, "logger.c") & t->tracking;
186 struct ast_bt *bt = NULL;
189 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
190 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
191 /* Don't warn abount uninitialized mutex.
192 * Simple try to initialize it.
193 * May be not needed in linux system.
195 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
196 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
197 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
198 filename, lineno, func, mutex_name);
202 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
204 if (t->tracking && !t->track) {
205 ast_reentrancy_init(&t->track);
213 /* The implementation of backtrace() may have its own locks.
214 * Capture the backtrace outside of the reentrancy lock to
215 * avoid deadlocks. See ASTERISK-22455. */
216 ast_bt_get_addresses(&tmp);
218 ast_reentrancy_lock(lt);
219 if (lt->reentrancy != AST_MAX_REENTRANCY) {
220 lt->backtrace[lt->reentrancy] = tmp;
221 bt = <->backtrace[lt->reentrancy];
223 ast_reentrancy_unlock(lt);
225 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
227 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
230 #endif /* DEBUG_THREADS */
232 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
234 time_t seconds = time(NULL);
235 time_t wait_time, reported_wait = 0;
237 #ifdef HAVE_MTX_PROFILE
238 ast_mark(mtx_prof, 1);
240 res = pthread_mutex_trylock(&t->mutex);
241 #ifdef HAVE_MTX_PROFILE
242 ast_mark(mtx_prof, 0);
245 wait_time = time(NULL) - seconds;
246 if (wait_time > reported_wait && (wait_time % 5) == 0) {
247 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
248 filename, lineno, func, (int) wait_time, mutex_name);
249 ast_reentrancy_lock(lt);
251 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
253 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
254 lt->file[ROFFSET], lt->lineno[ROFFSET],
255 lt->func[ROFFSET], mutex_name);
257 __dump_backtrace(<->backtrace[ROFFSET], canlog);
259 ast_reentrancy_unlock(lt);
260 reported_wait = wait_time;
264 } while (res == EBUSY);
266 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
267 #ifdef HAVE_MTX_PROFILE
268 ast_mark(mtx_prof, 1);
269 res = pthread_mutex_trylock(&t->mutex);
270 ast_mark(mtx_prof, 0);
273 res = pthread_mutex_lock(&t->mutex);
274 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
277 if (t->tracking && !res) {
278 ast_reentrancy_lock(lt);
279 if (lt->reentrancy < AST_MAX_REENTRANCY) {
280 lt->file[lt->reentrancy] = filename;
281 lt->lineno[lt->reentrancy] = lineno;
282 lt->func[lt->reentrancy] = func;
283 lt->thread[lt->reentrancy] = pthread_self();
286 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
287 filename, lineno, func, mutex_name);
289 ast_reentrancy_unlock(lt);
291 ast_mark_lock_acquired(t);
293 } else if (t->tracking) {
295 if (lt->reentrancy) {
296 ast_reentrancy_lock(lt);
297 bt = <->backtrace[lt->reentrancy-1];
298 ast_reentrancy_unlock(lt);
302 ast_remove_lock_info(t, bt);
304 ast_remove_lock_info(t);
308 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
309 filename, lineno, func, strerror(res));
312 #endif /* DEBUG_THREADS */
317 int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
318 const char* mutex_name, ast_mutex_t *t)
323 struct ast_lock_track *lt;
324 int canlog = strcmp(filename, "logger.c") & t->tracking;
326 struct ast_bt *bt = NULL;
329 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
330 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
331 /* Don't warn abount uninitialized mutex.
332 * Simple try to initialize it.
333 * May be not needed in linux system.
335 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
336 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
337 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
338 filename, lineno, func, mutex_name);
342 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
344 if (t->tracking && !t->track) {
345 ast_reentrancy_init(&t->track);
353 /* The implementation of backtrace() may have its own locks.
354 * Capture the backtrace outside of the reentrancy lock to
355 * avoid deadlocks. See ASTERISK-22455. */
356 ast_bt_get_addresses(&tmp);
358 ast_reentrancy_lock(lt);
359 if (lt->reentrancy != AST_MAX_REENTRANCY) {
360 lt->backtrace[lt->reentrancy] = tmp;
361 bt = <->backtrace[lt->reentrancy];
363 ast_reentrancy_unlock(lt);
365 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
367 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
370 #endif /* DEBUG_THREADS */
372 res = pthread_mutex_trylock(&t->mutex);
375 if (t->tracking && !res) {
376 ast_reentrancy_lock(lt);
377 if (lt->reentrancy < AST_MAX_REENTRANCY) {
378 lt->file[lt->reentrancy] = filename;
379 lt->lineno[lt->reentrancy] = lineno;
380 lt->func[lt->reentrancy] = func;
381 lt->thread[lt->reentrancy] = pthread_self();
384 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
385 filename, lineno, func, mutex_name);
387 ast_reentrancy_unlock(lt);
389 ast_mark_lock_acquired(t);
391 } else if (t->tracking) {
392 ast_mark_lock_failed(t);
394 #endif /* DEBUG_THREADS */
399 int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
400 const char *mutex_name, ast_mutex_t *t)
405 struct ast_lock_track *lt;
406 int canlog = strcmp(filename, "logger.c") & t->tracking;
408 struct ast_bt *bt = NULL;
411 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
412 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
413 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
414 filename, lineno, func, mutex_name);
415 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
416 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
417 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
418 filename, lineno, func, mutex_name);
422 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
424 if (t->tracking && !t->track) {
425 ast_reentrancy_init(&t->track);
430 ast_reentrancy_lock(lt);
431 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
432 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
433 filename, lineno, func, mutex_name);
434 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
435 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
437 __dump_backtrace(<->backtrace[ROFFSET], canlog);
442 if (--lt->reentrancy < 0) {
443 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
444 filename, lineno, func, mutex_name);
448 if (lt->reentrancy < AST_MAX_REENTRANCY) {
449 lt->file[lt->reentrancy] = NULL;
450 lt->lineno[lt->reentrancy] = 0;
451 lt->func[lt->reentrancy] = NULL;
452 lt->thread[lt->reentrancy] = 0;
456 if (lt->reentrancy) {
457 bt = <->backtrace[lt->reentrancy - 1];
460 ast_reentrancy_unlock(lt);
463 ast_remove_lock_info(t, bt);
465 ast_remove_lock_info(t);
468 #endif /* DEBUG_THREADS */
470 res = pthread_mutex_unlock(&t->mutex);
474 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
475 filename, lineno, func, strerror(res));
478 #endif /* DEBUG_THREADS */
484 int __ast_cond_init(const char *filename, int lineno, const char *func,
485 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
487 return pthread_cond_init(cond, cond_attr);
490 int __ast_cond_signal(const char *filename, int lineno, const char *func,
491 const char *cond_name, ast_cond_t *cond)
493 return pthread_cond_signal(cond);
496 int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
497 const char *cond_name, ast_cond_t *cond)
499 return pthread_cond_broadcast(cond);
502 int __ast_cond_destroy(const char *filename, int lineno, const char *func,
503 const char *cond_name, ast_cond_t *cond)
505 return pthread_cond_destroy(cond);
508 int __ast_cond_wait(const char *filename, int lineno, const char *func,
509 const char *cond_name, const char *mutex_name,
510 ast_cond_t *cond, ast_mutex_t *t)
515 struct ast_lock_track *lt;
516 struct ast_lock_track lt_orig;
517 int canlog = strcmp(filename, "logger.c") & t->tracking;
519 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
520 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
521 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
522 filename, lineno, func, mutex_name);
523 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
524 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
525 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
526 filename, lineno, func, mutex_name);
530 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
532 if (t->tracking && !t->track) {
533 ast_reentrancy_init(&t->track);
538 ast_reentrancy_lock(lt);
539 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
540 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
541 filename, lineno, func, mutex_name);
542 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
543 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
545 __dump_backtrace(<->backtrace[ROFFSET], canlog);
548 } else if (lt->reentrancy <= 0) {
549 __ast_mutex_logger("%s line %d (%s): attempted to wait on an unlocked mutex '%s'\n",
550 filename, lineno, func, mutex_name);
554 /* Waiting on a condition completely suspends a recursive mutex,
555 * even if it's been recursively locked multiple times. Make a
556 * copy of the lock tracking, and reset reentrancy to zero */
559 ast_reentrancy_unlock(lt);
561 ast_suspend_lock_info(t);
563 #endif /* DEBUG_THREADS */
565 res = pthread_cond_wait(cond, &t->mutex);
569 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
570 filename, lineno, func, strerror(res));
572 } else if (t->tracking) {
573 pthread_mutex_t reentr_mutex_orig;
574 ast_reentrancy_lock(lt);
575 /* Restore lock tracking to what it was prior to the wait */
576 reentr_mutex_orig = lt->reentr_mutex;
578 /* un-trash the mutex we just copied over */
579 lt->reentr_mutex = reentr_mutex_orig;
580 ast_reentrancy_unlock(lt);
582 ast_restore_lock_info(t);
584 #endif /* DEBUG_THREADS */
589 int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
590 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
591 ast_mutex_t *t, const struct timespec *abstime)
596 struct ast_lock_track *lt;
597 struct ast_lock_track lt_orig;
598 int canlog = strcmp(filename, "logger.c") & t->tracking;
600 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
601 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
602 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
603 filename, lineno, func, mutex_name);
604 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
605 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
606 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
607 filename, lineno, func, mutex_name);
611 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
613 if (t->tracking && !t->track) {
614 ast_reentrancy_init(&t->track);
619 ast_reentrancy_lock(lt);
620 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
621 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
622 filename, lineno, func, mutex_name);
623 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
624 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
626 __dump_backtrace(<->backtrace[ROFFSET], canlog);
629 } else if (lt->reentrancy <= 0) {
630 __ast_mutex_logger("%s line %d (%s): attempted to wait on an unlocked mutex '%s'\n",
631 filename, lineno, func, mutex_name);
635 /* Waiting on a condition completely suspends a recursive mutex,
636 * even if it's been recursively locked multiple times. Make a
637 * copy of the lock tracking, and reset reentrancy to zero */
640 ast_reentrancy_unlock(lt);
642 ast_suspend_lock_info(t);
644 #endif /* DEBUG_THREADS */
646 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
649 if (res && (res != ETIMEDOUT)) {
650 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
651 filename, lineno, func, strerror(res));
653 } else if (t->tracking) {
654 pthread_mutex_t reentr_mutex_orig;
655 ast_reentrancy_lock(lt);
656 /* Restore lock tracking to what it was prior to the wait */
657 reentr_mutex_orig = lt->reentr_mutex;
659 /* un-trash the mutex we just copied over */
660 lt->reentr_mutex = reentr_mutex_orig;
661 ast_reentrancy_unlock(lt);
663 ast_suspend_lock_info(t);
665 #endif /* DEBUG_THREADS */
670 int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
673 pthread_rwlockattr_t attr;
677 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
678 int canlog = strcmp(filename, "logger.c") & t->tracking;
680 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
681 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
682 filename, lineno, func, rwlock_name);
685 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
687 if ((t->tracking = tracking)) {
688 ast_reentrancy_init(&t->track);
690 #endif /* DEBUG_THREADS */
692 pthread_rwlockattr_init(&attr);
694 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
695 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
698 res = pthread_rwlock_init(&t->lock, &attr);
699 pthread_rwlockattr_destroy(&attr);
703 int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
708 struct ast_lock_track *lt = t->track;
709 int canlog = strcmp(filename, "logger.c") & t->tracking;
711 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
712 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
713 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
714 filename, lineno, func, rwlock_name);
717 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
719 #endif /* DEBUG_THREADS */
721 res = pthread_rwlock_destroy(&t->lock);
725 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
726 filename, lineno, func, rwlock_name, strerror(res));
728 if (t->tracking && lt) {
729 ast_reentrancy_lock(lt);
730 lt->file[0] = filename;
731 lt->lineno[0] = lineno;
736 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
738 ast_reentrancy_unlock(lt);
739 delete_reentrancy_cs(&t->track);
741 #endif /* DEBUG_THREADS */
746 int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
751 struct ast_lock_track *lt;
752 int canlog = strcmp(filename, "logger.c") & t->tracking;
754 struct ast_bt *bt = NULL;
759 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
760 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
761 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
762 filename, line, func, name);
763 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
764 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
765 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
766 filename, line, func, name);
770 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
772 if (t->tracking && !t->track) {
773 ast_reentrancy_init(&t->track);
778 ast_reentrancy_lock(lt);
779 if (lt->reentrancy) {
781 pthread_t self = pthread_self();
782 for (i = lt->reentrancy - 1; i >= 0; --i) {
783 if (lt->thread[i] == self) {
785 if (i != lt->reentrancy - 1) {
786 lt->file[i] = lt->file[lt->reentrancy - 1];
787 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
788 lt->func[i] = lt->func[lt->reentrancy - 1];
789 lt->thread[i] = lt->thread[lt->reentrancy - 1];
792 bt = <->backtrace[i];
794 lt->file[lt->reentrancy - 1] = NULL;
795 lt->lineno[lt->reentrancy - 1] = 0;
796 lt->func[lt->reentrancy - 1] = NULL;
797 lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
803 if (lock_found && --lt->reentrancy < 0) {
804 __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
805 filename, line, func, name);
809 ast_reentrancy_unlock(lt);
812 ast_remove_lock_info(t, bt);
814 ast_remove_lock_info(t);
817 #endif /* DEBUG_THREADS */
819 res = pthread_rwlock_unlock(&t->lock);
823 __ast_mutex_logger("%s line %d (%s): Error releasing rwlock: %s\n",
824 filename, line, func, strerror(res));
827 #endif /* DEBUG_THREADS */
832 int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
837 struct ast_lock_track *lt;
838 int canlog = strcmp(filename, "logger.c") & t->tracking;
840 struct ast_bt *bt = NULL;
843 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
844 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
845 /* Don't warn abount uninitialized lock.
846 * Simple try to initialize it.
847 * May be not needed in linux system.
849 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
850 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
851 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
852 filename, line, func, name);
856 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
858 if (t->tracking && !t->track) {
859 ast_reentrancy_init(&t->track);
867 /* The implementation of backtrace() may have its own locks.
868 * Capture the backtrace outside of the reentrancy lock to
869 * avoid deadlocks. See ASTERISK-22455. */
870 ast_bt_get_addresses(&tmp);
872 ast_reentrancy_lock(lt);
873 if (lt->reentrancy != AST_MAX_REENTRANCY) {
874 lt->backtrace[lt->reentrancy] = tmp;
875 bt = <->backtrace[lt->reentrancy];
877 ast_reentrancy_unlock(lt);
879 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
881 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
884 #endif /* DEBUG_THREADS */
886 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
888 time_t seconds = time(NULL);
889 time_t wait_time, reported_wait = 0;
891 res = pthread_rwlock_tryrdlock(&t->lock);
893 wait_time = time(NULL) - seconds;
894 if (wait_time > reported_wait && (wait_time % 5) == 0) {
895 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
896 filename, line, func, (int)wait_time, name);
898 ast_reentrancy_lock(lt);
900 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
902 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
903 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
904 lt->func[lt->reentrancy-1], name);
906 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
908 ast_reentrancy_unlock(lt);
910 reported_wait = wait_time;
914 } while (res == EBUSY);
916 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
917 res = pthread_rwlock_rdlock(&t->lock);
918 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
921 if (!res && t->tracking) {
922 ast_reentrancy_lock(lt);
923 if (lt->reentrancy < AST_MAX_REENTRANCY) {
924 lt->file[lt->reentrancy] = filename;
925 lt->lineno[lt->reentrancy] = line;
926 lt->func[lt->reentrancy] = func;
927 lt->thread[lt->reentrancy] = pthread_self();
930 ast_reentrancy_unlock(lt);
932 ast_mark_lock_acquired(t);
934 } else if (t->tracking) {
936 if (lt->reentrancy) {
937 ast_reentrancy_lock(lt);
938 bt = <->backtrace[lt->reentrancy-1];
939 ast_reentrancy_unlock(lt);
943 ast_remove_lock_info(t, bt);
945 ast_remove_lock_info(t);
950 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
951 filename, line, func, strerror(res));
954 #endif /* DEBUG_THREADS */
959 int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
964 struct ast_lock_track *lt;
965 int canlog = strcmp(filename, "logger.c") & t->tracking;
967 struct ast_bt *bt = NULL;
970 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
971 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
972 /* Don't warn abount uninitialized lock.
973 * Simple try to initialize it.
974 * May be not needed in linux system.
976 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
977 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
978 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
979 filename, line, func, name);
983 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
985 if (t->tracking && !t->track) {
986 ast_reentrancy_init(&t->track);
994 /* The implementation of backtrace() may have its own locks.
995 * Capture the backtrace outside of the reentrancy lock to
996 * avoid deadlocks. See ASTERISK-22455. */
997 ast_bt_get_addresses(&tmp);
999 ast_reentrancy_lock(lt);
1000 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1001 lt->backtrace[lt->reentrancy] = tmp;
1002 bt = <->backtrace[lt->reentrancy];
1004 ast_reentrancy_unlock(lt);
1006 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1008 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1011 #endif /* DEBUG_THREADS */
1013 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
1015 time_t seconds = time(NULL);
1016 time_t wait_time, reported_wait = 0;
1018 res = pthread_rwlock_trywrlock(&t->lock);
1020 wait_time = time(NULL) - seconds;
1021 if (wait_time > reported_wait && (wait_time % 5) == 0) {
1022 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
1023 filename, line, func, (int)wait_time, name);
1025 ast_reentrancy_lock(lt);
1027 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
1029 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
1030 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1031 lt->func[lt->reentrancy-1], name);
1033 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
1035 ast_reentrancy_unlock(lt);
1037 reported_wait = wait_time;
1041 } while (res == EBUSY);
1043 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1044 res = pthread_rwlock_wrlock(&t->lock);
1045 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1047 #ifdef DEBUG_THREADS
1048 if (!res && t->tracking) {
1049 ast_reentrancy_lock(lt);
1050 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1051 lt->file[lt->reentrancy] = filename;
1052 lt->lineno[lt->reentrancy] = line;
1053 lt->func[lt->reentrancy] = func;
1054 lt->thread[lt->reentrancy] = pthread_self();
1057 ast_reentrancy_unlock(lt);
1059 ast_mark_lock_acquired(t);
1061 } else if (t->tracking) {
1063 if (lt->reentrancy) {
1064 ast_reentrancy_lock(lt);
1065 bt = <->backtrace[lt->reentrancy-1];
1066 ast_reentrancy_unlock(lt);
1071 ast_remove_lock_info(t, bt);
1075 ast_remove_lock_info(t);
1080 __ast_mutex_logger("%s line %d (%s): Error obtaining write lock: %s\n",
1081 filename, line, func, strerror(res));
1084 #endif /* DEBUG_THREADS */
1089 int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1090 const struct timespec *abs_timeout)
1094 #ifdef DEBUG_THREADS
1095 struct ast_lock_track *lt;
1096 int canlog = strcmp(filename, "logger.c") & t->tracking;
1098 struct ast_bt *bt = NULL;
1101 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1102 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1103 /* Don't warn abount uninitialized lock.
1104 * Simple try to initialize it.
1105 * May be not needed in linux system.
1107 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1108 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1109 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1110 filename, line, func, name);
1114 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1116 if (t->tracking && !t->track) {
1117 ast_reentrancy_init(&t->track);
1125 /* The implementation of backtrace() may have its own locks.
1126 * Capture the backtrace outside of the reentrancy lock to
1127 * avoid deadlocks. See ASTERISK-22455. */
1128 ast_bt_get_addresses(&tmp);
1130 ast_reentrancy_lock(lt);
1131 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1132 lt->backtrace[lt->reentrancy] = tmp;
1133 bt = <->backtrace[lt->reentrancy];
1135 ast_reentrancy_unlock(lt);
1137 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1139 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1142 #endif /* DEBUG_THREADS */
1144 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1145 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1148 struct timeval _now;
1150 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1154 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1162 #ifdef DEBUG_THREADS
1163 if (!res && t->tracking) {
1164 ast_reentrancy_lock(lt);
1165 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1166 lt->file[lt->reentrancy] = filename;
1167 lt->lineno[lt->reentrancy] = line;
1168 lt->func[lt->reentrancy] = func;
1169 lt->thread[lt->reentrancy] = pthread_self();
1172 ast_reentrancy_unlock(lt);
1174 ast_mark_lock_acquired(t);
1176 } else if (t->tracking) {
1178 if (lt->reentrancy) {
1179 ast_reentrancy_lock(lt);
1180 bt = <->backtrace[lt->reentrancy-1];
1181 ast_reentrancy_unlock(lt);
1185 ast_remove_lock_info(t, bt);
1187 ast_remove_lock_info(t);
1191 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1192 filename, line, func, strerror(res));
1195 #endif /* DEBUG_THREADS */
1200 int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1201 const struct timespec *abs_timeout)
1205 #ifdef DEBUG_THREADS
1206 struct ast_lock_track *lt;
1207 int canlog = strcmp(filename, "logger.c") & t->tracking;
1209 struct ast_bt *bt = NULL;
1212 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1213 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1214 /* Don't warn abount uninitialized lock.
1215 * Simple try to initialize it.
1216 * May be not needed in linux system.
1218 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1219 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1220 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1221 filename, line, func, name);
1225 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1227 if (t->tracking && !t->track) {
1228 ast_reentrancy_init(&t->track);
1236 /* The implementation of backtrace() may have its own locks.
1237 * Capture the backtrace outside of the reentrancy lock to
1238 * avoid deadlocks. See ASTERISK-22455. */
1239 ast_bt_get_addresses(&tmp);
1241 ast_reentrancy_lock(lt);
1242 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1243 lt->backtrace[lt->reentrancy] = tmp;
1244 bt = <->backtrace[lt->reentrancy];
1246 ast_reentrancy_unlock(lt);
1248 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1250 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1253 #endif /* DEBUG_THREADS */
1255 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1256 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1259 struct timeval _now;
1261 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1265 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1273 #ifdef DEBUG_THREADS
1274 if (!res && t->tracking) {
1275 ast_reentrancy_lock(lt);
1276 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1277 lt->file[lt->reentrancy] = filename;
1278 lt->lineno[lt->reentrancy] = line;
1279 lt->func[lt->reentrancy] = func;
1280 lt->thread[lt->reentrancy] = pthread_self();
1283 ast_reentrancy_unlock(lt);
1285 ast_mark_lock_acquired(t);
1287 } else if (t->tracking) {
1289 if (lt->reentrancy) {
1290 ast_reentrancy_lock(lt);
1291 bt = <->backtrace[lt->reentrancy-1];
1292 ast_reentrancy_unlock(lt);
1297 ast_remove_lock_info(t, bt);
1301 ast_remove_lock_info(t);
1306 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1307 filename, line, func, strerror(res));
1310 #endif /* DEBUG_THREADS */
1315 int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1319 #ifdef DEBUG_THREADS
1320 struct ast_lock_track *lt;
1322 struct ast_bt *bt = NULL;
1324 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1325 int canlog = strcmp(filename, "logger.c") & t->tracking;
1327 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1328 /* Don't warn abount uninitialized lock.
1329 * Simple try to initialize it.
1330 * May be not needed in linux system.
1332 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1333 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1334 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1335 filename, line, func, name);
1339 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1341 if (t->tracking && !t->track) {
1342 ast_reentrancy_init(&t->track);
1350 /* The implementation of backtrace() may have its own locks.
1351 * Capture the backtrace outside of the reentrancy lock to
1352 * avoid deadlocks. See ASTERISK-22455. */
1353 ast_bt_get_addresses(&tmp);
1355 ast_reentrancy_lock(lt);
1356 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1357 lt->backtrace[lt->reentrancy] = tmp;
1358 bt = <->backtrace[lt->reentrancy];
1360 ast_reentrancy_unlock(lt);
1362 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1364 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
1367 #endif /* DEBUG_THREADS */
1369 res = pthread_rwlock_tryrdlock(&t->lock);
1371 #ifdef DEBUG_THREADS
1372 if (!res && t->tracking) {
1373 ast_reentrancy_lock(lt);
1374 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1375 lt->file[lt->reentrancy] = filename;
1376 lt->lineno[lt->reentrancy] = line;
1377 lt->func[lt->reentrancy] = func;
1378 lt->thread[lt->reentrancy] = pthread_self();
1381 ast_reentrancy_unlock(lt);
1383 ast_mark_lock_acquired(t);
1385 } else if (t->tracking) {
1386 ast_mark_lock_failed(t);
1388 #endif /* DEBUG_THREADS */
1393 int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1397 #ifdef DEBUG_THREADS
1398 struct ast_lock_track *lt;
1400 struct ast_bt *bt = NULL;
1402 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1403 int canlog = strcmp(filename, "logger.c") & t->tracking;
1405 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1406 /* Don't warn abount uninitialized lock.
1407 * Simple try to initialize it.
1408 * May be not needed in linux system.
1410 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1411 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1412 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1413 filename, line, func, name);
1417 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1419 if (t->tracking && !t->track) {
1420 ast_reentrancy_init(&t->track);
1428 /* The implementation of backtrace() may have its own locks.
1429 * Capture the backtrace outside of the reentrancy lock to
1430 * avoid deadlocks. See ASTERISK-22455. */
1431 ast_bt_get_addresses(&tmp);
1433 ast_reentrancy_lock(lt);
1434 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1435 lt->backtrace[lt->reentrancy] = tmp;
1436 bt = <->backtrace[lt->reentrancy];
1438 ast_reentrancy_unlock(lt);
1440 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1442 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1445 #endif /* DEBUG_THREADS */
1447 res = pthread_rwlock_trywrlock(&t->lock);
1449 #ifdef DEBUG_THREADS
1450 if (!res && t->tracking) {
1451 ast_reentrancy_lock(lt);
1452 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1453 lt->file[lt->reentrancy] = filename;
1454 lt->lineno[lt->reentrancy] = line;
1455 lt->func[lt->reentrancy] = func;
1456 lt->thread[lt->reentrancy] = pthread_self();
1459 ast_reentrancy_unlock(lt);
1460 ast_mark_lock_acquired(t);
1461 } else if (t->tracking) {
1462 ast_mark_lock_failed(t);
1464 #endif /* DEBUG_THREADS */