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.
26 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
28 #include "asterisk/lock.h"
30 /* Allow direct use of pthread_mutex_* / pthread_cond_* */
31 #undef pthread_mutex_init
32 #undef pthread_mutex_destroy
33 #undef pthread_mutex_lock
34 #undef pthread_mutex_trylock
35 #undef pthread_mutex_t
36 #undef pthread_mutex_unlock
37 #undef pthread_cond_init
38 #undef pthread_cond_signal
39 #undef pthread_cond_broadcast
40 #undef pthread_cond_destroy
41 #undef pthread_cond_wait
42 #undef pthread_cond_timedwait
44 int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func,
45 const char *mutex_name, ast_mutex_t *t)
48 pthread_mutexattr_t attr;
51 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
52 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
54 int canlog = strcmp(filename, "logger.c") & track;
55 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
56 filename, lineno, func, mutex_name);
62 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
64 if ((t->tracking = tracking)) {
65 ast_reentrancy_init(&t->track);
67 #endif /* DEBUG_THREADS */
69 pthread_mutexattr_init(&attr);
70 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
72 res = pthread_mutex_init(&t->mutex, &attr);
73 pthread_mutexattr_destroy(&attr);
77 int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
78 const char *mutex_name, ast_mutex_t *t)
83 struct ast_lock_track *lt;
84 int canlog = strcmp(filename, "logger.c") & t->tracking;
86 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
87 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
88 /* Don't try to uninitialize non initialized mutex
89 * This may no effect on linux
90 * And always ganerate core on *BSD with
92 * This not error condition if the mutex created on the fly.
94 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
95 filename, lineno, func, mutex_name);
100 if (t->tracking && !t->track) {
101 ast_reentrancy_init(&t->track);
105 res = pthread_mutex_trylock(&t->mutex);
108 pthread_mutex_unlock(&t->mutex);
111 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
112 filename, lineno, func, mutex_name);
115 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
116 filename, lineno, func, mutex_name);
118 ast_reentrancy_lock(lt);
119 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
120 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
122 __dump_backtrace(<->backtrace[ROFFSET], canlog);
124 ast_reentrancy_unlock(lt);
128 #endif /* DEBUG_THREADS */
130 res = pthread_mutex_destroy(&t->mutex);
134 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
135 filename, lineno, func, mutex_name, strerror(res));
138 ast_reentrancy_lock(lt);
139 lt->file[0] = filename;
140 lt->lineno[0] = lineno;
145 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
147 ast_reentrancy_unlock(lt);
148 delete_reentrancy_cs(&t->track);
150 #endif /* DEBUG_THREADS */
155 int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
156 const char* mutex_name, ast_mutex_t *t)
161 struct ast_lock_track *lt;
162 int canlog = strcmp(filename, "logger.c") & t->tracking;
164 struct ast_bt *bt = NULL;
167 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
168 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
169 /* Don't warn abount uninitialized mutex.
170 * Simple try to initialize it.
171 * May be not needed in linux system.
173 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
174 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
175 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
176 filename, lineno, func, mutex_name);
180 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
182 if (t->tracking && !t->track) {
183 ast_reentrancy_init(&t->track);
189 ast_reentrancy_lock(lt);
190 if (lt->reentrancy != AST_MAX_REENTRANCY) {
191 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
192 bt = <->backtrace[lt->reentrancy];
194 ast_reentrancy_unlock(lt);
195 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
197 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
200 #endif /* DEBUG_THREADS */
202 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
204 time_t seconds = time(NULL);
205 time_t wait_time, reported_wait = 0;
207 #ifdef HAVE_MTX_PROFILE
208 ast_mark(mtx_prof, 1);
210 res = pthread_mutex_trylock(&t->mutex);
211 #ifdef HAVE_MTX_PROFILE
212 ast_mark(mtx_prof, 0);
215 wait_time = time(NULL) - seconds;
216 if (wait_time > reported_wait && (wait_time % 5) == 0) {
217 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
218 filename, lineno, func, (int) wait_time, mutex_name);
219 ast_reentrancy_lock(lt);
221 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
223 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
224 lt->file[ROFFSET], lt->lineno[ROFFSET],
225 lt->func[ROFFSET], mutex_name);
227 __dump_backtrace(<->backtrace[ROFFSET], canlog);
229 ast_reentrancy_unlock(lt);
230 reported_wait = wait_time;
234 } while (res == EBUSY);
236 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
237 #ifdef HAVE_MTX_PROFILE
238 ast_mark(mtx_prof, 1);
239 res = pthread_mutex_trylock(&t->mutex);
240 ast_mark(mtx_prof, 0);
243 res = pthread_mutex_lock(&t->mutex);
244 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
247 if (t->tracking && !res) {
248 ast_reentrancy_lock(lt);
249 if (lt->reentrancy < AST_MAX_REENTRANCY) {
250 lt->file[lt->reentrancy] = filename;
251 lt->lineno[lt->reentrancy] = lineno;
252 lt->func[lt->reentrancy] = func;
253 lt->thread[lt->reentrancy] = pthread_self();
256 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
257 filename, lineno, func, mutex_name);
259 ast_reentrancy_unlock(lt);
261 ast_mark_lock_acquired(t);
263 } else if (t->tracking) {
265 if (lt->reentrancy) {
266 ast_reentrancy_lock(lt);
267 bt = <->backtrace[lt->reentrancy-1];
268 ast_reentrancy_unlock(lt);
272 ast_remove_lock_info(t, bt);
274 ast_remove_lock_info(t);
278 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
279 filename, lineno, func, strerror(res));
282 #endif /* DEBUG_THREADS */
287 int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
288 const char* mutex_name, ast_mutex_t *t)
293 struct ast_lock_track *lt;
294 int canlog = strcmp(filename, "logger.c") & t->tracking;
296 struct ast_bt *bt = NULL;
299 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
300 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
301 /* Don't warn abount uninitialized mutex.
302 * Simple try to initialize it.
303 * May be not needed in linux system.
305 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
306 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
307 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
308 filename, lineno, func, mutex_name);
312 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
314 if (t->tracking && !t->track) {
315 ast_reentrancy_init(&t->track);
321 ast_reentrancy_lock(lt);
322 if (lt->reentrancy != AST_MAX_REENTRANCY) {
323 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
324 bt = <->backtrace[lt->reentrancy];
326 ast_reentrancy_unlock(lt);
327 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
329 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
332 #endif /* DEBUG_THREADS */
334 res = pthread_mutex_trylock(&t->mutex);
337 if (t->tracking && !res) {
338 ast_reentrancy_lock(lt);
339 if (lt->reentrancy < AST_MAX_REENTRANCY) {
340 lt->file[lt->reentrancy] = filename;
341 lt->lineno[lt->reentrancy] = lineno;
342 lt->func[lt->reentrancy] = func;
343 lt->thread[lt->reentrancy] = pthread_self();
346 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
347 filename, lineno, func, mutex_name);
349 ast_reentrancy_unlock(lt);
351 ast_mark_lock_acquired(t);
353 } else if (t->tracking) {
354 ast_mark_lock_failed(t);
356 #endif /* DEBUG_THREADS */
361 int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
362 const char *mutex_name, ast_mutex_t *t)
367 struct ast_lock_track *lt;
368 int canlog = strcmp(filename, "logger.c") & t->tracking;
370 struct ast_bt *bt = NULL;
373 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
374 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
375 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
376 filename, lineno, func, mutex_name);
377 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
378 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
379 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
380 filename, lineno, func, mutex_name);
384 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
386 if (t->tracking && !t->track) {
387 ast_reentrancy_init(&t->track);
392 ast_reentrancy_lock(lt);
393 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
394 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
395 filename, lineno, func, mutex_name);
396 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
397 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
399 __dump_backtrace(<->backtrace[ROFFSET], canlog);
404 if (--lt->reentrancy < 0) {
405 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
406 filename, lineno, func, mutex_name);
410 if (lt->reentrancy < AST_MAX_REENTRANCY) {
411 lt->file[lt->reentrancy] = NULL;
412 lt->lineno[lt->reentrancy] = 0;
413 lt->func[lt->reentrancy] = NULL;
414 lt->thread[lt->reentrancy] = 0;
418 if (lt->reentrancy) {
419 bt = <->backtrace[lt->reentrancy - 1];
422 ast_reentrancy_unlock(lt);
425 ast_remove_lock_info(t, bt);
427 ast_remove_lock_info(t);
430 #endif /* DEBUG_THREADS */
432 res = pthread_mutex_unlock(&t->mutex);
436 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
437 filename, lineno, func, strerror(res));
440 #endif /* DEBUG_THREADS */
446 int __ast_cond_init(const char *filename, int lineno, const char *func,
447 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
449 return pthread_cond_init(cond, cond_attr);
452 int __ast_cond_signal(const char *filename, int lineno, const char *func,
453 const char *cond_name, ast_cond_t *cond)
455 return pthread_cond_signal(cond);
458 int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
459 const char *cond_name, ast_cond_t *cond)
461 return pthread_cond_broadcast(cond);
464 int __ast_cond_destroy(const char *filename, int lineno, const char *func,
465 const char *cond_name, ast_cond_t *cond)
467 return pthread_cond_destroy(cond);
470 int __ast_cond_wait(const char *filename, int lineno, const char *func,
471 const char *cond_name, const char *mutex_name,
472 ast_cond_t *cond, ast_mutex_t *t)
477 struct ast_lock_track *lt;
478 int canlog = strcmp(filename, "logger.c") & t->tracking;
480 struct ast_bt *bt = NULL;
483 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
484 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
485 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
486 filename, lineno, func, mutex_name);
487 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
488 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
489 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
490 filename, lineno, func, mutex_name);
494 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
496 if (t->tracking && !t->track) {
497 ast_reentrancy_init(&t->track);
502 ast_reentrancy_lock(lt);
503 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
504 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
505 filename, lineno, func, mutex_name);
506 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
507 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
509 __dump_backtrace(<->backtrace[ROFFSET], canlog);
514 if (--lt->reentrancy < 0) {
515 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
516 filename, lineno, func, mutex_name);
520 if (lt->reentrancy < AST_MAX_REENTRANCY) {
521 lt->file[lt->reentrancy] = NULL;
522 lt->lineno[lt->reentrancy] = 0;
523 lt->func[lt->reentrancy] = NULL;
524 lt->thread[lt->reentrancy] = 0;
528 if (lt->reentrancy) {
529 bt = <->backtrace[lt->reentrancy - 1];
532 ast_reentrancy_unlock(lt);
535 ast_remove_lock_info(t, bt);
537 ast_remove_lock_info(t);
540 #endif /* DEBUG_THREADS */
542 res = pthread_cond_wait(cond, &t->mutex);
546 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
547 filename, lineno, func, strerror(res));
549 } else if (t->tracking) {
550 ast_reentrancy_lock(lt);
551 if (lt->reentrancy < AST_MAX_REENTRANCY) {
552 lt->file[lt->reentrancy] = filename;
553 lt->lineno[lt->reentrancy] = lineno;
554 lt->func[lt->reentrancy] = func;
555 lt->thread[lt->reentrancy] = pthread_self();
557 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
558 bt = <->backtrace[lt->reentrancy];
562 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
563 filename, lineno, func, mutex_name);
565 ast_reentrancy_unlock(lt);
568 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
570 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
573 #endif /* DEBUG_THREADS */
578 int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
579 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
580 ast_mutex_t *t, const struct timespec *abstime)
585 struct ast_lock_track *lt;
586 int canlog = strcmp(filename, "logger.c") & t->tracking;
588 struct ast_bt *bt = NULL;
591 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
592 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
593 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
594 filename, lineno, func, mutex_name);
595 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
596 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
597 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
598 filename, lineno, func, mutex_name);
602 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
604 if (t->tracking && !t->track) {
605 ast_reentrancy_init(&t->track);
610 ast_reentrancy_lock(lt);
611 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
612 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
613 filename, lineno, func, mutex_name);
614 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
615 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
617 __dump_backtrace(<->backtrace[ROFFSET], canlog);
622 if (--lt->reentrancy < 0) {
623 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
624 filename, lineno, func, mutex_name);
628 if (lt->reentrancy < AST_MAX_REENTRANCY) {
629 lt->file[lt->reentrancy] = NULL;
630 lt->lineno[lt->reentrancy] = 0;
631 lt->func[lt->reentrancy] = NULL;
632 lt->thread[lt->reentrancy] = 0;
635 if (lt->reentrancy) {
636 bt = <->backtrace[lt->reentrancy - 1];
639 ast_reentrancy_unlock(lt);
642 ast_remove_lock_info(t, bt);
644 ast_remove_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 ast_reentrancy_lock(lt);
658 if (lt->reentrancy < AST_MAX_REENTRANCY) {
659 lt->file[lt->reentrancy] = filename;
660 lt->lineno[lt->reentrancy] = lineno;
661 lt->func[lt->reentrancy] = func;
662 lt->thread[lt->reentrancy] = pthread_self();
664 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
665 bt = <->backtrace[lt->reentrancy];
669 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
670 filename, lineno, func, mutex_name);
672 ast_reentrancy_unlock(lt);
675 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
677 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
680 #endif /* DEBUG_THREADS */
685 int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
688 pthread_rwlockattr_t attr;
692 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
693 int canlog = strcmp(filename, "logger.c") & t->tracking;
695 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
696 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
697 filename, lineno, func, rwlock_name);
700 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
702 if ((t->tracking = tracking)) {
703 ast_reentrancy_init(&t->track);
705 #endif /* DEBUG_THREADS */
707 pthread_rwlockattr_init(&attr);
709 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
710 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
713 res = pthread_rwlock_init(&t->lock, &attr);
714 pthread_rwlockattr_destroy(&attr);
718 int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
723 struct ast_lock_track *lt = t->track;
724 int canlog = strcmp(filename, "logger.c") & t->tracking;
726 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
727 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
728 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
729 filename, lineno, func, rwlock_name);
732 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
734 #endif /* DEBUG_THREADS */
736 res = pthread_rwlock_destroy(&t->lock);
740 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
741 filename, lineno, func, rwlock_name, strerror(res));
744 ast_reentrancy_lock(lt);
745 lt->file[0] = filename;
746 lt->lineno[0] = lineno;
751 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
753 ast_reentrancy_unlock(lt);
754 delete_reentrancy_cs(&t->track);
756 #endif /* DEBUG_THREADS */
761 int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
766 struct ast_lock_track *lt;
767 int canlog = strcmp(filename, "logger.c") & t->tracking;
769 struct ast_bt *bt = NULL;
774 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
775 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
776 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
777 filename, line, func, name);
778 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
779 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
780 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
781 filename, line, func, name);
785 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
787 if (t->tracking && !t->track) {
788 ast_reentrancy_init(&t->track);
793 ast_reentrancy_lock(lt);
794 if (lt->reentrancy) {
796 pthread_t self = pthread_self();
797 for (i = lt->reentrancy - 1; i >= 0; --i) {
798 if (lt->thread[i] == self) {
800 if (i != lt->reentrancy - 1) {
801 lt->file[i] = lt->file[lt->reentrancy - 1];
802 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
803 lt->func[i] = lt->func[lt->reentrancy - 1];
804 lt->thread[i] = lt->thread[lt->reentrancy - 1];
807 bt = <->backtrace[i];
809 lt->file[lt->reentrancy - 1] = NULL;
810 lt->lineno[lt->reentrancy - 1] = 0;
811 lt->func[lt->reentrancy - 1] = NULL;
812 lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
818 if (lock_found && --lt->reentrancy < 0) {
819 __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
820 filename, line, func, name);
824 ast_reentrancy_unlock(lt);
827 ast_remove_lock_info(t, bt);
829 ast_remove_lock_info(t);
832 #endif /* DEBUG_THREADS */
834 res = pthread_rwlock_unlock(&t->lock);
838 __ast_mutex_logger("%s line %d (%s): Error releasing rwlock: %s\n",
839 filename, line, func, strerror(res));
842 #endif /* DEBUG_THREADS */
847 int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
852 struct ast_lock_track *lt;
853 int canlog = strcmp(filename, "logger.c") & t->tracking;
855 struct ast_bt *bt = NULL;
858 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
859 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
860 /* Don't warn abount uninitialized lock.
861 * Simple try to initialize it.
862 * May be not needed in linux system.
864 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
865 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
866 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
867 filename, line, func, name);
871 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
873 if (t->tracking && !t->track) {
874 ast_reentrancy_init(&t->track);
880 ast_reentrancy_lock(lt);
881 if (lt->reentrancy != AST_MAX_REENTRANCY) {
882 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
883 bt = <->backtrace[lt->reentrancy];
885 ast_reentrancy_unlock(lt);
886 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
888 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
891 #endif /* DEBUG_THREADS */
893 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
895 time_t seconds = time(NULL);
896 time_t wait_time, reported_wait = 0;
898 res = pthread_rwlock_tryrdlock(&t->lock);
900 wait_time = time(NULL) - seconds;
901 if (wait_time > reported_wait && (wait_time % 5) == 0) {
902 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
903 filename, line, func, (int)wait_time, name);
905 ast_reentrancy_lock(lt);
907 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
909 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
910 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
911 lt->func[lt->reentrancy-1], name);
913 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
915 ast_reentrancy_unlock(lt);
917 reported_wait = wait_time;
921 } while (res == EBUSY);
923 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
924 res = pthread_rwlock_rdlock(&t->lock);
925 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
928 if (!res && t->tracking) {
929 ast_reentrancy_lock(lt);
930 if (lt->reentrancy < AST_MAX_REENTRANCY) {
931 lt->file[lt->reentrancy] = filename;
932 lt->lineno[lt->reentrancy] = line;
933 lt->func[lt->reentrancy] = func;
934 lt->thread[lt->reentrancy] = pthread_self();
937 ast_reentrancy_unlock(lt);
939 ast_mark_lock_acquired(t);
941 } else if (t->tracking) {
943 if (lt->reentrancy) {
944 ast_reentrancy_lock(lt);
945 bt = <->backtrace[lt->reentrancy-1];
946 ast_reentrancy_unlock(lt);
950 ast_remove_lock_info(t, bt);
952 ast_remove_lock_info(t);
957 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
958 filename, line, func, strerror(res));
961 #endif /* DEBUG_THREADS */
966 int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
971 struct ast_lock_track *lt;
972 int canlog = strcmp(filename, "logger.c") & t->tracking;
974 struct ast_bt *bt = NULL;
977 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
978 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
979 /* Don't warn abount uninitialized lock.
980 * Simple try to initialize it.
981 * May be not needed in linux system.
983 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
984 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
985 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
986 filename, line, func, name);
990 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
992 if (t->tracking && !t->track) {
993 ast_reentrancy_init(&t->track);
999 ast_reentrancy_lock(lt);
1000 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1001 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1002 bt = <->backtrace[lt->reentrancy];
1004 ast_reentrancy_unlock(lt);
1005 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1007 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1010 #endif /* DEBUG_THREADS */
1012 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
1014 time_t seconds = time(NULL);
1015 time_t wait_time, reported_wait = 0;
1017 res = pthread_rwlock_trywrlock(&t->lock);
1019 wait_time = time(NULL) - seconds;
1020 if (wait_time > reported_wait && (wait_time % 5) == 0) {
1021 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
1022 filename, line, func, (int)wait_time, name);
1024 ast_reentrancy_lock(lt);
1026 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
1028 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
1029 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1030 lt->func[lt->reentrancy-1], name);
1032 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
1034 ast_reentrancy_unlock(lt);
1036 reported_wait = wait_time;
1040 } while (res == EBUSY);
1042 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1043 res = pthread_rwlock_wrlock(&t->lock);
1044 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1046 #ifdef DEBUG_THREADS
1047 if (!res && t->tracking) {
1048 ast_reentrancy_lock(lt);
1049 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1050 lt->file[lt->reentrancy] = filename;
1051 lt->lineno[lt->reentrancy] = line;
1052 lt->func[lt->reentrancy] = func;
1053 lt->thread[lt->reentrancy] = pthread_self();
1056 ast_reentrancy_unlock(lt);
1058 ast_mark_lock_acquired(t);
1060 } else if (t->tracking) {
1062 if (lt->reentrancy) {
1063 ast_reentrancy_lock(lt);
1064 bt = <->backtrace[lt->reentrancy-1];
1065 ast_reentrancy_unlock(lt);
1070 ast_remove_lock_info(t, bt);
1074 ast_remove_lock_info(t);
1079 __ast_mutex_logger("%s line %d (%s): Error obtaining write lock: %s\n",
1080 filename, line, func, strerror(res));
1083 #endif /* DEBUG_THREADS */
1088 int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1089 const struct timespec *abs_timeout)
1093 #ifdef DEBUG_THREADS
1094 struct ast_lock_track *lt;
1095 int canlog = strcmp(filename, "logger.c") & t->tracking;
1097 struct ast_bt *bt = NULL;
1100 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1101 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1102 /* Don't warn abount uninitialized lock.
1103 * Simple try to initialize it.
1104 * May be not needed in linux system.
1106 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1107 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1108 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1109 filename, line, func, name);
1113 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1115 if (t->tracking && !t->track) {
1116 ast_reentrancy_init(&t->track);
1122 ast_reentrancy_lock(lt);
1123 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1124 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1125 bt = <->backtrace[lt->reentrancy];
1127 ast_reentrancy_unlock(lt);
1128 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1130 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1133 #endif /* DEBUG_THREADS */
1135 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1136 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1139 struct timeval _start = ast_tvnow(), _diff;
1141 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1144 _diff = ast_tvsub(ast_tvnow(), _start);
1145 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1153 #ifdef DEBUG_THREADS
1154 if (!res && t->tracking) {
1155 ast_reentrancy_lock(lt);
1156 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1157 lt->file[lt->reentrancy] = filename;
1158 lt->lineno[lt->reentrancy] = line;
1159 lt->func[lt->reentrancy] = func;
1160 lt->thread[lt->reentrancy] = pthread_self();
1163 ast_reentrancy_unlock(lt);
1165 ast_mark_lock_acquired(t);
1167 } else if (t->tracking) {
1169 if (lt->reentrancy) {
1170 ast_reentrancy_lock(lt);
1171 bt = <->backtrace[lt->reentrancy-1];
1172 ast_reentrancy_unlock(lt);
1176 ast_remove_lock_info(t, bt);
1178 ast_remove_lock_info(t);
1182 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1183 filename, line, func, strerror(res));
1186 #endif /* DEBUG_THREADS */
1191 int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1192 const struct timespec *abs_timeout)
1196 #ifdef DEBUG_THREADS
1197 struct ast_lock_track *lt;
1198 int canlog = strcmp(filename, "logger.c") & t->tracking;
1200 struct ast_bt *bt = NULL;
1203 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1204 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1205 /* Don't warn abount uninitialized lock.
1206 * Simple try to initialize it.
1207 * May be not needed in linux system.
1209 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1210 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1211 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1212 filename, line, func, name);
1216 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1218 if (t->tracking && !t->track) {
1219 ast_reentrancy_init(&t->track);
1225 ast_reentrancy_lock(lt);
1226 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1227 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1228 bt = <->backtrace[lt->reentrancy];
1230 ast_reentrancy_unlock(lt);
1231 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1233 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1236 #endif /* DEBUG_THREADS */
1238 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1239 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1242 struct timeval _start = ast_tvnow(), _diff;
1244 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1247 _diff = ast_tvsub(ast_tvnow(), _start);
1248 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1256 #ifdef DEBUG_THREADS
1257 if (!res && t->tracking) {
1258 ast_reentrancy_lock(lt);
1259 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1260 lt->file[lt->reentrancy] = filename;
1261 lt->lineno[lt->reentrancy] = line;
1262 lt->func[lt->reentrancy] = func;
1263 lt->thread[lt->reentrancy] = pthread_self();
1266 ast_reentrancy_unlock(lt);
1268 ast_mark_lock_acquired(t);
1270 } else if (t->tracking) {
1272 if (lt->reentrancy) {
1273 ast_reentrancy_lock(lt);
1274 bt = <->backtrace[lt->reentrancy-1];
1275 ast_reentrancy_unlock(lt);
1280 ast_remove_lock_info(t, bt);
1284 ast_remove_lock_info(t);
1289 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1290 filename, line, func, strerror(res));
1293 #endif /* DEBUG_THREADS */
1298 int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1302 #ifdef DEBUG_THREADS
1303 struct ast_lock_track *lt;
1305 struct ast_bt *bt = NULL;
1307 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1308 int canlog = strcmp(filename, "logger.c") & t->tracking;
1310 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1311 /* Don't warn abount uninitialized lock.
1312 * Simple try to initialize it.
1313 * May be not needed in linux system.
1315 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1316 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1317 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1318 filename, line, func, name);
1322 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1324 if (t->tracking && !t->track) {
1325 ast_reentrancy_init(&t->track);
1331 ast_reentrancy_lock(lt);
1332 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1333 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1334 bt = <->backtrace[lt->reentrancy];
1336 ast_reentrancy_unlock(lt);
1337 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1339 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
1342 #endif /* DEBUG_THREADS */
1344 res = pthread_rwlock_tryrdlock(&t->lock);
1346 #ifdef DEBUG_THREADS
1347 if (!res && t->tracking) {
1348 ast_reentrancy_lock(lt);
1349 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1350 lt->file[lt->reentrancy] = filename;
1351 lt->lineno[lt->reentrancy] = line;
1352 lt->func[lt->reentrancy] = func;
1353 lt->thread[lt->reentrancy] = pthread_self();
1356 ast_reentrancy_unlock(lt);
1358 ast_mark_lock_acquired(t);
1360 } else if (t->tracking) {
1361 ast_mark_lock_failed(t);
1363 #endif /* DEBUG_THREADS */
1368 int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1372 #ifdef DEBUG_THREADS
1373 struct ast_lock_track *lt;
1375 struct ast_bt *bt = NULL;
1377 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1378 int canlog = strcmp(filename, "logger.c") & t->tracking;
1380 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1381 /* Don't warn abount uninitialized lock.
1382 * Simple try to initialize it.
1383 * May be not needed in linux system.
1385 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1386 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1387 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1388 filename, line, func, name);
1392 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1394 if (t->tracking && !t->track) {
1395 ast_reentrancy_init(&t->track);
1401 ast_reentrancy_lock(lt);
1402 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1403 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1404 bt = <->backtrace[lt->reentrancy];
1406 ast_reentrancy_unlock(lt);
1407 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1409 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1412 #endif /* DEBUG_THREADS */
1414 res = pthread_rwlock_trywrlock(&t->lock);
1416 #ifdef DEBUG_THREADS
1417 if (!res && t->tracking) {
1418 ast_reentrancy_lock(lt);
1419 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1420 lt->file[lt->reentrancy] = filename;
1421 lt->lineno[lt->reentrancy] = line;
1422 lt->func[lt->reentrancy] = func;
1423 lt->thread[lt->reentrancy] = pthread_self();
1426 ast_reentrancy_unlock(lt);
1427 ast_mark_lock_acquired(t);
1428 } else if (t->tracking) {
1429 ast_mark_lock_failed(t);
1431 #endif /* DEBUG_THREADS */