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 */
314 ast_assert(res == 0);/*!< \todo BUGBUG Test to ensure that lock/unlock does not fail. */
318 int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
319 const char* mutex_name, ast_mutex_t *t)
324 struct ast_lock_track *lt;
325 int canlog = strcmp(filename, "logger.c") & t->tracking;
327 struct ast_bt *bt = NULL;
330 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
331 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
332 /* Don't warn abount uninitialized mutex.
333 * Simple try to initialize it.
334 * May be not needed in linux system.
336 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
337 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
338 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
339 filename, lineno, func, mutex_name);
343 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
345 if (t->tracking && !t->track) {
346 ast_reentrancy_init(&t->track);
354 /* The implementation of backtrace() may have its own locks.
355 * Capture the backtrace outside of the reentrancy lock to
356 * avoid deadlocks. See ASTERISK-22455. */
357 ast_bt_get_addresses(&tmp);
359 ast_reentrancy_lock(lt);
360 if (lt->reentrancy != AST_MAX_REENTRANCY) {
361 lt->backtrace[lt->reentrancy] = tmp;
362 bt = <->backtrace[lt->reentrancy];
364 ast_reentrancy_unlock(lt);
366 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
368 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
371 #endif /* DEBUG_THREADS */
373 res = pthread_mutex_trylock(&t->mutex);
376 if (t->tracking && !res) {
377 ast_reentrancy_lock(lt);
378 if (lt->reentrancy < AST_MAX_REENTRANCY) {
379 lt->file[lt->reentrancy] = filename;
380 lt->lineno[lt->reentrancy] = lineno;
381 lt->func[lt->reentrancy] = func;
382 lt->thread[lt->reentrancy] = pthread_self();
385 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
386 filename, lineno, func, mutex_name);
388 ast_reentrancy_unlock(lt);
390 ast_mark_lock_acquired(t);
392 } else if (t->tracking) {
393 ast_mark_lock_failed(t);
395 #endif /* DEBUG_THREADS */
400 int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
401 const char *mutex_name, ast_mutex_t *t)
406 struct ast_lock_track *lt;
407 int canlog = strcmp(filename, "logger.c") & t->tracking;
409 struct ast_bt *bt = NULL;
412 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
413 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
414 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
415 filename, lineno, func, mutex_name);
416 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
417 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
418 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
419 filename, lineno, func, mutex_name);
421 ast_assert(res == 0);/*!< \todo BUGBUG Test to ensure that lock/unlock does not fail. */
424 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
426 if (t->tracking && !t->track) {
427 ast_reentrancy_init(&t->track);
432 ast_reentrancy_lock(lt);
433 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
434 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
435 filename, lineno, func, mutex_name);
436 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
437 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
439 __dump_backtrace(<->backtrace[ROFFSET], canlog);
444 if (--lt->reentrancy < 0) {
445 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
446 filename, lineno, func, mutex_name);
450 if (lt->reentrancy < AST_MAX_REENTRANCY) {
451 lt->file[lt->reentrancy] = NULL;
452 lt->lineno[lt->reentrancy] = 0;
453 lt->func[lt->reentrancy] = NULL;
454 lt->thread[lt->reentrancy] = 0;
458 if (lt->reentrancy) {
459 bt = <->backtrace[lt->reentrancy - 1];
462 ast_reentrancy_unlock(lt);
465 ast_remove_lock_info(t, bt);
467 ast_remove_lock_info(t);
470 #endif /* DEBUG_THREADS */
472 res = pthread_mutex_unlock(&t->mutex);
476 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
477 filename, lineno, func, strerror(res));
480 #endif /* DEBUG_THREADS */
482 ast_assert(res == 0);/*!< \todo BUGBUG Test to ensure that lock/unlock does not fail. */
487 int __ast_cond_init(const char *filename, int lineno, const char *func,
488 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
490 return pthread_cond_init(cond, cond_attr);
493 int __ast_cond_signal(const char *filename, int lineno, const char *func,
494 const char *cond_name, ast_cond_t *cond)
496 return pthread_cond_signal(cond);
499 int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
500 const char *cond_name, ast_cond_t *cond)
502 return pthread_cond_broadcast(cond);
505 int __ast_cond_destroy(const char *filename, int lineno, const char *func,
506 const char *cond_name, ast_cond_t *cond)
508 return pthread_cond_destroy(cond);
511 int __ast_cond_wait(const char *filename, int lineno, const char *func,
512 const char *cond_name, const char *mutex_name,
513 ast_cond_t *cond, ast_mutex_t *t)
518 struct ast_lock_track *lt;
519 struct ast_lock_track lt_orig;
520 int canlog = strcmp(filename, "logger.c") & t->tracking;
522 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
523 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
524 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
525 filename, lineno, func, mutex_name);
526 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
527 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
528 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
529 filename, lineno, func, mutex_name);
533 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
535 if (t->tracking && !t->track) {
536 ast_reentrancy_init(&t->track);
541 ast_reentrancy_lock(lt);
542 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
543 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
544 filename, lineno, func, mutex_name);
545 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
546 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
548 __dump_backtrace(<->backtrace[ROFFSET], canlog);
551 } else if (lt->reentrancy <= 0) {
552 __ast_mutex_logger("%s line %d (%s): attempted to wait on an unlocked mutex '%s'\n",
553 filename, lineno, func, mutex_name);
557 /* Waiting on a condition completely suspends a recursive mutex,
558 * even if it's been recursively locked multiple times. Make a
559 * copy of the lock tracking, and reset reentrancy to zero */
562 ast_reentrancy_unlock(lt);
564 ast_suspend_lock_info(t);
566 #endif /* DEBUG_THREADS */
568 res = pthread_cond_wait(cond, &t->mutex);
572 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
573 filename, lineno, func, strerror(res));
575 } else if (t->tracking) {
576 pthread_mutex_t reentr_mutex_orig;
577 ast_reentrancy_lock(lt);
578 /* Restore lock tracking to what it was prior to the wait */
579 reentr_mutex_orig = lt->reentr_mutex;
581 /* un-trash the mutex we just copied over */
582 lt->reentr_mutex = reentr_mutex_orig;
583 ast_reentrancy_unlock(lt);
585 ast_restore_lock_info(t);
587 #endif /* DEBUG_THREADS */
592 int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
593 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
594 ast_mutex_t *t, const struct timespec *abstime)
599 struct ast_lock_track *lt;
600 struct ast_lock_track lt_orig;
601 int canlog = strcmp(filename, "logger.c") & t->tracking;
603 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
604 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
605 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
606 filename, lineno, func, mutex_name);
607 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
608 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
609 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
610 filename, lineno, func, mutex_name);
614 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
616 if (t->tracking && !t->track) {
617 ast_reentrancy_init(&t->track);
622 ast_reentrancy_lock(lt);
623 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
624 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
625 filename, lineno, func, mutex_name);
626 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
627 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
629 __dump_backtrace(<->backtrace[ROFFSET], canlog);
632 } else if (lt->reentrancy <= 0) {
633 __ast_mutex_logger("%s line %d (%s): attempted to wait on an unlocked mutex '%s'\n",
634 filename, lineno, func, mutex_name);
638 /* Waiting on a condition completely suspends a recursive mutex,
639 * even if it's been recursively locked multiple times. Make a
640 * copy of the lock tracking, and reset reentrancy to zero */
643 ast_reentrancy_unlock(lt);
645 ast_suspend_lock_info(t);
647 #endif /* DEBUG_THREADS */
649 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
652 if (res && (res != ETIMEDOUT)) {
653 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
654 filename, lineno, func, strerror(res));
656 } else if (t->tracking) {
657 pthread_mutex_t reentr_mutex_orig;
658 ast_reentrancy_lock(lt);
659 /* Restore lock tracking to what it was prior to the wait */
660 reentr_mutex_orig = lt->reentr_mutex;
662 /* un-trash the mutex we just copied over */
663 lt->reentr_mutex = reentr_mutex_orig;
664 ast_reentrancy_unlock(lt);
666 ast_suspend_lock_info(t);
668 #endif /* DEBUG_THREADS */
673 int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
676 pthread_rwlockattr_t attr;
680 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
681 int canlog = strcmp(filename, "logger.c") & t->tracking;
683 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
684 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
685 filename, lineno, func, rwlock_name);
688 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
690 if ((t->tracking = tracking)) {
691 ast_reentrancy_init(&t->track);
693 #endif /* DEBUG_THREADS */
695 pthread_rwlockattr_init(&attr);
697 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
698 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
701 res = pthread_rwlock_init(&t->lock, &attr);
702 pthread_rwlockattr_destroy(&attr);
706 int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
711 struct ast_lock_track *lt = t->track;
712 int canlog = strcmp(filename, "logger.c") & t->tracking;
714 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
715 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
716 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
717 filename, lineno, func, rwlock_name);
720 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
722 #endif /* DEBUG_THREADS */
724 res = pthread_rwlock_destroy(&t->lock);
728 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
729 filename, lineno, func, rwlock_name, strerror(res));
731 if (t->tracking && lt) {
732 ast_reentrancy_lock(lt);
733 lt->file[0] = filename;
734 lt->lineno[0] = lineno;
739 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
741 ast_reentrancy_unlock(lt);
742 delete_reentrancy_cs(&t->track);
744 #endif /* DEBUG_THREADS */
749 int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
754 struct ast_lock_track *lt;
755 int canlog = strcmp(filename, "logger.c") & t->tracking;
757 struct ast_bt *bt = NULL;
762 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
763 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
764 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
765 filename, line, func, name);
766 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
767 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
768 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
769 filename, line, func, name);
773 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
775 if (t->tracking && !t->track) {
776 ast_reentrancy_init(&t->track);
781 ast_reentrancy_lock(lt);
782 if (lt->reentrancy) {
784 pthread_t self = pthread_self();
785 for (i = lt->reentrancy - 1; i >= 0; --i) {
786 if (lt->thread[i] == self) {
788 if (i != lt->reentrancy - 1) {
789 lt->file[i] = lt->file[lt->reentrancy - 1];
790 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
791 lt->func[i] = lt->func[lt->reentrancy - 1];
792 lt->thread[i] = lt->thread[lt->reentrancy - 1];
795 bt = <->backtrace[i];
797 lt->file[lt->reentrancy - 1] = NULL;
798 lt->lineno[lt->reentrancy - 1] = 0;
799 lt->func[lt->reentrancy - 1] = NULL;
800 lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
806 if (lock_found && --lt->reentrancy < 0) {
807 __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
808 filename, line, func, name);
812 ast_reentrancy_unlock(lt);
815 ast_remove_lock_info(t, bt);
817 ast_remove_lock_info(t);
820 #endif /* DEBUG_THREADS */
822 res = pthread_rwlock_unlock(&t->lock);
826 __ast_mutex_logger("%s line %d (%s): Error releasing rwlock: %s\n",
827 filename, line, func, strerror(res));
830 #endif /* DEBUG_THREADS */
835 int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
840 struct ast_lock_track *lt;
841 int canlog = strcmp(filename, "logger.c") & t->tracking;
843 struct ast_bt *bt = NULL;
846 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
847 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
848 /* Don't warn abount uninitialized lock.
849 * Simple try to initialize it.
850 * May be not needed in linux system.
852 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
853 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
854 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
855 filename, line, func, name);
859 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
861 if (t->tracking && !t->track) {
862 ast_reentrancy_init(&t->track);
870 /* The implementation of backtrace() may have its own locks.
871 * Capture the backtrace outside of the reentrancy lock to
872 * avoid deadlocks. See ASTERISK-22455. */
873 ast_bt_get_addresses(&tmp);
875 ast_reentrancy_lock(lt);
876 if (lt->reentrancy != AST_MAX_REENTRANCY) {
877 lt->backtrace[lt->reentrancy] = tmp;
878 bt = <->backtrace[lt->reentrancy];
880 ast_reentrancy_unlock(lt);
882 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
884 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
887 #endif /* DEBUG_THREADS */
889 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
891 time_t seconds = time(NULL);
892 time_t wait_time, reported_wait = 0;
894 res = pthread_rwlock_tryrdlock(&t->lock);
896 wait_time = time(NULL) - seconds;
897 if (wait_time > reported_wait && (wait_time % 5) == 0) {
898 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
899 filename, line, func, (int)wait_time, name);
901 ast_reentrancy_lock(lt);
903 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
905 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
906 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
907 lt->func[lt->reentrancy-1], name);
909 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
911 ast_reentrancy_unlock(lt);
913 reported_wait = wait_time;
917 } while (res == EBUSY);
919 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
920 res = pthread_rwlock_rdlock(&t->lock);
921 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
924 if (!res && t->tracking) {
925 ast_reentrancy_lock(lt);
926 if (lt->reentrancy < AST_MAX_REENTRANCY) {
927 lt->file[lt->reentrancy] = filename;
928 lt->lineno[lt->reentrancy] = line;
929 lt->func[lt->reentrancy] = func;
930 lt->thread[lt->reentrancy] = pthread_self();
933 ast_reentrancy_unlock(lt);
935 ast_mark_lock_acquired(t);
937 } else if (t->tracking) {
939 if (lt->reentrancy) {
940 ast_reentrancy_lock(lt);
941 bt = <->backtrace[lt->reentrancy-1];
942 ast_reentrancy_unlock(lt);
946 ast_remove_lock_info(t, bt);
948 ast_remove_lock_info(t);
953 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
954 filename, line, func, strerror(res));
957 #endif /* DEBUG_THREADS */
962 int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
967 struct ast_lock_track *lt;
968 int canlog = strcmp(filename, "logger.c") & t->tracking;
970 struct ast_bt *bt = NULL;
973 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
974 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
975 /* Don't warn abount uninitialized lock.
976 * Simple try to initialize it.
977 * May be not needed in linux system.
979 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
980 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
981 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
982 filename, line, func, name);
986 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
988 if (t->tracking && !t->track) {
989 ast_reentrancy_init(&t->track);
997 /* The implementation of backtrace() may have its own locks.
998 * Capture the backtrace outside of the reentrancy lock to
999 * avoid deadlocks. See ASTERISK-22455. */
1000 ast_bt_get_addresses(&tmp);
1002 ast_reentrancy_lock(lt);
1003 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1004 lt->backtrace[lt->reentrancy] = tmp;
1005 bt = <->backtrace[lt->reentrancy];
1007 ast_reentrancy_unlock(lt);
1009 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1011 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1014 #endif /* DEBUG_THREADS */
1016 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
1018 time_t seconds = time(NULL);
1019 time_t wait_time, reported_wait = 0;
1021 res = pthread_rwlock_trywrlock(&t->lock);
1023 wait_time = time(NULL) - seconds;
1024 if (wait_time > reported_wait && (wait_time % 5) == 0) {
1025 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
1026 filename, line, func, (int)wait_time, name);
1028 ast_reentrancy_lock(lt);
1030 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
1032 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
1033 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1034 lt->func[lt->reentrancy-1], name);
1036 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
1038 ast_reentrancy_unlock(lt);
1040 reported_wait = wait_time;
1044 } while (res == EBUSY);
1046 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1047 res = pthread_rwlock_wrlock(&t->lock);
1048 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1050 #ifdef DEBUG_THREADS
1051 if (!res && t->tracking) {
1052 ast_reentrancy_lock(lt);
1053 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1054 lt->file[lt->reentrancy] = filename;
1055 lt->lineno[lt->reentrancy] = line;
1056 lt->func[lt->reentrancy] = func;
1057 lt->thread[lt->reentrancy] = pthread_self();
1060 ast_reentrancy_unlock(lt);
1062 ast_mark_lock_acquired(t);
1064 } else if (t->tracking) {
1066 if (lt->reentrancy) {
1067 ast_reentrancy_lock(lt);
1068 bt = <->backtrace[lt->reentrancy-1];
1069 ast_reentrancy_unlock(lt);
1074 ast_remove_lock_info(t, bt);
1078 ast_remove_lock_info(t);
1083 __ast_mutex_logger("%s line %d (%s): Error obtaining write lock: %s\n",
1084 filename, line, func, strerror(res));
1087 #endif /* DEBUG_THREADS */
1092 int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1093 const struct timespec *abs_timeout)
1097 #ifdef DEBUG_THREADS
1098 struct ast_lock_track *lt;
1099 int canlog = strcmp(filename, "logger.c") & t->tracking;
1101 struct ast_bt *bt = NULL;
1104 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1105 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1106 /* Don't warn abount uninitialized lock.
1107 * Simple try to initialize it.
1108 * May be not needed in linux system.
1110 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1111 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1112 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1113 filename, line, func, name);
1117 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1119 if (t->tracking && !t->track) {
1120 ast_reentrancy_init(&t->track);
1128 /* The implementation of backtrace() may have its own locks.
1129 * Capture the backtrace outside of the reentrancy lock to
1130 * avoid deadlocks. See ASTERISK-22455. */
1131 ast_bt_get_addresses(&tmp);
1133 ast_reentrancy_lock(lt);
1134 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1135 lt->backtrace[lt->reentrancy] = tmp;
1136 bt = <->backtrace[lt->reentrancy];
1138 ast_reentrancy_unlock(lt);
1140 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1142 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1145 #endif /* DEBUG_THREADS */
1147 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1148 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1151 struct timeval _now;
1153 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1157 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1165 #ifdef DEBUG_THREADS
1166 if (!res && t->tracking) {
1167 ast_reentrancy_lock(lt);
1168 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1169 lt->file[lt->reentrancy] = filename;
1170 lt->lineno[lt->reentrancy] = line;
1171 lt->func[lt->reentrancy] = func;
1172 lt->thread[lt->reentrancy] = pthread_self();
1175 ast_reentrancy_unlock(lt);
1177 ast_mark_lock_acquired(t);
1179 } else if (t->tracking) {
1181 if (lt->reentrancy) {
1182 ast_reentrancy_lock(lt);
1183 bt = <->backtrace[lt->reentrancy-1];
1184 ast_reentrancy_unlock(lt);
1188 ast_remove_lock_info(t, bt);
1190 ast_remove_lock_info(t);
1194 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1195 filename, line, func, strerror(res));
1198 #endif /* DEBUG_THREADS */
1203 int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1204 const struct timespec *abs_timeout)
1208 #ifdef DEBUG_THREADS
1209 struct ast_lock_track *lt;
1210 int canlog = strcmp(filename, "logger.c") & t->tracking;
1212 struct ast_bt *bt = NULL;
1215 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1216 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1217 /* Don't warn abount uninitialized lock.
1218 * Simple try to initialize it.
1219 * May be not needed in linux system.
1221 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1222 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1223 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1224 filename, line, func, name);
1228 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1230 if (t->tracking && !t->track) {
1231 ast_reentrancy_init(&t->track);
1239 /* The implementation of backtrace() may have its own locks.
1240 * Capture the backtrace outside of the reentrancy lock to
1241 * avoid deadlocks. See ASTERISK-22455. */
1242 ast_bt_get_addresses(&tmp);
1244 ast_reentrancy_lock(lt);
1245 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1246 lt->backtrace[lt->reentrancy] = tmp;
1247 bt = <->backtrace[lt->reentrancy];
1249 ast_reentrancy_unlock(lt);
1251 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1253 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1256 #endif /* DEBUG_THREADS */
1258 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1259 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1262 struct timeval _now;
1264 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1268 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1276 #ifdef DEBUG_THREADS
1277 if (!res && t->tracking) {
1278 ast_reentrancy_lock(lt);
1279 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1280 lt->file[lt->reentrancy] = filename;
1281 lt->lineno[lt->reentrancy] = line;
1282 lt->func[lt->reentrancy] = func;
1283 lt->thread[lt->reentrancy] = pthread_self();
1286 ast_reentrancy_unlock(lt);
1288 ast_mark_lock_acquired(t);
1290 } else if (t->tracking) {
1292 if (lt->reentrancy) {
1293 ast_reentrancy_lock(lt);
1294 bt = <->backtrace[lt->reentrancy-1];
1295 ast_reentrancy_unlock(lt);
1300 ast_remove_lock_info(t, bt);
1304 ast_remove_lock_info(t);
1309 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1310 filename, line, func, strerror(res));
1313 #endif /* DEBUG_THREADS */
1318 int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1322 #ifdef DEBUG_THREADS
1323 struct ast_lock_track *lt;
1325 struct ast_bt *bt = NULL;
1327 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1328 int canlog = strcmp(filename, "logger.c") & t->tracking;
1330 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1331 /* Don't warn abount uninitialized lock.
1332 * Simple try to initialize it.
1333 * May be not needed in linux system.
1335 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1336 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1337 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1338 filename, line, func, name);
1342 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1344 if (t->tracking && !t->track) {
1345 ast_reentrancy_init(&t->track);
1353 /* The implementation of backtrace() may have its own locks.
1354 * Capture the backtrace outside of the reentrancy lock to
1355 * avoid deadlocks. See ASTERISK-22455. */
1356 ast_bt_get_addresses(&tmp);
1358 ast_reentrancy_lock(lt);
1359 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1360 lt->backtrace[lt->reentrancy] = tmp;
1361 bt = <->backtrace[lt->reentrancy];
1363 ast_reentrancy_unlock(lt);
1365 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1367 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
1370 #endif /* DEBUG_THREADS */
1372 res = pthread_rwlock_tryrdlock(&t->lock);
1374 #ifdef DEBUG_THREADS
1375 if (!res && t->tracking) {
1376 ast_reentrancy_lock(lt);
1377 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1378 lt->file[lt->reentrancy] = filename;
1379 lt->lineno[lt->reentrancy] = line;
1380 lt->func[lt->reentrancy] = func;
1381 lt->thread[lt->reentrancy] = pthread_self();
1384 ast_reentrancy_unlock(lt);
1386 ast_mark_lock_acquired(t);
1388 } else if (t->tracking) {
1389 ast_mark_lock_failed(t);
1391 #endif /* DEBUG_THREADS */
1396 int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1400 #ifdef DEBUG_THREADS
1401 struct ast_lock_track *lt;
1403 struct ast_bt *bt = NULL;
1405 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1406 int canlog = strcmp(filename, "logger.c") & t->tracking;
1408 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1409 /* Don't warn abount uninitialized lock.
1410 * Simple try to initialize it.
1411 * May be not needed in linux system.
1413 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1414 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1415 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1416 filename, line, func, name);
1420 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1422 if (t->tracking && !t->track) {
1423 ast_reentrancy_init(&t->track);
1431 /* The implementation of backtrace() may have its own locks.
1432 * Capture the backtrace outside of the reentrancy lock to
1433 * avoid deadlocks. See ASTERISK-22455. */
1434 ast_bt_get_addresses(&tmp);
1436 ast_reentrancy_lock(lt);
1437 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1438 lt->backtrace[lt->reentrancy] = tmp;
1439 bt = <->backtrace[lt->reentrancy];
1441 ast_reentrancy_unlock(lt);
1443 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1445 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1448 #endif /* DEBUG_THREADS */
1450 res = pthread_rwlock_trywrlock(&t->lock);
1452 #ifdef DEBUG_THREADS
1453 if (!res && t->tracking) {
1454 ast_reentrancy_lock(lt);
1455 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1456 lt->file[lt->reentrancy] = filename;
1457 lt->lineno[lt->reentrancy] = line;
1458 lt->func[lt->reentrancy] = func;
1459 lt->thread[lt->reentrancy] = pthread_self();
1462 ast_reentrancy_unlock(lt);
1463 ast_mark_lock_acquired(t);
1464 } else if (t->tracking) {
1465 ast_mark_lock_failed(t);
1467 #endif /* DEBUG_THREADS */