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 ast_reentrancy_init(&t->track);
65 t->tracking = tracking;
66 #endif /* DEBUG_THREADS */
68 pthread_mutexattr_init(&attr);
69 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
71 res = pthread_mutex_init(&t->mutex, &attr);
72 pthread_mutexattr_destroy(&attr);
76 int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
77 const char *mutex_name, ast_mutex_t *t)
82 struct ast_lock_track *lt;
83 int canlog = strcmp(filename, "logger.c") & t->tracking;
85 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
86 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
87 /* Don't try to uninitialize non initialized mutex
88 * This may no effect on linux
89 * And always ganerate core on *BSD with
91 * This not error condition if the mutex created on the fly.
93 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
94 filename, lineno, func, mutex_name);
101 res = pthread_mutex_trylock(&t->mutex);
104 pthread_mutex_unlock(&t->mutex);
107 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
108 filename, lineno, func, mutex_name);
111 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
112 filename, lineno, func, mutex_name);
113 ast_reentrancy_lock(lt);
114 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
115 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
117 __dump_backtrace(<->backtrace[ROFFSET], canlog);
119 ast_reentrancy_unlock(lt);
122 #endif /* DEBUG_THREADS */
124 res = pthread_mutex_destroy(&t->mutex);
128 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
129 filename, lineno, func, mutex_name, strerror(res));
131 ast_reentrancy_lock(lt);
132 lt->file[0] = filename;
133 lt->lineno[0] = lineno;
138 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
140 ast_reentrancy_unlock(lt);
141 delete_reentrancy_cs(lt);
142 #endif /* DEBUG_THREADS */
147 int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
148 const char* mutex_name, ast_mutex_t *t)
153 struct ast_lock_track *lt = &t->track;
154 int canlog = strcmp(filename, "logger.c") & t->tracking;
156 struct ast_bt *bt = NULL;
159 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
160 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
161 /* Don't warn abount uninitialized mutex.
162 * Simple try to initialize it.
163 * May be not needed in linux system.
165 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
166 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
167 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
168 filename, lineno, func, mutex_name);
172 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
176 ast_reentrancy_lock(lt);
177 if (lt->reentrancy != AST_MAX_REENTRANCY) {
178 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
179 bt = <->backtrace[lt->reentrancy];
181 ast_reentrancy_unlock(lt);
182 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
184 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
187 #endif /* DEBUG_THREADS */
189 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
191 time_t seconds = time(NULL);
192 time_t wait_time, reported_wait = 0;
194 #ifdef HAVE_MTX_PROFILE
195 ast_mark(mtx_prof, 1);
197 res = pthread_mutex_trylock(&t->mutex);
198 #ifdef HAVE_MTX_PROFILE
199 ast_mark(mtx_prof, 0);
202 wait_time = time(NULL) - seconds;
203 if (wait_time > reported_wait && (wait_time % 5) == 0) {
204 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
205 filename, lineno, func, (int) wait_time, mutex_name);
206 ast_reentrancy_lock(lt);
208 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
210 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
211 lt->file[ROFFSET], lt->lineno[ROFFSET],
212 lt->func[ROFFSET], mutex_name);
214 __dump_backtrace(<->backtrace[ROFFSET], canlog);
216 ast_reentrancy_unlock(lt);
217 reported_wait = wait_time;
221 } while (res == EBUSY);
223 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
224 #ifdef HAVE_MTX_PROFILE
225 ast_mark(mtx_prof, 1);
226 res = pthread_mutex_trylock(&t->mutex);
227 ast_mark(mtx_prof, 0);
230 res = pthread_mutex_lock(&t->mutex);
231 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
235 ast_reentrancy_lock(lt);
236 if (lt->reentrancy < AST_MAX_REENTRANCY) {
237 lt->file[lt->reentrancy] = filename;
238 lt->lineno[lt->reentrancy] = lineno;
239 lt->func[lt->reentrancy] = func;
240 lt->thread[lt->reentrancy] = pthread_self();
243 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
244 filename, lineno, func, mutex_name);
246 ast_reentrancy_unlock(lt);
248 ast_mark_lock_acquired(t);
252 if (lt->reentrancy) {
253 ast_reentrancy_lock(lt);
254 bt = <->backtrace[lt->reentrancy-1];
255 ast_reentrancy_unlock(lt);
260 ast_remove_lock_info(t, bt);
264 ast_remove_lock_info(t);
267 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
268 filename, lineno, func, strerror(res));
271 #endif /* DEBUG_THREADS */
276 int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
277 const char* mutex_name, ast_mutex_t *t)
282 struct ast_lock_track *lt= &t->track;
283 int canlog = strcmp(filename, "logger.c") & t->tracking;
285 struct ast_bt *bt = NULL;
288 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
289 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
290 /* Don't warn abount uninitialized mutex.
291 * Simple try to initialize it.
292 * May be not needed in linux system.
294 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
295 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
296 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
297 filename, lineno, func, mutex_name);
301 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
305 ast_reentrancy_lock(lt);
306 if (lt->reentrancy != AST_MAX_REENTRANCY) {
307 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
308 bt = <->backtrace[lt->reentrancy];
310 ast_reentrancy_unlock(lt);
311 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
313 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
316 #endif /* DEBUG_THREADS */
318 res = pthread_mutex_trylock(&t->mutex);
322 ast_reentrancy_lock(lt);
323 if (lt->reentrancy < AST_MAX_REENTRANCY) {
324 lt->file[lt->reentrancy] = filename;
325 lt->lineno[lt->reentrancy] = lineno;
326 lt->func[lt->reentrancy] = func;
327 lt->thread[lt->reentrancy] = pthread_self();
330 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
331 filename, lineno, func, mutex_name);
333 ast_reentrancy_unlock(lt);
335 ast_mark_lock_acquired(t);
337 } else if (t->tracking) {
338 ast_mark_lock_failed(t);
340 #endif /* DEBUG_THREADS */
345 int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
346 const char *mutex_name, ast_mutex_t *t)
351 struct ast_lock_track *lt = &t->track;
352 int canlog = strcmp(filename, "logger.c") & t->tracking;
354 struct ast_bt *bt = NULL;
357 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
358 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
359 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
360 filename, lineno, func, mutex_name);
361 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
362 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
363 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
364 filename, lineno, func, mutex_name);
368 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
370 ast_reentrancy_lock(lt);
371 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
372 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
373 filename, lineno, func, mutex_name);
374 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
375 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
377 __dump_backtrace(<->backtrace[ROFFSET], canlog);
382 if (--lt->reentrancy < 0) {
383 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
384 filename, lineno, func, mutex_name);
388 if (lt->reentrancy < AST_MAX_REENTRANCY) {
389 lt->file[lt->reentrancy] = NULL;
390 lt->lineno[lt->reentrancy] = 0;
391 lt->func[lt->reentrancy] = NULL;
392 lt->thread[lt->reentrancy] = 0;
396 if (lt->reentrancy) {
397 bt = <->backtrace[lt->reentrancy - 1];
400 ast_reentrancy_unlock(lt);
404 ast_remove_lock_info(t, bt);
406 ast_remove_lock_info(t);
409 #endif /* DEBUG_THREADS */
411 res = pthread_mutex_unlock(&t->mutex);
415 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
416 filename, lineno, func, strerror(res));
419 #endif /* DEBUG_THREADS */
425 int __ast_cond_init(const char *filename, int lineno, const char *func,
426 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
428 return pthread_cond_init(cond, cond_attr);
431 int __ast_cond_signal(const char *filename, int lineno, const char *func,
432 const char *cond_name, ast_cond_t *cond)
434 return pthread_cond_signal(cond);
437 int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
438 const char *cond_name, ast_cond_t *cond)
440 return pthread_cond_broadcast(cond);
443 int __ast_cond_destroy(const char *filename, int lineno, const char *func,
444 const char *cond_name, ast_cond_t *cond)
446 return pthread_cond_destroy(cond);
449 int __ast_cond_wait(const char *filename, int lineno, const char *func,
450 const char *cond_name, const char *mutex_name,
451 ast_cond_t *cond, ast_mutex_t *t)
456 struct ast_lock_track *lt= &t->track;
457 int canlog = strcmp(filename, "logger.c") & t->tracking;
459 struct ast_bt *bt = NULL;
462 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
463 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
464 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
465 filename, lineno, func, mutex_name);
466 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
467 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
468 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
469 filename, lineno, func, mutex_name);
473 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
475 ast_reentrancy_lock(lt);
476 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
477 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
478 filename, lineno, func, mutex_name);
479 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
480 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
482 __dump_backtrace(<->backtrace[ROFFSET], canlog);
487 if (--lt->reentrancy < 0) {
488 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
489 filename, lineno, func, mutex_name);
493 if (lt->reentrancy < AST_MAX_REENTRANCY) {
494 lt->file[lt->reentrancy] = NULL;
495 lt->lineno[lt->reentrancy] = 0;
496 lt->func[lt->reentrancy] = NULL;
497 lt->thread[lt->reentrancy] = 0;
501 if (lt->reentrancy) {
502 bt = <->backtrace[lt->reentrancy - 1];
505 ast_reentrancy_unlock(lt);
509 ast_remove_lock_info(t, bt);
511 ast_remove_lock_info(t);
514 #endif /* DEBUG_THREADS */
516 res = pthread_cond_wait(cond, &t->mutex);
520 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
521 filename, lineno, func, strerror(res));
524 ast_reentrancy_lock(lt);
525 if (lt->reentrancy < AST_MAX_REENTRANCY) {
526 lt->file[lt->reentrancy] = filename;
527 lt->lineno[lt->reentrancy] = lineno;
528 lt->func[lt->reentrancy] = func;
529 lt->thread[lt->reentrancy] = pthread_self();
531 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
532 bt = <->backtrace[lt->reentrancy];
536 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
537 filename, lineno, func, mutex_name);
539 ast_reentrancy_unlock(lt);
543 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
545 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
549 #endif /* DEBUG_THREADS */
554 int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
555 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
556 ast_mutex_t *t, const struct timespec *abstime)
561 struct ast_lock_track *lt = &t->track;
562 int canlog = strcmp(filename, "logger.c") & t->tracking;
564 struct ast_bt *bt = NULL;
567 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
568 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
569 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
570 filename, lineno, func, mutex_name);
571 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
572 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
573 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
574 filename, lineno, func, mutex_name);
578 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
580 ast_reentrancy_lock(lt);
581 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
582 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
583 filename, lineno, func, mutex_name);
584 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
585 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
587 __dump_backtrace(<->backtrace[ROFFSET], canlog);
592 if (--lt->reentrancy < 0) {
593 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
594 filename, lineno, func, mutex_name);
598 if (lt->reentrancy < AST_MAX_REENTRANCY) {
599 lt->file[lt->reentrancy] = NULL;
600 lt->lineno[lt->reentrancy] = 0;
601 lt->func[lt->reentrancy] = NULL;
602 lt->thread[lt->reentrancy] = 0;
605 if (lt->reentrancy) {
606 bt = <->backtrace[lt->reentrancy - 1];
609 ast_reentrancy_unlock(lt);
613 ast_remove_lock_info(t, bt);
615 ast_remove_lock_info(t);
618 #endif /* DEBUG_THREADS */
620 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
623 if (res && (res != ETIMEDOUT)) {
624 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
625 filename, lineno, func, strerror(res));
628 ast_reentrancy_lock(lt);
629 if (lt->reentrancy < AST_MAX_REENTRANCY) {
630 lt->file[lt->reentrancy] = filename;
631 lt->lineno[lt->reentrancy] = lineno;
632 lt->func[lt->reentrancy] = func;
633 lt->thread[lt->reentrancy] = pthread_self();
635 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
636 bt = <->backtrace[lt->reentrancy];
640 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
641 filename, lineno, func, mutex_name);
643 ast_reentrancy_unlock(lt);
647 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
649 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
653 #endif /* DEBUG_THREADS */
658 int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
661 pthread_rwlockattr_t attr;
664 struct ast_lock_track *lt= &t->track;
666 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
667 int canlog = strcmp(filename, "logger.c") & t->tracking;
669 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
670 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
671 filename, lineno, func, rwlock_name);
674 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
676 ast_reentrancy_init(lt);
677 t->tracking = tracking;
678 #endif /* DEBUG_THREADS */
680 pthread_rwlockattr_init(&attr);
682 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
683 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
686 res = pthread_rwlock_init(&t->lock, &attr);
687 pthread_rwlockattr_destroy(&attr);
691 int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
696 struct ast_lock_track *lt = &t->track;
697 int canlog = strcmp(filename, "logger.c") & t->tracking;
699 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
700 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
701 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
702 filename, lineno, func, rwlock_name);
705 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
707 #endif /* DEBUG_THREADS */
709 res = pthread_rwlock_destroy(&t->lock);
713 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
714 filename, lineno, func, rwlock_name, strerror(res));
716 ast_reentrancy_lock(lt);
717 lt->file[0] = filename;
718 lt->lineno[0] = lineno;
723 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
725 ast_reentrancy_unlock(lt);
726 delete_reentrancy_cs(lt);
727 #endif /* DEBUG_THREADS */
732 int __ast_rwlock_unlock(ast_rwlock_t *t, const char *name,
733 const char *filename, int line, const char *func)
738 struct ast_lock_track *lt = &t->track;
739 int canlog = strcmp(filename, "logger.c") & t->tracking;
741 struct ast_bt *bt = NULL;
746 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
747 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
748 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
749 filename, line, func, name);
750 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
751 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
752 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
753 filename, line, func, name);
757 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
759 ast_reentrancy_lock(lt);
760 if (lt->reentrancy) {
762 pthread_t self = pthread_self();
763 for (i = lt->reentrancy - 1; i >= 0; --i) {
764 if (lt->thread[i] == self) {
766 if (i != lt->reentrancy - 1) {
767 lt->file[i] = lt->file[lt->reentrancy - 1];
768 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
769 lt->func[i] = lt->func[lt->reentrancy - 1];
770 lt->thread[i] = lt->thread[lt->reentrancy - 1];
773 bt = <->backtrace[i];
775 lt->file[lt->reentrancy - 1] = NULL;
776 lt->lineno[lt->reentrancy - 1] = 0;
777 lt->func[lt->reentrancy - 1] = NULL;
778 lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
784 if (lock_found && --lt->reentrancy < 0) {
785 __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
786 filename, line, func, name);
790 ast_reentrancy_unlock(lt);
794 ast_remove_lock_info(t, bt);
796 ast_remove_lock_info(t);
799 #endif /* DEBUG_THREADS */
801 res = pthread_rwlock_unlock(&t->lock);
805 __ast_mutex_logger("%s line %d (%s): Error releasing rwlock: %s\n",
806 filename, line, func, strerror(res));
809 #endif /* DEBUG_THREADS */
814 int __ast_rwlock_rdlock(ast_rwlock_t *t, const char *name,
815 const char *filename, int line, const char *func)
820 struct ast_lock_track *lt = &t->track;
821 int canlog = strcmp(filename, "logger.c") & t->tracking;
823 struct ast_bt *bt = NULL;
826 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
827 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
828 /* Don't warn abount uninitialized lock.
829 * Simple try to initialize it.
830 * May be not needed in linux system.
832 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
833 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
834 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
835 filename, line, func, name);
839 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
843 ast_reentrancy_lock(lt);
844 if (lt->reentrancy != AST_MAX_REENTRANCY) {
845 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
846 bt = <->backtrace[lt->reentrancy];
848 ast_reentrancy_unlock(lt);
849 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
851 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
854 #endif /* DEBUG_THREADS */
856 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
858 time_t seconds = time(NULL);
859 time_t wait_time, reported_wait = 0;
861 res = pthread_rwlock_tryrdlock(&t->lock);
863 wait_time = time(NULL) - seconds;
864 if (wait_time > reported_wait && (wait_time % 5) == 0) {
865 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
866 filename, line, func, (int)wait_time, name);
867 ast_reentrancy_lock(lt);
869 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
871 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
872 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
873 lt->func[lt->reentrancy-1], name);
875 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
877 ast_reentrancy_unlock(lt);
878 reported_wait = wait_time;
882 } while (res == EBUSY);
884 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
885 res = pthread_rwlock_rdlock(&t->lock);
886 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
890 ast_reentrancy_lock(lt);
891 if (lt->reentrancy < AST_MAX_REENTRANCY) {
892 lt->file[lt->reentrancy] = filename;
893 lt->lineno[lt->reentrancy] = line;
894 lt->func[lt->reentrancy] = func;
895 lt->thread[lt->reentrancy] = pthread_self();
898 ast_reentrancy_unlock(lt);
900 ast_mark_lock_acquired(t);
904 if (lt->reentrancy) {
905 ast_reentrancy_lock(lt);
906 bt = <->backtrace[lt->reentrancy-1];
907 ast_reentrancy_unlock(lt);
912 ast_remove_lock_info(t, bt);
916 ast_remove_lock_info(t);
919 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
920 filename, line, func, strerror(res));
923 #endif /* DEBUG_THREADS */
928 int __ast_rwlock_wrlock(ast_rwlock_t *t, const char *name,
929 const char *filename, int line, const char *func)
934 struct ast_lock_track *lt = &t->track;
935 int canlog = strcmp(filename, "logger.c") & t->tracking;
937 struct ast_bt *bt = NULL;
940 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
941 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
942 /* Don't warn abount uninitialized lock.
943 * Simple try to initialize it.
944 * May be not needed in linux system.
946 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
947 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
948 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
949 filename, line, func, name);
953 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
957 ast_reentrancy_lock(lt);
958 if (lt->reentrancy != AST_MAX_REENTRANCY) {
959 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
960 bt = <->backtrace[lt->reentrancy];
962 ast_reentrancy_unlock(lt);
963 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
965 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
968 #endif /* DEBUG_THREADS */
970 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
972 time_t seconds = time(NULL);
973 time_t wait_time, reported_wait = 0;
975 res = pthread_rwlock_trywrlock(&t->lock);
977 wait_time = time(NULL) - seconds;
978 if (wait_time > reported_wait && (wait_time % 5) == 0) {
979 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
980 filename, line, func, (int)wait_time, name);
981 ast_reentrancy_lock(lt);
983 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
985 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
986 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
987 lt->func[lt->reentrancy-1], name);
989 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
991 ast_reentrancy_unlock(lt);
992 reported_wait = wait_time;
996 } while (res == EBUSY);
998 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
999 res = pthread_rwlock_wrlock(&t->lock);
1000 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1002 #ifdef DEBUG_THREADS
1004 ast_reentrancy_lock(lt);
1005 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1006 lt->file[lt->reentrancy] = filename;
1007 lt->lineno[lt->reentrancy] = line;
1008 lt->func[lt->reentrancy] = func;
1009 lt->thread[lt->reentrancy] = pthread_self();
1012 ast_reentrancy_unlock(lt);
1014 ast_mark_lock_acquired(t);
1018 if (lt->reentrancy) {
1019 ast_reentrancy_lock(lt);
1020 bt = <->backtrace[lt->reentrancy-1];
1021 ast_reentrancy_unlock(lt);
1026 ast_remove_lock_info(t, bt);
1030 ast_remove_lock_info(t);
1033 __ast_mutex_logger("%s line %d (%s): Error obtaining write lock: %s\n",
1034 filename, line, func, strerror(res));
1037 #endif /* DEBUG_THREADS */
1042 int __ast_rwlock_timedrdlock(ast_rwlock_t *t, const char *name,
1043 const struct timespec *abs_timeout, const char *filename, int line, const char *func)
1047 #ifdef DEBUG_THREADS
1048 struct ast_lock_track *lt = &t->track;
1049 int canlog = strcmp(filename, "logger.c") & t->tracking;
1051 struct ast_bt *bt = NULL;
1054 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1055 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1056 /* Don't warn abount uninitialized lock.
1057 * Simple try to initialize it.
1058 * May be not needed in linux system.
1060 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1061 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1062 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1063 filename, line, func, name);
1067 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1071 ast_reentrancy_lock(lt);
1072 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1073 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1074 bt = <->backtrace[lt->reentrancy];
1076 ast_reentrancy_unlock(lt);
1077 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1079 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1082 #endif /* DEBUG_THREADS */
1084 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1085 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1088 struct timeval _start = ast_tvnow(), _diff;
1090 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1093 _diff = ast_tvsub(ast_tvnow(), _start);
1094 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1102 #ifdef DEBUG_THREADS
1104 ast_reentrancy_lock(lt);
1105 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1106 lt->file[lt->reentrancy] = filename;
1107 lt->lineno[lt->reentrancy] = line;
1108 lt->func[lt->reentrancy] = func;
1109 lt->thread[lt->reentrancy] = pthread_self();
1112 ast_reentrancy_unlock(lt);
1114 ast_mark_lock_acquired(t);
1118 if (lt->reentrancy) {
1119 ast_reentrancy_lock(lt);
1120 bt = <->backtrace[lt->reentrancy-1];
1121 ast_reentrancy_unlock(lt);
1126 ast_remove_lock_info(t, bt);
1130 ast_remove_lock_info(t);
1133 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1134 filename, line, func, strerror(res));
1137 #endif /* DEBUG_THREADS */
1142 int __ast_rwlock_timedwrlock(ast_rwlock_t *t, const char *name,
1143 const struct timespec *abs_timeout, const char *filename, int line, const char *func)
1147 #ifdef DEBUG_THREADS
1148 struct ast_lock_track *lt = &t->track;
1149 int canlog = strcmp(filename, "logger.c") & t->tracking;
1151 struct ast_bt *bt = NULL;
1154 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1155 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1156 /* Don't warn abount uninitialized lock.
1157 * Simple try to initialize it.
1158 * May be not needed in linux system.
1160 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1161 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1162 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1163 filename, line, func, name);
1167 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1171 ast_reentrancy_lock(lt);
1172 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1173 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1174 bt = <->backtrace[lt->reentrancy];
1176 ast_reentrancy_unlock(lt);
1177 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1179 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1182 #endif /* DEBUG_THREADS */
1184 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1185 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1188 struct timeval _start = ast_tvnow(), _diff;
1190 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1193 _diff = ast_tvsub(ast_tvnow(), _start);
1194 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1202 #ifdef DEBUG_THREADS
1204 ast_reentrancy_lock(lt);
1205 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1206 lt->file[lt->reentrancy] = filename;
1207 lt->lineno[lt->reentrancy] = line;
1208 lt->func[lt->reentrancy] = func;
1209 lt->thread[lt->reentrancy] = pthread_self();
1212 ast_reentrancy_unlock(lt);
1214 ast_mark_lock_acquired(t);
1218 if (lt->reentrancy) {
1219 ast_reentrancy_lock(lt);
1220 bt = <->backtrace[lt->reentrancy-1];
1221 ast_reentrancy_unlock(lt);
1226 ast_remove_lock_info(t, bt);
1230 ast_remove_lock_info(t);
1233 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1234 filename, line, func, strerror(res));
1237 #endif /* DEBUG_THREADS */
1242 int __ast_rwlock_tryrdlock(ast_rwlock_t *t, const char *name,
1243 const char *filename, int line, const char *func)
1247 #ifdef DEBUG_THREADS
1248 struct ast_lock_track *lt = &t->track;
1250 struct ast_bt *bt = NULL;
1252 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1253 int canlog = strcmp(filename, "logger.c") & t->tracking;
1255 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1256 /* Don't warn abount uninitialized lock.
1257 * Simple try to initialize it.
1258 * May be not needed in linux system.
1260 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1261 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1262 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1263 filename, line, func, name);
1267 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1271 ast_reentrancy_lock(lt);
1272 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1273 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1274 bt = <->backtrace[lt->reentrancy];
1276 ast_reentrancy_unlock(lt);
1277 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1279 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
1282 #endif /* DEBUG_THREADS */
1284 res = pthread_rwlock_tryrdlock(&t->lock);
1286 #ifdef DEBUG_THREADS
1288 ast_reentrancy_lock(lt);
1289 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1290 lt->file[lt->reentrancy] = filename;
1291 lt->lineno[lt->reentrancy] = line;
1292 lt->func[lt->reentrancy] = func;
1293 lt->thread[lt->reentrancy] = pthread_self();
1296 ast_reentrancy_unlock(lt);
1298 ast_mark_lock_acquired(t);
1300 } else if (t->tracking) {
1301 ast_mark_lock_failed(t);
1303 #endif /* DEBUG_THREADS */
1308 int __ast_rwlock_trywrlock(ast_rwlock_t *t, const char *name,
1309 const char *filename, int line, const char *func)
1313 #ifdef DEBUG_THREADS
1314 struct ast_lock_track *lt= &t->track;
1316 struct ast_bt *bt = NULL;
1318 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1319 int canlog = strcmp(filename, "logger.c") & t->tracking;
1321 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1322 /* Don't warn abount uninitialized lock.
1323 * Simple try to initialize it.
1324 * May be not needed in linux system.
1326 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1327 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1328 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1329 filename, line, func, name);
1333 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1337 ast_reentrancy_lock(lt);
1338 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1339 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1340 bt = <->backtrace[lt->reentrancy];
1342 ast_reentrancy_unlock(lt);
1343 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1345 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1348 #endif /* DEBUG_THREADS */
1350 res = pthread_rwlock_trywrlock(&t->lock);
1352 #ifdef DEBUG_THREADS
1354 ast_reentrancy_lock(lt);
1355 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1356 lt->file[lt->reentrancy] = filename;
1357 lt->lineno[lt->reentrancy] = line;
1358 lt->func[lt->reentrancy] = func;
1359 lt->thread[lt->reentrancy] = pthread_self();
1362 ast_reentrancy_unlock(lt);
1364 ast_mark_lock_acquired(t);
1366 } else if (t->tracking) {
1367 ast_mark_lock_failed(t);
1369 #endif /* DEBUG_THREADS */