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/lock.h"
34 /* Allow direct use of pthread_mutex_* / pthread_cond_* */
35 #undef pthread_mutex_init
36 #undef pthread_mutex_destroy
37 #undef pthread_mutex_lock
38 #undef pthread_mutex_trylock
39 #undef pthread_mutex_t
40 #undef pthread_mutex_unlock
41 #undef pthread_cond_init
42 #undef pthread_cond_signal
43 #undef pthread_cond_broadcast
44 #undef pthread_cond_destroy
45 #undef pthread_cond_wait
46 #undef pthread_cond_timedwait
48 int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func,
49 const char *mutex_name, ast_mutex_t *t)
52 pthread_mutexattr_t attr;
56 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
57 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
59 int canlog = strcmp(filename, "logger.c") & track;
60 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
61 filename, lineno, func, mutex_name);
67 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
69 if ((t->tracking = tracking)) {
70 ast_reentrancy_init(&t->track);
72 #endif /* DEBUG_THREADS */
74 pthread_mutexattr_init(&attr);
75 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
77 res = pthread_mutex_init(&t->mutex, &attr);
78 pthread_mutexattr_destroy(&attr);
82 int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
83 const char *mutex_name, ast_mutex_t *t)
88 struct ast_lock_track *lt;
89 int canlog = strcmp(filename, "logger.c") & t->tracking;
91 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
92 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
93 /* Don't try to uninitialize non initialized mutex
94 * This may no effect on linux
95 * And always ganerate core on *BSD with
97 * This not error condition if the mutex created on the fly.
99 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
100 filename, lineno, func, mutex_name);
105 if (t->tracking && !t->track) {
106 ast_reentrancy_init(&t->track);
110 res = pthread_mutex_trylock(&t->mutex);
113 pthread_mutex_unlock(&t->mutex);
116 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
117 filename, lineno, func, mutex_name);
120 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
121 filename, lineno, func, mutex_name);
123 ast_reentrancy_lock(lt);
124 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
125 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
127 __dump_backtrace(<->backtrace[ROFFSET], canlog);
129 ast_reentrancy_unlock(lt);
133 #endif /* DEBUG_THREADS */
135 res = pthread_mutex_destroy(&t->mutex);
139 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
140 filename, lineno, func, mutex_name, strerror(res));
143 ast_reentrancy_lock(lt);
144 lt->file[0] = filename;
145 lt->lineno[0] = lineno;
150 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
152 ast_reentrancy_unlock(lt);
153 delete_reentrancy_cs(&t->track);
155 #endif /* DEBUG_THREADS */
160 int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
161 const char* mutex_name, ast_mutex_t *t)
166 struct ast_lock_track *lt;
167 int canlog = strcmp(filename, "logger.c") & t->tracking;
169 struct ast_bt *bt = NULL;
172 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
173 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
174 /* Don't warn abount uninitialized mutex.
175 * Simple try to initialize it.
176 * May be not needed in linux system.
178 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
179 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
180 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
181 filename, lineno, func, mutex_name);
185 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
187 if (t->tracking && !t->track) {
188 ast_reentrancy_init(&t->track);
194 ast_reentrancy_lock(lt);
195 if (lt->reentrancy != AST_MAX_REENTRANCY) {
196 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
197 bt = <->backtrace[lt->reentrancy];
199 ast_reentrancy_unlock(lt);
200 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
202 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
205 #endif /* DEBUG_THREADS */
207 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
209 time_t seconds = time(NULL);
210 time_t wait_time, reported_wait = 0;
212 #ifdef HAVE_MTX_PROFILE
213 ast_mark(mtx_prof, 1);
215 res = pthread_mutex_trylock(&t->mutex);
216 #ifdef HAVE_MTX_PROFILE
217 ast_mark(mtx_prof, 0);
220 wait_time = time(NULL) - seconds;
221 if (wait_time > reported_wait && (wait_time % 5) == 0) {
222 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
223 filename, lineno, func, (int) wait_time, mutex_name);
224 ast_reentrancy_lock(lt);
226 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
228 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
229 lt->file[ROFFSET], lt->lineno[ROFFSET],
230 lt->func[ROFFSET], mutex_name);
232 __dump_backtrace(<->backtrace[ROFFSET], canlog);
234 ast_reentrancy_unlock(lt);
235 reported_wait = wait_time;
239 } while (res == EBUSY);
241 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
242 #ifdef HAVE_MTX_PROFILE
243 ast_mark(mtx_prof, 1);
244 res = pthread_mutex_trylock(&t->mutex);
245 ast_mark(mtx_prof, 0);
248 res = pthread_mutex_lock(&t->mutex);
249 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
252 if (t->tracking && !res) {
253 ast_reentrancy_lock(lt);
254 if (lt->reentrancy < AST_MAX_REENTRANCY) {
255 lt->file[lt->reentrancy] = filename;
256 lt->lineno[lt->reentrancy] = lineno;
257 lt->func[lt->reentrancy] = func;
258 lt->thread[lt->reentrancy] = pthread_self();
261 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
262 filename, lineno, func, mutex_name);
264 ast_reentrancy_unlock(lt);
266 ast_mark_lock_acquired(t);
268 } else if (t->tracking) {
270 if (lt->reentrancy) {
271 ast_reentrancy_lock(lt);
272 bt = <->backtrace[lt->reentrancy-1];
273 ast_reentrancy_unlock(lt);
277 ast_remove_lock_info(t, bt);
279 ast_remove_lock_info(t);
283 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
284 filename, lineno, func, strerror(res));
287 #endif /* DEBUG_THREADS */
292 int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
293 const char* mutex_name, ast_mutex_t *t)
298 struct ast_lock_track *lt;
299 int canlog = strcmp(filename, "logger.c") & t->tracking;
301 struct ast_bt *bt = NULL;
304 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
305 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
306 /* Don't warn abount uninitialized mutex.
307 * Simple try to initialize it.
308 * May be not needed in linux system.
310 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
311 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
312 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
313 filename, lineno, func, mutex_name);
317 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
319 if (t->tracking && !t->track) {
320 ast_reentrancy_init(&t->track);
326 ast_reentrancy_lock(lt);
327 if (lt->reentrancy != AST_MAX_REENTRANCY) {
328 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
329 bt = <->backtrace[lt->reentrancy];
331 ast_reentrancy_unlock(lt);
332 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
334 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
337 #endif /* DEBUG_THREADS */
339 res = pthread_mutex_trylock(&t->mutex);
342 if (t->tracking && !res) {
343 ast_reentrancy_lock(lt);
344 if (lt->reentrancy < AST_MAX_REENTRANCY) {
345 lt->file[lt->reentrancy] = filename;
346 lt->lineno[lt->reentrancy] = lineno;
347 lt->func[lt->reentrancy] = func;
348 lt->thread[lt->reentrancy] = pthread_self();
351 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
352 filename, lineno, func, mutex_name);
354 ast_reentrancy_unlock(lt);
356 ast_mark_lock_acquired(t);
358 } else if (t->tracking) {
359 ast_mark_lock_failed(t);
361 #endif /* DEBUG_THREADS */
366 int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
367 const char *mutex_name, ast_mutex_t *t)
372 struct ast_lock_track *lt;
373 int canlog = strcmp(filename, "logger.c") & t->tracking;
375 struct ast_bt *bt = NULL;
378 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
379 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
380 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
381 filename, lineno, func, mutex_name);
382 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
383 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
384 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
385 filename, lineno, func, mutex_name);
389 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
391 if (t->tracking && !t->track) {
392 ast_reentrancy_init(&t->track);
397 ast_reentrancy_lock(lt);
398 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
399 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
400 filename, lineno, func, mutex_name);
401 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
402 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
404 __dump_backtrace(<->backtrace[ROFFSET], canlog);
409 if (--lt->reentrancy < 0) {
410 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
411 filename, lineno, func, mutex_name);
415 if (lt->reentrancy < AST_MAX_REENTRANCY) {
416 lt->file[lt->reentrancy] = NULL;
417 lt->lineno[lt->reentrancy] = 0;
418 lt->func[lt->reentrancy] = NULL;
419 lt->thread[lt->reentrancy] = 0;
423 if (lt->reentrancy) {
424 bt = <->backtrace[lt->reentrancy - 1];
427 ast_reentrancy_unlock(lt);
430 ast_remove_lock_info(t, bt);
432 ast_remove_lock_info(t);
435 #endif /* DEBUG_THREADS */
437 res = pthread_mutex_unlock(&t->mutex);
441 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
442 filename, lineno, func, strerror(res));
445 #endif /* DEBUG_THREADS */
451 int __ast_cond_init(const char *filename, int lineno, const char *func,
452 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
454 return pthread_cond_init(cond, cond_attr);
457 int __ast_cond_signal(const char *filename, int lineno, const char *func,
458 const char *cond_name, ast_cond_t *cond)
460 return pthread_cond_signal(cond);
463 int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
464 const char *cond_name, ast_cond_t *cond)
466 return pthread_cond_broadcast(cond);
469 int __ast_cond_destroy(const char *filename, int lineno, const char *func,
470 const char *cond_name, ast_cond_t *cond)
472 return pthread_cond_destroy(cond);
475 int __ast_cond_wait(const char *filename, int lineno, const char *func,
476 const char *cond_name, const char *mutex_name,
477 ast_cond_t *cond, ast_mutex_t *t)
482 struct ast_lock_track *lt;
483 int canlog = strcmp(filename, "logger.c") & t->tracking;
485 struct ast_bt *bt = NULL;
488 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
489 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
490 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
491 filename, lineno, func, mutex_name);
492 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
493 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
494 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
495 filename, lineno, func, mutex_name);
499 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
501 if (t->tracking && !t->track) {
502 ast_reentrancy_init(&t->track);
507 ast_reentrancy_lock(lt);
508 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
509 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
510 filename, lineno, func, mutex_name);
511 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
512 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
514 __dump_backtrace(<->backtrace[ROFFSET], canlog);
519 if (--lt->reentrancy < 0) {
520 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
521 filename, lineno, func, mutex_name);
525 if (lt->reentrancy < AST_MAX_REENTRANCY) {
526 lt->file[lt->reentrancy] = NULL;
527 lt->lineno[lt->reentrancy] = 0;
528 lt->func[lt->reentrancy] = NULL;
529 lt->thread[lt->reentrancy] = 0;
533 if (lt->reentrancy) {
534 bt = <->backtrace[lt->reentrancy - 1];
537 ast_reentrancy_unlock(lt);
540 ast_remove_lock_info(t, bt);
542 ast_remove_lock_info(t);
545 #endif /* DEBUG_THREADS */
547 res = pthread_cond_wait(cond, &t->mutex);
551 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
552 filename, lineno, func, strerror(res));
554 } else if (t->tracking) {
555 ast_reentrancy_lock(lt);
556 if (lt->reentrancy < AST_MAX_REENTRANCY) {
557 lt->file[lt->reentrancy] = filename;
558 lt->lineno[lt->reentrancy] = lineno;
559 lt->func[lt->reentrancy] = func;
560 lt->thread[lt->reentrancy] = pthread_self();
562 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
563 bt = <->backtrace[lt->reentrancy];
567 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
568 filename, lineno, func, mutex_name);
570 ast_reentrancy_unlock(lt);
573 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
575 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
578 #endif /* DEBUG_THREADS */
583 int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
584 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
585 ast_mutex_t *t, const struct timespec *abstime)
590 struct ast_lock_track *lt;
591 int canlog = strcmp(filename, "logger.c") & t->tracking;
593 struct ast_bt *bt = NULL;
596 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
597 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
598 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
599 filename, lineno, func, mutex_name);
600 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
601 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
602 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
603 filename, lineno, func, mutex_name);
607 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
609 if (t->tracking && !t->track) {
610 ast_reentrancy_init(&t->track);
615 ast_reentrancy_lock(lt);
616 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
617 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
618 filename, lineno, func, mutex_name);
619 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
620 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
622 __dump_backtrace(<->backtrace[ROFFSET], canlog);
627 if (--lt->reentrancy < 0) {
628 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
629 filename, lineno, func, mutex_name);
633 if (lt->reentrancy < AST_MAX_REENTRANCY) {
634 lt->file[lt->reentrancy] = NULL;
635 lt->lineno[lt->reentrancy] = 0;
636 lt->func[lt->reentrancy] = NULL;
637 lt->thread[lt->reentrancy] = 0;
640 if (lt->reentrancy) {
641 bt = <->backtrace[lt->reentrancy - 1];
644 ast_reentrancy_unlock(lt);
647 ast_remove_lock_info(t, bt);
649 ast_remove_lock_info(t);
652 #endif /* DEBUG_THREADS */
654 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
657 if (res && (res != ETIMEDOUT)) {
658 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
659 filename, lineno, func, strerror(res));
661 } else if (t->tracking) {
662 ast_reentrancy_lock(lt);
663 if (lt->reentrancy < AST_MAX_REENTRANCY) {
664 lt->file[lt->reentrancy] = filename;
665 lt->lineno[lt->reentrancy] = lineno;
666 lt->func[lt->reentrancy] = func;
667 lt->thread[lt->reentrancy] = pthread_self();
669 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
670 bt = <->backtrace[lt->reentrancy];
674 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
675 filename, lineno, func, mutex_name);
677 ast_reentrancy_unlock(lt);
680 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
682 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
685 #endif /* DEBUG_THREADS */
690 int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
693 pthread_rwlockattr_t attr;
697 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
698 int canlog = strcmp(filename, "logger.c") & t->tracking;
700 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
701 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
702 filename, lineno, func, rwlock_name);
705 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
707 if ((t->tracking = tracking)) {
708 ast_reentrancy_init(&t->track);
710 #endif /* DEBUG_THREADS */
712 pthread_rwlockattr_init(&attr);
714 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
715 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
718 res = pthread_rwlock_init(&t->lock, &attr);
719 pthread_rwlockattr_destroy(&attr);
723 int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
728 struct ast_lock_track *lt = t->track;
729 int canlog = strcmp(filename, "logger.c") & t->tracking;
731 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
732 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
733 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
734 filename, lineno, func, rwlock_name);
737 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
739 #endif /* DEBUG_THREADS */
741 res = pthread_rwlock_destroy(&t->lock);
745 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
746 filename, lineno, func, rwlock_name, strerror(res));
749 ast_reentrancy_lock(lt);
750 lt->file[0] = filename;
751 lt->lineno[0] = lineno;
756 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
758 ast_reentrancy_unlock(lt);
759 delete_reentrancy_cs(&t->track);
761 #endif /* DEBUG_THREADS */
766 int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
771 struct ast_lock_track *lt;
772 int canlog = strcmp(filename, "logger.c") & t->tracking;
774 struct ast_bt *bt = NULL;
779 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
780 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
781 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
782 filename, line, func, name);
783 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
784 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
785 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
786 filename, line, func, name);
790 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
792 if (t->tracking && !t->track) {
793 ast_reentrancy_init(&t->track);
798 ast_reentrancy_lock(lt);
799 if (lt->reentrancy) {
801 pthread_t self = pthread_self();
802 for (i = lt->reentrancy - 1; i >= 0; --i) {
803 if (lt->thread[i] == self) {
805 if (i != lt->reentrancy - 1) {
806 lt->file[i] = lt->file[lt->reentrancy - 1];
807 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
808 lt->func[i] = lt->func[lt->reentrancy - 1];
809 lt->thread[i] = lt->thread[lt->reentrancy - 1];
812 bt = <->backtrace[i];
814 lt->file[lt->reentrancy - 1] = NULL;
815 lt->lineno[lt->reentrancy - 1] = 0;
816 lt->func[lt->reentrancy - 1] = NULL;
817 lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
823 if (lock_found && --lt->reentrancy < 0) {
824 __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
825 filename, line, func, name);
829 ast_reentrancy_unlock(lt);
832 ast_remove_lock_info(t, bt);
834 ast_remove_lock_info(t);
837 #endif /* DEBUG_THREADS */
839 res = pthread_rwlock_unlock(&t->lock);
843 __ast_mutex_logger("%s line %d (%s): Error releasing rwlock: %s\n",
844 filename, line, func, strerror(res));
847 #endif /* DEBUG_THREADS */
852 int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
857 struct ast_lock_track *lt;
858 int canlog = strcmp(filename, "logger.c") & t->tracking;
860 struct ast_bt *bt = NULL;
863 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
864 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
865 /* Don't warn abount uninitialized lock.
866 * Simple try to initialize it.
867 * May be not needed in linux system.
869 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
870 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
871 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
872 filename, line, func, name);
876 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
878 if (t->tracking && !t->track) {
879 ast_reentrancy_init(&t->track);
885 ast_reentrancy_lock(lt);
886 if (lt->reentrancy != AST_MAX_REENTRANCY) {
887 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
888 bt = <->backtrace[lt->reentrancy];
890 ast_reentrancy_unlock(lt);
891 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
893 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
896 #endif /* DEBUG_THREADS */
898 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
900 time_t seconds = time(NULL);
901 time_t wait_time, reported_wait = 0;
903 res = pthread_rwlock_tryrdlock(&t->lock);
905 wait_time = time(NULL) - seconds;
906 if (wait_time > reported_wait && (wait_time % 5) == 0) {
907 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
908 filename, line, func, (int)wait_time, name);
910 ast_reentrancy_lock(lt);
912 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
914 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
915 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
916 lt->func[lt->reentrancy-1], name);
918 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
920 ast_reentrancy_unlock(lt);
922 reported_wait = wait_time;
926 } while (res == EBUSY);
928 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
929 res = pthread_rwlock_rdlock(&t->lock);
930 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
933 if (!res && t->tracking) {
934 ast_reentrancy_lock(lt);
935 if (lt->reentrancy < AST_MAX_REENTRANCY) {
936 lt->file[lt->reentrancy] = filename;
937 lt->lineno[lt->reentrancy] = line;
938 lt->func[lt->reentrancy] = func;
939 lt->thread[lt->reentrancy] = pthread_self();
942 ast_reentrancy_unlock(lt);
944 ast_mark_lock_acquired(t);
946 } else if (t->tracking) {
948 if (lt->reentrancy) {
949 ast_reentrancy_lock(lt);
950 bt = <->backtrace[lt->reentrancy-1];
951 ast_reentrancy_unlock(lt);
955 ast_remove_lock_info(t, bt);
957 ast_remove_lock_info(t);
962 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
963 filename, line, func, strerror(res));
966 #endif /* DEBUG_THREADS */
971 int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
976 struct ast_lock_track *lt;
977 int canlog = strcmp(filename, "logger.c") & t->tracking;
979 struct ast_bt *bt = NULL;
982 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
983 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
984 /* Don't warn abount uninitialized lock.
985 * Simple try to initialize it.
986 * May be not needed in linux system.
988 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
989 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
990 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
991 filename, line, func, name);
995 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
997 if (t->tracking && !t->track) {
998 ast_reentrancy_init(&t->track);
1004 ast_reentrancy_lock(lt);
1005 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1006 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1007 bt = <->backtrace[lt->reentrancy];
1009 ast_reentrancy_unlock(lt);
1010 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1012 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1015 #endif /* DEBUG_THREADS */
1017 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
1019 time_t seconds = time(NULL);
1020 time_t wait_time, reported_wait = 0;
1022 res = pthread_rwlock_trywrlock(&t->lock);
1024 wait_time = time(NULL) - seconds;
1025 if (wait_time > reported_wait && (wait_time % 5) == 0) {
1026 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
1027 filename, line, func, (int)wait_time, name);
1029 ast_reentrancy_lock(lt);
1031 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
1033 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
1034 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1035 lt->func[lt->reentrancy-1], name);
1037 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
1039 ast_reentrancy_unlock(lt);
1041 reported_wait = wait_time;
1045 } while (res == EBUSY);
1047 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1048 res = pthread_rwlock_wrlock(&t->lock);
1049 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1051 #ifdef DEBUG_THREADS
1052 if (!res && t->tracking) {
1053 ast_reentrancy_lock(lt);
1054 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1055 lt->file[lt->reentrancy] = filename;
1056 lt->lineno[lt->reentrancy] = line;
1057 lt->func[lt->reentrancy] = func;
1058 lt->thread[lt->reentrancy] = pthread_self();
1061 ast_reentrancy_unlock(lt);
1063 ast_mark_lock_acquired(t);
1065 } else if (t->tracking) {
1067 if (lt->reentrancy) {
1068 ast_reentrancy_lock(lt);
1069 bt = <->backtrace[lt->reentrancy-1];
1070 ast_reentrancy_unlock(lt);
1075 ast_remove_lock_info(t, bt);
1079 ast_remove_lock_info(t);
1084 __ast_mutex_logger("%s line %d (%s): Error obtaining write lock: %s\n",
1085 filename, line, func, strerror(res));
1088 #endif /* DEBUG_THREADS */
1093 int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1094 const struct timespec *abs_timeout)
1098 #ifdef DEBUG_THREADS
1099 struct ast_lock_track *lt;
1100 int canlog = strcmp(filename, "logger.c") & t->tracking;
1102 struct ast_bt *bt = NULL;
1105 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1106 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1107 /* Don't warn abount uninitialized lock.
1108 * Simple try to initialize it.
1109 * May be not needed in linux system.
1111 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1112 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1113 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1114 filename, line, func, name);
1118 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1120 if (t->tracking && !t->track) {
1121 ast_reentrancy_init(&t->track);
1127 ast_reentrancy_lock(lt);
1128 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1129 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1130 bt = <->backtrace[lt->reentrancy];
1132 ast_reentrancy_unlock(lt);
1133 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1135 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1138 #endif /* DEBUG_THREADS */
1140 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1141 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1144 struct timeval _now;
1146 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1150 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1158 #ifdef DEBUG_THREADS
1159 if (!res && t->tracking) {
1160 ast_reentrancy_lock(lt);
1161 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1162 lt->file[lt->reentrancy] = filename;
1163 lt->lineno[lt->reentrancy] = line;
1164 lt->func[lt->reentrancy] = func;
1165 lt->thread[lt->reentrancy] = pthread_self();
1168 ast_reentrancy_unlock(lt);
1170 ast_mark_lock_acquired(t);
1172 } else if (t->tracking) {
1174 if (lt->reentrancy) {
1175 ast_reentrancy_lock(lt);
1176 bt = <->backtrace[lt->reentrancy-1];
1177 ast_reentrancy_unlock(lt);
1181 ast_remove_lock_info(t, bt);
1183 ast_remove_lock_info(t);
1187 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1188 filename, line, func, strerror(res));
1191 #endif /* DEBUG_THREADS */
1196 int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1197 const struct timespec *abs_timeout)
1201 #ifdef DEBUG_THREADS
1202 struct ast_lock_track *lt;
1203 int canlog = strcmp(filename, "logger.c") & t->tracking;
1205 struct ast_bt *bt = NULL;
1208 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1209 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1210 /* Don't warn abount uninitialized lock.
1211 * Simple try to initialize it.
1212 * May be not needed in linux system.
1214 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1215 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1216 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1217 filename, line, func, name);
1221 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1223 if (t->tracking && !t->track) {
1224 ast_reentrancy_init(&t->track);
1230 ast_reentrancy_lock(lt);
1231 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1232 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1233 bt = <->backtrace[lt->reentrancy];
1235 ast_reentrancy_unlock(lt);
1236 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1238 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1241 #endif /* DEBUG_THREADS */
1243 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1244 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1247 struct timeval _now;
1249 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1253 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1261 #ifdef DEBUG_THREADS
1262 if (!res && t->tracking) {
1263 ast_reentrancy_lock(lt);
1264 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1265 lt->file[lt->reentrancy] = filename;
1266 lt->lineno[lt->reentrancy] = line;
1267 lt->func[lt->reentrancy] = func;
1268 lt->thread[lt->reentrancy] = pthread_self();
1271 ast_reentrancy_unlock(lt);
1273 ast_mark_lock_acquired(t);
1275 } else if (t->tracking) {
1277 if (lt->reentrancy) {
1278 ast_reentrancy_lock(lt);
1279 bt = <->backtrace[lt->reentrancy-1];
1280 ast_reentrancy_unlock(lt);
1285 ast_remove_lock_info(t, bt);
1289 ast_remove_lock_info(t);
1294 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1295 filename, line, func, strerror(res));
1298 #endif /* DEBUG_THREADS */
1303 int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1307 #ifdef DEBUG_THREADS
1308 struct ast_lock_track *lt;
1310 struct ast_bt *bt = NULL;
1312 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1313 int canlog = strcmp(filename, "logger.c") & t->tracking;
1315 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1316 /* Don't warn abount uninitialized lock.
1317 * Simple try to initialize it.
1318 * May be not needed in linux system.
1320 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1321 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1322 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1323 filename, line, func, name);
1327 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1329 if (t->tracking && !t->track) {
1330 ast_reentrancy_init(&t->track);
1336 ast_reentrancy_lock(lt);
1337 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1338 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1339 bt = <->backtrace[lt->reentrancy];
1341 ast_reentrancy_unlock(lt);
1342 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1344 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
1347 #endif /* DEBUG_THREADS */
1349 res = pthread_rwlock_tryrdlock(&t->lock);
1351 #ifdef DEBUG_THREADS
1352 if (!res && t->tracking) {
1353 ast_reentrancy_lock(lt);
1354 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1355 lt->file[lt->reentrancy] = filename;
1356 lt->lineno[lt->reentrancy] = line;
1357 lt->func[lt->reentrancy] = func;
1358 lt->thread[lt->reentrancy] = pthread_self();
1361 ast_reentrancy_unlock(lt);
1363 ast_mark_lock_acquired(t);
1365 } else if (t->tracking) {
1366 ast_mark_lock_failed(t);
1368 #endif /* DEBUG_THREADS */
1373 int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1377 #ifdef DEBUG_THREADS
1378 struct ast_lock_track *lt;
1380 struct ast_bt *bt = NULL;
1382 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1383 int canlog = strcmp(filename, "logger.c") & t->tracking;
1385 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1386 /* Don't warn abount uninitialized lock.
1387 * Simple try to initialize it.
1388 * May be not needed in linux system.
1390 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1391 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1392 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1393 filename, line, func, name);
1397 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1399 if (t->tracking && !t->track) {
1400 ast_reentrancy_init(&t->track);
1406 ast_reentrancy_lock(lt);
1407 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1408 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1409 bt = <->backtrace[lt->reentrancy];
1411 ast_reentrancy_unlock(lt);
1412 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1414 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1417 #endif /* DEBUG_THREADS */
1419 res = pthread_rwlock_trywrlock(&t->lock);
1421 #ifdef DEBUG_THREADS
1422 if (!res && t->tracking) {
1423 ast_reentrancy_lock(lt);
1424 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1425 lt->file[lt->reentrancy] = filename;
1426 lt->lineno[lt->reentrancy] = line;
1427 lt->func[lt->reentrancy] = func;
1428 lt->thread[lt->reentrancy] = pthread_self();
1431 ast_reentrancy_unlock(lt);
1432 ast_mark_lock_acquired(t);
1433 } else if (t->tracking) {
1434 ast_mark_lock_failed(t);
1436 #endif /* DEBUG_THREADS */