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 #endif /* DEBUG_THREADS */
67 pthread_mutexattr_init(&attr);
68 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
70 res = pthread_mutex_init(&t->mutex, &attr);
71 pthread_mutexattr_destroy(&attr);
75 int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
76 const char *mutex_name, ast_mutex_t *t)
81 struct ast_lock_track *lt;
82 int canlog = strcmp(filename, "logger.c") & t->tracking;
84 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
85 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
86 /* Don't try to uninitialize non initialized mutex
87 * This may no effect on linux
88 * And always ganerate core on *BSD with
90 * This not error condition if the mutex created on the fly.
92 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
93 filename, lineno, func, mutex_name);
98 if (t->tracking && !t->track) {
99 ast_reentrancy_init(&t->track);
103 res = pthread_mutex_trylock(&t->mutex);
106 pthread_mutex_unlock(&t->mutex);
109 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
110 filename, lineno, func, mutex_name);
113 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
114 filename, lineno, func, mutex_name);
116 ast_reentrancy_lock(lt);
117 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
118 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
120 __dump_backtrace(<->backtrace[ROFFSET], canlog);
122 ast_reentrancy_unlock(lt);
126 #endif /* DEBUG_THREADS */
128 res = pthread_mutex_destroy(&t->mutex);
132 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
133 filename, lineno, func, mutex_name, strerror(res));
136 ast_reentrancy_lock(lt);
137 lt->file[0] = filename;
138 lt->lineno[0] = lineno;
143 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
145 ast_reentrancy_unlock(lt);
146 delete_reentrancy_cs(&t->track);
148 #endif /* DEBUG_THREADS */
153 int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
154 const char* mutex_name, ast_mutex_t *t)
159 struct ast_lock_track *lt;
160 int canlog = strcmp(filename, "logger.c") & t->tracking;
162 struct ast_bt *bt = NULL;
165 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
166 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
167 /* Don't warn abount uninitialized mutex.
168 * Simple try to initialize it.
169 * May be not needed in linux system.
171 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
172 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
173 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
174 filename, lineno, func, mutex_name);
178 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
180 if (t->tracking && !t->track) {
181 ast_reentrancy_init(&t->track);
187 ast_reentrancy_lock(lt);
188 if (lt->reentrancy != AST_MAX_REENTRANCY) {
189 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
190 bt = <->backtrace[lt->reentrancy];
192 ast_reentrancy_unlock(lt);
193 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
195 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
198 #endif /* DEBUG_THREADS */
200 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
202 time_t seconds = time(NULL);
203 time_t wait_time, reported_wait = 0;
205 #ifdef HAVE_MTX_PROFILE
206 ast_mark(mtx_prof, 1);
208 res = pthread_mutex_trylock(&t->mutex);
209 #ifdef HAVE_MTX_PROFILE
210 ast_mark(mtx_prof, 0);
213 wait_time = time(NULL) - seconds;
214 if (wait_time > reported_wait && (wait_time % 5) == 0) {
215 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
216 filename, lineno, func, (int) wait_time, mutex_name);
217 ast_reentrancy_lock(lt);
219 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
221 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
222 lt->file[ROFFSET], lt->lineno[ROFFSET],
223 lt->func[ROFFSET], mutex_name);
225 __dump_backtrace(<->backtrace[ROFFSET], canlog);
227 ast_reentrancy_unlock(lt);
228 reported_wait = wait_time;
232 } while (res == EBUSY);
234 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
235 #ifdef HAVE_MTX_PROFILE
236 ast_mark(mtx_prof, 1);
237 res = pthread_mutex_trylock(&t->mutex);
238 ast_mark(mtx_prof, 0);
241 res = pthread_mutex_lock(&t->mutex);
242 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
245 if (t->tracking && !res) {
246 ast_reentrancy_lock(lt);
247 if (lt->reentrancy < AST_MAX_REENTRANCY) {
248 lt->file[lt->reentrancy] = filename;
249 lt->lineno[lt->reentrancy] = lineno;
250 lt->func[lt->reentrancy] = func;
251 lt->thread[lt->reentrancy] = pthread_self();
254 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
255 filename, lineno, func, mutex_name);
257 ast_reentrancy_unlock(lt);
259 ast_mark_lock_acquired(t);
261 } else if (t->tracking) {
263 if (lt->reentrancy) {
264 ast_reentrancy_lock(lt);
265 bt = <->backtrace[lt->reentrancy-1];
266 ast_reentrancy_unlock(lt);
270 ast_remove_lock_info(t, bt);
272 ast_remove_lock_info(t);
276 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
277 filename, lineno, func, strerror(res));
280 #endif /* DEBUG_THREADS */
285 int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
286 const char* mutex_name, ast_mutex_t *t)
291 struct ast_lock_track *lt;
292 int canlog = strcmp(filename, "logger.c") & t->tracking;
294 struct ast_bt *bt = NULL;
297 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
298 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
299 /* Don't warn abount uninitialized mutex.
300 * Simple try to initialize it.
301 * May be not needed in linux system.
303 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
304 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
305 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
306 filename, lineno, func, mutex_name);
310 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
312 if (t->tracking && !t->track) {
313 ast_reentrancy_init(&t->track);
319 ast_reentrancy_lock(lt);
320 if (lt->reentrancy != AST_MAX_REENTRANCY) {
321 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
322 bt = <->backtrace[lt->reentrancy];
324 ast_reentrancy_unlock(lt);
325 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
327 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
330 #endif /* DEBUG_THREADS */
332 res = pthread_mutex_trylock(&t->mutex);
335 if (t->tracking && !res) {
336 ast_reentrancy_lock(lt);
337 if (lt->reentrancy < AST_MAX_REENTRANCY) {
338 lt->file[lt->reentrancy] = filename;
339 lt->lineno[lt->reentrancy] = lineno;
340 lt->func[lt->reentrancy] = func;
341 lt->thread[lt->reentrancy] = pthread_self();
344 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
345 filename, lineno, func, mutex_name);
347 ast_reentrancy_unlock(lt);
349 ast_mark_lock_acquired(t);
351 } else if (t->tracking) {
352 ast_mark_lock_failed(t);
354 #endif /* DEBUG_THREADS */
359 int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
360 const char *mutex_name, ast_mutex_t *t)
365 struct ast_lock_track *lt;
366 int canlog = strcmp(filename, "logger.c") & t->tracking;
368 struct ast_bt *bt = NULL;
371 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
372 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
373 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
374 filename, lineno, func, mutex_name);
375 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
376 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
377 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
378 filename, lineno, func, mutex_name);
382 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
384 if (t->tracking && !t->track) {
385 ast_reentrancy_init(&t->track);
390 ast_reentrancy_lock(lt);
391 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
392 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
393 filename, lineno, func, mutex_name);
394 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
395 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
397 __dump_backtrace(<->backtrace[ROFFSET], canlog);
402 if (--lt->reentrancy < 0) {
403 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
404 filename, lineno, func, mutex_name);
408 if (lt->reentrancy < AST_MAX_REENTRANCY) {
409 lt->file[lt->reentrancy] = NULL;
410 lt->lineno[lt->reentrancy] = 0;
411 lt->func[lt->reentrancy] = NULL;
412 lt->thread[lt->reentrancy] = 0;
416 if (lt->reentrancy) {
417 bt = <->backtrace[lt->reentrancy - 1];
420 ast_reentrancy_unlock(lt);
423 ast_remove_lock_info(t, bt);
425 ast_remove_lock_info(t);
428 #endif /* DEBUG_THREADS */
430 res = pthread_mutex_unlock(&t->mutex);
434 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
435 filename, lineno, func, strerror(res));
438 #endif /* DEBUG_THREADS */
444 int __ast_cond_init(const char *filename, int lineno, const char *func,
445 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
447 return pthread_cond_init(cond, cond_attr);
450 int __ast_cond_signal(const char *filename, int lineno, const char *func,
451 const char *cond_name, ast_cond_t *cond)
453 return pthread_cond_signal(cond);
456 int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
457 const char *cond_name, ast_cond_t *cond)
459 return pthread_cond_broadcast(cond);
462 int __ast_cond_destroy(const char *filename, int lineno, const char *func,
463 const char *cond_name, ast_cond_t *cond)
465 return pthread_cond_destroy(cond);
468 int __ast_cond_wait(const char *filename, int lineno, const char *func,
469 const char *cond_name, const char *mutex_name,
470 ast_cond_t *cond, ast_mutex_t *t)
475 struct ast_lock_track *lt;
476 int canlog = strcmp(filename, "logger.c") & t->tracking;
478 struct ast_bt *bt = NULL;
481 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
482 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
483 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
484 filename, lineno, func, mutex_name);
485 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
486 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
487 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
488 filename, lineno, func, mutex_name);
492 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
494 if (t->tracking && !t->track) {
495 ast_reentrancy_init(&t->track);
500 ast_reentrancy_lock(lt);
501 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
502 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
503 filename, lineno, func, mutex_name);
504 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
505 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
507 __dump_backtrace(<->backtrace[ROFFSET], canlog);
512 if (--lt->reentrancy < 0) {
513 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
514 filename, lineno, func, mutex_name);
518 if (lt->reentrancy < AST_MAX_REENTRANCY) {
519 lt->file[lt->reentrancy] = NULL;
520 lt->lineno[lt->reentrancy] = 0;
521 lt->func[lt->reentrancy] = NULL;
522 lt->thread[lt->reentrancy] = 0;
526 if (lt->reentrancy) {
527 bt = <->backtrace[lt->reentrancy - 1];
530 ast_reentrancy_unlock(lt);
533 ast_remove_lock_info(t, bt);
535 ast_remove_lock_info(t);
538 #endif /* DEBUG_THREADS */
540 res = pthread_cond_wait(cond, &t->mutex);
544 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
545 filename, lineno, func, strerror(res));
547 } else if (t->tracking) {
548 ast_reentrancy_lock(lt);
549 if (lt->reentrancy < AST_MAX_REENTRANCY) {
550 lt->file[lt->reentrancy] = filename;
551 lt->lineno[lt->reentrancy] = lineno;
552 lt->func[lt->reentrancy] = func;
553 lt->thread[lt->reentrancy] = pthread_self();
555 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
556 bt = <->backtrace[lt->reentrancy];
560 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
561 filename, lineno, func, mutex_name);
563 ast_reentrancy_unlock(lt);
566 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
568 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
571 #endif /* DEBUG_THREADS */
576 int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
577 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
578 ast_mutex_t *t, const struct timespec *abstime)
583 struct ast_lock_track *lt;
584 int canlog = strcmp(filename, "logger.c") & t->tracking;
586 struct ast_bt *bt = NULL;
589 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
590 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
591 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
592 filename, lineno, func, mutex_name);
593 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
594 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
595 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
596 filename, lineno, func, mutex_name);
600 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
602 if (t->tracking && !t->track) {
603 ast_reentrancy_init(&t->track);
608 ast_reentrancy_lock(lt);
609 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
610 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
611 filename, lineno, func, mutex_name);
612 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
613 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
615 __dump_backtrace(<->backtrace[ROFFSET], canlog);
620 if (--lt->reentrancy < 0) {
621 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
622 filename, lineno, func, mutex_name);
626 if (lt->reentrancy < AST_MAX_REENTRANCY) {
627 lt->file[lt->reentrancy] = NULL;
628 lt->lineno[lt->reentrancy] = 0;
629 lt->func[lt->reentrancy] = NULL;
630 lt->thread[lt->reentrancy] = 0;
633 if (lt->reentrancy) {
634 bt = <->backtrace[lt->reentrancy - 1];
637 ast_reentrancy_unlock(lt);
640 ast_remove_lock_info(t, bt);
642 ast_remove_lock_info(t);
645 #endif /* DEBUG_THREADS */
647 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
650 if (res && (res != ETIMEDOUT)) {
651 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
652 filename, lineno, func, strerror(res));
654 } else if (t->tracking) {
655 ast_reentrancy_lock(lt);
656 if (lt->reentrancy < AST_MAX_REENTRANCY) {
657 lt->file[lt->reentrancy] = filename;
658 lt->lineno[lt->reentrancy] = lineno;
659 lt->func[lt->reentrancy] = func;
660 lt->thread[lt->reentrancy] = pthread_self();
662 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
663 bt = <->backtrace[lt->reentrancy];
667 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
668 filename, lineno, func, mutex_name);
670 ast_reentrancy_unlock(lt);
673 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
675 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
678 #endif /* DEBUG_THREADS */
683 int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
686 pthread_rwlockattr_t attr;
690 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
691 int canlog = strcmp(filename, "logger.c") & t->tracking;
693 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
694 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
695 filename, lineno, func, rwlock_name);
698 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
700 if ((t->tracking = tracking)) {
701 ast_reentrancy_init(&t->track);
703 #endif /* DEBUG_THREADS */
705 pthread_rwlockattr_init(&attr);
707 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
708 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
711 res = pthread_rwlock_init(&t->lock, &attr);
712 pthread_rwlockattr_destroy(&attr);
716 int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
721 struct ast_lock_track *lt = t->track;
722 int canlog = strcmp(filename, "logger.c") & t->tracking;
724 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
725 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
726 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
727 filename, lineno, func, rwlock_name);
730 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
732 #endif /* DEBUG_THREADS */
734 res = pthread_rwlock_destroy(&t->lock);
738 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
739 filename, lineno, func, rwlock_name, strerror(res));
742 ast_reentrancy_lock(lt);
743 lt->file[0] = filename;
744 lt->lineno[0] = lineno;
749 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
751 ast_reentrancy_unlock(lt);
752 delete_reentrancy_cs(&t->track);
754 #endif /* DEBUG_THREADS */
759 int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
764 struct ast_lock_track *lt;
765 int canlog = strcmp(filename, "logger.c") & t->tracking;
767 struct ast_bt *bt = NULL;
772 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
773 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
774 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
775 filename, line, func, name);
776 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
777 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
778 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
779 filename, line, func, name);
783 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
785 if (t->tracking && !t->track) {
786 ast_reentrancy_init(&t->track);
791 ast_reentrancy_lock(lt);
792 if (lt->reentrancy) {
794 pthread_t self = pthread_self();
795 for (i = lt->reentrancy - 1; i >= 0; --i) {
796 if (lt->thread[i] == self) {
798 if (i != lt->reentrancy - 1) {
799 lt->file[i] = lt->file[lt->reentrancy - 1];
800 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
801 lt->func[i] = lt->func[lt->reentrancy - 1];
802 lt->thread[i] = lt->thread[lt->reentrancy - 1];
805 bt = <->backtrace[i];
807 lt->file[lt->reentrancy - 1] = NULL;
808 lt->lineno[lt->reentrancy - 1] = 0;
809 lt->func[lt->reentrancy - 1] = NULL;
810 lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
816 if (lock_found && --lt->reentrancy < 0) {
817 __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
818 filename, line, func, name);
822 ast_reentrancy_unlock(lt);
825 ast_remove_lock_info(t, bt);
827 ast_remove_lock_info(t);
830 #endif /* DEBUG_THREADS */
832 res = pthread_rwlock_unlock(&t->lock);
836 __ast_mutex_logger("%s line %d (%s): Error releasing rwlock: %s\n",
837 filename, line, func, strerror(res));
840 #endif /* DEBUG_THREADS */
845 int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
850 struct ast_lock_track *lt;
851 int canlog = strcmp(filename, "logger.c") & t->tracking;
853 struct ast_bt *bt = NULL;
856 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
857 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
858 /* Don't warn abount uninitialized lock.
859 * Simple try to initialize it.
860 * May be not needed in linux system.
862 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
863 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
864 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
865 filename, line, func, name);
869 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
871 if (t->tracking && !t->track) {
872 ast_reentrancy_init(&t->track);
878 ast_reentrancy_lock(lt);
879 if (lt->reentrancy != AST_MAX_REENTRANCY) {
880 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
881 bt = <->backtrace[lt->reentrancy];
883 ast_reentrancy_unlock(lt);
884 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
886 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
889 #endif /* DEBUG_THREADS */
891 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
893 time_t seconds = time(NULL);
894 time_t wait_time, reported_wait = 0;
896 res = pthread_rwlock_tryrdlock(&t->lock);
898 wait_time = time(NULL) - seconds;
899 if (wait_time > reported_wait && (wait_time % 5) == 0) {
900 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
901 filename, line, func, (int)wait_time, name);
903 ast_reentrancy_lock(lt);
905 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
907 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
908 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
909 lt->func[lt->reentrancy-1], name);
911 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
913 ast_reentrancy_unlock(lt);
915 reported_wait = wait_time;
919 } while (res == EBUSY);
921 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
922 res = pthread_rwlock_rdlock(&t->lock);
923 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
926 if (!res && t->tracking) {
927 ast_reentrancy_lock(lt);
928 if (lt->reentrancy < AST_MAX_REENTRANCY) {
929 lt->file[lt->reentrancy] = filename;
930 lt->lineno[lt->reentrancy] = line;
931 lt->func[lt->reentrancy] = func;
932 lt->thread[lt->reentrancy] = pthread_self();
935 ast_reentrancy_unlock(lt);
937 ast_mark_lock_acquired(t);
939 } else if (t->tracking) {
941 if (lt->reentrancy) {
942 ast_reentrancy_lock(lt);
943 bt = <->backtrace[lt->reentrancy-1];
944 ast_reentrancy_unlock(lt);
948 ast_remove_lock_info(t, bt);
950 ast_remove_lock_info(t);
955 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
956 filename, line, func, strerror(res));
959 #endif /* DEBUG_THREADS */
964 int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
969 struct ast_lock_track *lt;
970 int canlog = strcmp(filename, "logger.c") & t->tracking;
972 struct ast_bt *bt = NULL;
975 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
976 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
977 /* Don't warn abount uninitialized lock.
978 * Simple try to initialize it.
979 * May be not needed in linux system.
981 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
982 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
983 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
984 filename, line, func, name);
988 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
990 if (t->tracking && !t->track) {
991 ast_reentrancy_init(&t->track);
997 ast_reentrancy_lock(lt);
998 if (lt->reentrancy != AST_MAX_REENTRANCY) {
999 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1000 bt = <->backtrace[lt->reentrancy];
1002 ast_reentrancy_unlock(lt);
1003 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1005 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1008 #endif /* DEBUG_THREADS */
1010 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
1012 time_t seconds = time(NULL);
1013 time_t wait_time, reported_wait = 0;
1015 res = pthread_rwlock_trywrlock(&t->lock);
1017 wait_time = time(NULL) - seconds;
1018 if (wait_time > reported_wait && (wait_time % 5) == 0) {
1019 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
1020 filename, line, func, (int)wait_time, name);
1022 ast_reentrancy_lock(lt);
1024 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
1026 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
1027 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1028 lt->func[lt->reentrancy-1], name);
1030 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
1032 ast_reentrancy_unlock(lt);
1034 reported_wait = wait_time;
1038 } while (res == EBUSY);
1040 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1041 res = pthread_rwlock_wrlock(&t->lock);
1042 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1044 #ifdef DEBUG_THREADS
1045 if (!res && t->tracking) {
1046 ast_reentrancy_lock(lt);
1047 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1048 lt->file[lt->reentrancy] = filename;
1049 lt->lineno[lt->reentrancy] = line;
1050 lt->func[lt->reentrancy] = func;
1051 lt->thread[lt->reentrancy] = pthread_self();
1054 ast_reentrancy_unlock(lt);
1056 ast_mark_lock_acquired(t);
1058 } else if (t->tracking) {
1060 if (lt->reentrancy) {
1061 ast_reentrancy_lock(lt);
1062 bt = <->backtrace[lt->reentrancy-1];
1063 ast_reentrancy_unlock(lt);
1068 ast_remove_lock_info(t, bt);
1072 ast_remove_lock_info(t);
1077 __ast_mutex_logger("%s line %d (%s): Error obtaining write lock: %s\n",
1078 filename, line, func, strerror(res));
1081 #endif /* DEBUG_THREADS */
1086 int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1087 const struct timespec *abs_timeout)
1091 #ifdef DEBUG_THREADS
1092 struct ast_lock_track *lt;
1093 int canlog = strcmp(filename, "logger.c") & t->tracking;
1095 struct ast_bt *bt = NULL;
1098 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1099 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1100 /* Don't warn abount uninitialized lock.
1101 * Simple try to initialize it.
1102 * May be not needed in linux system.
1104 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1105 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1106 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1107 filename, line, func, name);
1111 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1113 if (t->tracking && !t->track) {
1114 ast_reentrancy_init(&t->track);
1120 ast_reentrancy_lock(lt);
1121 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1122 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1123 bt = <->backtrace[lt->reentrancy];
1125 ast_reentrancy_unlock(lt);
1126 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1128 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1131 #endif /* DEBUG_THREADS */
1133 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1134 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1137 struct timeval _start = ast_tvnow(), _diff;
1139 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1142 _diff = ast_tvsub(ast_tvnow(), _start);
1143 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1151 #ifdef DEBUG_THREADS
1152 if (!res && t->tracking) {
1153 ast_reentrancy_lock(lt);
1154 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1155 lt->file[lt->reentrancy] = filename;
1156 lt->lineno[lt->reentrancy] = line;
1157 lt->func[lt->reentrancy] = func;
1158 lt->thread[lt->reentrancy] = pthread_self();
1161 ast_reentrancy_unlock(lt);
1163 ast_mark_lock_acquired(t);
1165 } else if (t->tracking) {
1167 if (lt->reentrancy) {
1168 ast_reentrancy_lock(lt);
1169 bt = <->backtrace[lt->reentrancy-1];
1170 ast_reentrancy_unlock(lt);
1174 ast_remove_lock_info(t, bt);
1176 ast_remove_lock_info(t);
1180 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1181 filename, line, func, strerror(res));
1184 #endif /* DEBUG_THREADS */
1189 int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1190 const struct timespec *abs_timeout)
1194 #ifdef DEBUG_THREADS
1195 struct ast_lock_track *lt;
1196 int canlog = strcmp(filename, "logger.c") & t->tracking;
1198 struct ast_bt *bt = NULL;
1201 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1202 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1203 /* Don't warn abount uninitialized lock.
1204 * Simple try to initialize it.
1205 * May be not needed in linux system.
1207 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1208 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1209 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1210 filename, line, func, name);
1214 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1216 if (t->tracking && !t->track) {
1217 ast_reentrancy_init(&t->track);
1223 ast_reentrancy_lock(lt);
1224 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1225 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1226 bt = <->backtrace[lt->reentrancy];
1228 ast_reentrancy_unlock(lt);
1229 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1231 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1234 #endif /* DEBUG_THREADS */
1236 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1237 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1240 struct timeval _start = ast_tvnow(), _diff;
1242 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1245 _diff = ast_tvsub(ast_tvnow(), _start);
1246 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1254 #ifdef DEBUG_THREADS
1255 if (!res && t->tracking) {
1256 ast_reentrancy_lock(lt);
1257 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1258 lt->file[lt->reentrancy] = filename;
1259 lt->lineno[lt->reentrancy] = line;
1260 lt->func[lt->reentrancy] = func;
1261 lt->thread[lt->reentrancy] = pthread_self();
1264 ast_reentrancy_unlock(lt);
1266 ast_mark_lock_acquired(t);
1268 } else if (t->tracking) {
1270 if (lt->reentrancy) {
1271 ast_reentrancy_lock(lt);
1272 bt = <->backtrace[lt->reentrancy-1];
1273 ast_reentrancy_unlock(lt);
1278 ast_remove_lock_info(t, bt);
1282 ast_remove_lock_info(t);
1287 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1288 filename, line, func, strerror(res));
1291 #endif /* DEBUG_THREADS */
1296 int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1300 #ifdef DEBUG_THREADS
1301 struct ast_lock_track *lt;
1303 struct ast_bt *bt = NULL;
1305 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1306 int canlog = strcmp(filename, "logger.c") & t->tracking;
1308 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1309 /* Don't warn abount uninitialized lock.
1310 * Simple try to initialize it.
1311 * May be not needed in linux system.
1313 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1314 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1315 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1316 filename, line, func, name);
1320 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1322 if (t->tracking && !t->track) {
1323 ast_reentrancy_init(&t->track);
1329 ast_reentrancy_lock(lt);
1330 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1331 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1332 bt = <->backtrace[lt->reentrancy];
1334 ast_reentrancy_unlock(lt);
1335 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1337 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
1340 #endif /* DEBUG_THREADS */
1342 res = pthread_rwlock_tryrdlock(&t->lock);
1344 #ifdef DEBUG_THREADS
1345 if (!res && t->tracking) {
1346 ast_reentrancy_lock(lt);
1347 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1348 lt->file[lt->reentrancy] = filename;
1349 lt->lineno[lt->reentrancy] = line;
1350 lt->func[lt->reentrancy] = func;
1351 lt->thread[lt->reentrancy] = pthread_self();
1354 ast_reentrancy_unlock(lt);
1356 ast_mark_lock_acquired(t);
1358 } else if (t->tracking) {
1359 ast_mark_lock_failed(t);
1361 #endif /* DEBUG_THREADS */
1366 int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1370 #ifdef DEBUG_THREADS
1371 struct ast_lock_track *lt;
1373 struct ast_bt *bt = NULL;
1375 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1376 int canlog = strcmp(filename, "logger.c") & t->tracking;
1378 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1379 /* Don't warn abount uninitialized lock.
1380 * Simple try to initialize it.
1381 * May be not needed in linux system.
1383 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1384 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1385 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1386 filename, line, func, name);
1390 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1392 if (t->tracking && !t->track) {
1393 ast_reentrancy_init(&t->track);
1399 ast_reentrancy_lock(lt);
1400 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1401 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1402 bt = <->backtrace[lt->reentrancy];
1404 ast_reentrancy_unlock(lt);
1405 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1407 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1410 #endif /* DEBUG_THREADS */
1412 res = pthread_rwlock_trywrlock(&t->lock);
1414 #ifdef DEBUG_THREADS
1415 if (!res && t->tracking) {
1416 ast_reentrancy_lock(lt);
1417 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1418 lt->file[lt->reentrancy] = filename;
1419 lt->lineno[lt->reentrancy] = line;
1420 lt->func[lt->reentrancy] = func;
1421 lt->thread[lt->reentrancy] = pthread_self();
1424 ast_reentrancy_unlock(lt);
1425 ast_mark_lock_acquired(t);
1426 } else if (t->tracking) {
1427 ast_mark_lock_failed(t);
1429 #endif /* DEBUG_THREADS */