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;
52 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
53 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
55 int canlog = strcmp(filename, "logger.c") & track;
56 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
57 filename, lineno, func, mutex_name);
63 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
65 if ((t->tracking = tracking)) {
66 ast_reentrancy_init(&t->track);
68 #endif /* DEBUG_THREADS */
70 pthread_mutexattr_init(&attr);
71 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
73 res = pthread_mutex_init(&t->mutex, &attr);
74 pthread_mutexattr_destroy(&attr);
78 int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
79 const char *mutex_name, ast_mutex_t *t)
84 struct ast_lock_track *lt;
85 int canlog = strcmp(filename, "logger.c") & t->tracking;
87 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
88 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
89 /* Don't try to uninitialize non initialized mutex
90 * This may no effect on linux
91 * And always ganerate core on *BSD with
93 * This not error condition if the mutex created on the fly.
95 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
96 filename, lineno, func, mutex_name);
101 if (t->tracking && !t->track) {
102 ast_reentrancy_init(&t->track);
106 res = pthread_mutex_trylock(&t->mutex);
109 pthread_mutex_unlock(&t->mutex);
112 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
113 filename, lineno, func, mutex_name);
116 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
117 filename, lineno, func, mutex_name);
119 ast_reentrancy_lock(lt);
120 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
121 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
123 __dump_backtrace(<->backtrace[ROFFSET], canlog);
125 ast_reentrancy_unlock(lt);
129 #endif /* DEBUG_THREADS */
131 res = pthread_mutex_destroy(&t->mutex);
135 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
136 filename, lineno, func, mutex_name, strerror(res));
139 ast_reentrancy_lock(lt);
140 lt->file[0] = filename;
141 lt->lineno[0] = lineno;
146 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
148 ast_reentrancy_unlock(lt);
149 delete_reentrancy_cs(&t->track);
151 #endif /* DEBUG_THREADS */
156 int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
157 const char* mutex_name, ast_mutex_t *t)
162 struct ast_lock_track *lt;
163 int canlog = strcmp(filename, "logger.c") & t->tracking;
165 struct ast_bt *bt = NULL;
168 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
169 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
170 /* Don't warn abount uninitialized mutex.
171 * Simple try to initialize it.
172 * May be not needed in linux system.
174 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
175 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
176 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
177 filename, lineno, func, mutex_name);
181 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
183 if (t->tracking && !t->track) {
184 ast_reentrancy_init(&t->track);
190 ast_reentrancy_lock(lt);
191 if (lt->reentrancy != AST_MAX_REENTRANCY) {
192 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
193 bt = <->backtrace[lt->reentrancy];
195 ast_reentrancy_unlock(lt);
196 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
198 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
201 #endif /* DEBUG_THREADS */
203 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
205 time_t seconds = time(NULL);
206 time_t wait_time, reported_wait = 0;
208 #ifdef HAVE_MTX_PROFILE
209 ast_mark(mtx_prof, 1);
211 res = pthread_mutex_trylock(&t->mutex);
212 #ifdef HAVE_MTX_PROFILE
213 ast_mark(mtx_prof, 0);
216 wait_time = time(NULL) - seconds;
217 if (wait_time > reported_wait && (wait_time % 5) == 0) {
218 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
219 filename, lineno, func, (int) wait_time, mutex_name);
220 ast_reentrancy_lock(lt);
222 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
224 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
225 lt->file[ROFFSET], lt->lineno[ROFFSET],
226 lt->func[ROFFSET], mutex_name);
228 __dump_backtrace(<->backtrace[ROFFSET], canlog);
230 ast_reentrancy_unlock(lt);
231 reported_wait = wait_time;
235 } while (res == EBUSY);
237 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
238 #ifdef HAVE_MTX_PROFILE
239 ast_mark(mtx_prof, 1);
240 res = pthread_mutex_trylock(&t->mutex);
241 ast_mark(mtx_prof, 0);
244 res = pthread_mutex_lock(&t->mutex);
245 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
248 if (t->tracking && !res) {
249 ast_reentrancy_lock(lt);
250 if (lt->reentrancy < AST_MAX_REENTRANCY) {
251 lt->file[lt->reentrancy] = filename;
252 lt->lineno[lt->reentrancy] = lineno;
253 lt->func[lt->reentrancy] = func;
254 lt->thread[lt->reentrancy] = pthread_self();
257 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
258 filename, lineno, func, mutex_name);
260 ast_reentrancy_unlock(lt);
262 ast_mark_lock_acquired(t);
264 } else if (t->tracking) {
266 if (lt->reentrancy) {
267 ast_reentrancy_lock(lt);
268 bt = <->backtrace[lt->reentrancy-1];
269 ast_reentrancy_unlock(lt);
273 ast_remove_lock_info(t, bt);
275 ast_remove_lock_info(t);
279 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
280 filename, lineno, func, strerror(res));
283 #endif /* DEBUG_THREADS */
288 int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
289 const char* mutex_name, ast_mutex_t *t)
294 struct ast_lock_track *lt;
295 int canlog = strcmp(filename, "logger.c") & t->tracking;
297 struct ast_bt *bt = NULL;
300 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
301 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
302 /* Don't warn abount uninitialized mutex.
303 * Simple try to initialize it.
304 * May be not needed in linux system.
306 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
307 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
308 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
309 filename, lineno, func, mutex_name);
313 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
315 if (t->tracking && !t->track) {
316 ast_reentrancy_init(&t->track);
322 ast_reentrancy_lock(lt);
323 if (lt->reentrancy != AST_MAX_REENTRANCY) {
324 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
325 bt = <->backtrace[lt->reentrancy];
327 ast_reentrancy_unlock(lt);
328 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
330 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
333 #endif /* DEBUG_THREADS */
335 res = pthread_mutex_trylock(&t->mutex);
338 if (t->tracking && !res) {
339 ast_reentrancy_lock(lt);
340 if (lt->reentrancy < AST_MAX_REENTRANCY) {
341 lt->file[lt->reentrancy] = filename;
342 lt->lineno[lt->reentrancy] = lineno;
343 lt->func[lt->reentrancy] = func;
344 lt->thread[lt->reentrancy] = pthread_self();
347 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
348 filename, lineno, func, mutex_name);
350 ast_reentrancy_unlock(lt);
352 ast_mark_lock_acquired(t);
354 } else if (t->tracking) {
355 ast_mark_lock_failed(t);
357 #endif /* DEBUG_THREADS */
362 int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
363 const char *mutex_name, ast_mutex_t *t)
368 struct ast_lock_track *lt;
369 int canlog = strcmp(filename, "logger.c") & t->tracking;
371 struct ast_bt *bt = NULL;
374 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
375 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
376 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
377 filename, lineno, func, mutex_name);
378 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
379 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
380 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
381 filename, lineno, func, mutex_name);
385 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
387 if (t->tracking && !t->track) {
388 ast_reentrancy_init(&t->track);
393 ast_reentrancy_lock(lt);
394 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
395 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
396 filename, lineno, func, mutex_name);
397 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
398 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
400 __dump_backtrace(<->backtrace[ROFFSET], canlog);
405 if (--lt->reentrancy < 0) {
406 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
407 filename, lineno, func, mutex_name);
411 if (lt->reentrancy < AST_MAX_REENTRANCY) {
412 lt->file[lt->reentrancy] = NULL;
413 lt->lineno[lt->reentrancy] = 0;
414 lt->func[lt->reentrancy] = NULL;
415 lt->thread[lt->reentrancy] = 0;
419 if (lt->reentrancy) {
420 bt = <->backtrace[lt->reentrancy - 1];
423 ast_reentrancy_unlock(lt);
426 ast_remove_lock_info(t, bt);
428 ast_remove_lock_info(t);
431 #endif /* DEBUG_THREADS */
433 res = pthread_mutex_unlock(&t->mutex);
437 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
438 filename, lineno, func, strerror(res));
441 #endif /* DEBUG_THREADS */
447 int __ast_cond_init(const char *filename, int lineno, const char *func,
448 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
450 return pthread_cond_init(cond, cond_attr);
453 int __ast_cond_signal(const char *filename, int lineno, const char *func,
454 const char *cond_name, ast_cond_t *cond)
456 return pthread_cond_signal(cond);
459 int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
460 const char *cond_name, ast_cond_t *cond)
462 return pthread_cond_broadcast(cond);
465 int __ast_cond_destroy(const char *filename, int lineno, const char *func,
466 const char *cond_name, ast_cond_t *cond)
468 return pthread_cond_destroy(cond);
471 int __ast_cond_wait(const char *filename, int lineno, const char *func,
472 const char *cond_name, const char *mutex_name,
473 ast_cond_t *cond, ast_mutex_t *t)
478 struct ast_lock_track *lt;
479 int canlog = strcmp(filename, "logger.c") & t->tracking;
481 struct ast_bt *bt = NULL;
484 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
485 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
486 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
487 filename, lineno, func, mutex_name);
488 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
489 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
490 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
491 filename, lineno, func, mutex_name);
495 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
497 if (t->tracking && !t->track) {
498 ast_reentrancy_init(&t->track);
503 ast_reentrancy_lock(lt);
504 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
505 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
506 filename, lineno, func, mutex_name);
507 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
508 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
510 __dump_backtrace(<->backtrace[ROFFSET], canlog);
515 if (--lt->reentrancy < 0) {
516 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
517 filename, lineno, func, mutex_name);
521 if (lt->reentrancy < AST_MAX_REENTRANCY) {
522 lt->file[lt->reentrancy] = NULL;
523 lt->lineno[lt->reentrancy] = 0;
524 lt->func[lt->reentrancy] = NULL;
525 lt->thread[lt->reentrancy] = 0;
529 if (lt->reentrancy) {
530 bt = <->backtrace[lt->reentrancy - 1];
533 ast_reentrancy_unlock(lt);
536 ast_remove_lock_info(t, bt);
538 ast_remove_lock_info(t);
541 #endif /* DEBUG_THREADS */
543 res = pthread_cond_wait(cond, &t->mutex);
547 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
548 filename, lineno, func, strerror(res));
550 } else if (t->tracking) {
551 ast_reentrancy_lock(lt);
552 if (lt->reentrancy < AST_MAX_REENTRANCY) {
553 lt->file[lt->reentrancy] = filename;
554 lt->lineno[lt->reentrancy] = lineno;
555 lt->func[lt->reentrancy] = func;
556 lt->thread[lt->reentrancy] = pthread_self();
558 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
559 bt = <->backtrace[lt->reentrancy];
563 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
564 filename, lineno, func, mutex_name);
566 ast_reentrancy_unlock(lt);
569 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
571 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
574 #endif /* DEBUG_THREADS */
579 int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
580 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
581 ast_mutex_t *t, const struct timespec *abstime)
586 struct ast_lock_track *lt;
587 int canlog = strcmp(filename, "logger.c") & t->tracking;
589 struct ast_bt *bt = NULL;
592 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
593 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
594 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
595 filename, lineno, func, mutex_name);
596 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
597 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
598 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
599 filename, lineno, func, mutex_name);
603 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
605 if (t->tracking && !t->track) {
606 ast_reentrancy_init(&t->track);
611 ast_reentrancy_lock(lt);
612 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
613 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
614 filename, lineno, func, mutex_name);
615 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
616 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
618 __dump_backtrace(<->backtrace[ROFFSET], canlog);
623 if (--lt->reentrancy < 0) {
624 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
625 filename, lineno, func, mutex_name);
629 if (lt->reentrancy < AST_MAX_REENTRANCY) {
630 lt->file[lt->reentrancy] = NULL;
631 lt->lineno[lt->reentrancy] = 0;
632 lt->func[lt->reentrancy] = NULL;
633 lt->thread[lt->reentrancy] = 0;
636 if (lt->reentrancy) {
637 bt = <->backtrace[lt->reentrancy - 1];
640 ast_reentrancy_unlock(lt);
643 ast_remove_lock_info(t, bt);
645 ast_remove_lock_info(t);
648 #endif /* DEBUG_THREADS */
650 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
653 if (res && (res != ETIMEDOUT)) {
654 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
655 filename, lineno, func, strerror(res));
657 } else if (t->tracking) {
658 ast_reentrancy_lock(lt);
659 if (lt->reentrancy < AST_MAX_REENTRANCY) {
660 lt->file[lt->reentrancy] = filename;
661 lt->lineno[lt->reentrancy] = lineno;
662 lt->func[lt->reentrancy] = func;
663 lt->thread[lt->reentrancy] = pthread_self();
665 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
666 bt = <->backtrace[lt->reentrancy];
670 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
671 filename, lineno, func, mutex_name);
673 ast_reentrancy_unlock(lt);
676 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
678 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
681 #endif /* DEBUG_THREADS */
686 int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
689 pthread_rwlockattr_t attr;
693 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
694 int canlog = strcmp(filename, "logger.c") & t->tracking;
696 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
697 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
698 filename, lineno, func, rwlock_name);
701 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
703 if ((t->tracking = tracking)) {
704 ast_reentrancy_init(&t->track);
706 #endif /* DEBUG_THREADS */
708 pthread_rwlockattr_init(&attr);
710 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
711 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
714 res = pthread_rwlock_init(&t->lock, &attr);
715 pthread_rwlockattr_destroy(&attr);
719 int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
724 struct ast_lock_track *lt = t->track;
725 int canlog = strcmp(filename, "logger.c") & t->tracking;
727 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
728 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
729 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
730 filename, lineno, func, rwlock_name);
733 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
735 #endif /* DEBUG_THREADS */
737 res = pthread_rwlock_destroy(&t->lock);
741 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
742 filename, lineno, func, rwlock_name, strerror(res));
745 ast_reentrancy_lock(lt);
746 lt->file[0] = filename;
747 lt->lineno[0] = lineno;
752 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
754 ast_reentrancy_unlock(lt);
755 delete_reentrancy_cs(&t->track);
757 #endif /* DEBUG_THREADS */
762 int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
767 struct ast_lock_track *lt;
768 int canlog = strcmp(filename, "logger.c") & t->tracking;
770 struct ast_bt *bt = NULL;
775 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
776 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
777 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
778 filename, line, func, name);
779 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
780 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
781 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
782 filename, line, func, name);
786 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
788 if (t->tracking && !t->track) {
789 ast_reentrancy_init(&t->track);
794 ast_reentrancy_lock(lt);
795 if (lt->reentrancy) {
797 pthread_t self = pthread_self();
798 for (i = lt->reentrancy - 1; i >= 0; --i) {
799 if (lt->thread[i] == self) {
801 if (i != lt->reentrancy - 1) {
802 lt->file[i] = lt->file[lt->reentrancy - 1];
803 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
804 lt->func[i] = lt->func[lt->reentrancy - 1];
805 lt->thread[i] = lt->thread[lt->reentrancy - 1];
808 bt = <->backtrace[i];
810 lt->file[lt->reentrancy - 1] = NULL;
811 lt->lineno[lt->reentrancy - 1] = 0;
812 lt->func[lt->reentrancy - 1] = NULL;
813 lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
819 if (lock_found && --lt->reentrancy < 0) {
820 __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
821 filename, line, func, name);
825 ast_reentrancy_unlock(lt);
828 ast_remove_lock_info(t, bt);
830 ast_remove_lock_info(t);
833 #endif /* DEBUG_THREADS */
835 res = pthread_rwlock_unlock(&t->lock);
839 __ast_mutex_logger("%s line %d (%s): Error releasing rwlock: %s\n",
840 filename, line, func, strerror(res));
843 #endif /* DEBUG_THREADS */
848 int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
853 struct ast_lock_track *lt;
854 int canlog = strcmp(filename, "logger.c") & t->tracking;
856 struct ast_bt *bt = NULL;
859 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
860 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
861 /* Don't warn abount uninitialized lock.
862 * Simple try to initialize it.
863 * May be not needed in linux system.
865 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
866 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
867 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
868 filename, line, func, name);
872 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
874 if (t->tracking && !t->track) {
875 ast_reentrancy_init(&t->track);
881 ast_reentrancy_lock(lt);
882 if (lt->reentrancy != AST_MAX_REENTRANCY) {
883 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
884 bt = <->backtrace[lt->reentrancy];
886 ast_reentrancy_unlock(lt);
887 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
889 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
892 #endif /* DEBUG_THREADS */
894 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
896 time_t seconds = time(NULL);
897 time_t wait_time, reported_wait = 0;
899 res = pthread_rwlock_tryrdlock(&t->lock);
901 wait_time = time(NULL) - seconds;
902 if (wait_time > reported_wait && (wait_time % 5) == 0) {
903 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
904 filename, line, func, (int)wait_time, name);
906 ast_reentrancy_lock(lt);
908 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
910 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
911 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
912 lt->func[lt->reentrancy-1], name);
914 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
916 ast_reentrancy_unlock(lt);
918 reported_wait = wait_time;
922 } while (res == EBUSY);
924 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
925 res = pthread_rwlock_rdlock(&t->lock);
926 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
929 if (!res && t->tracking) {
930 ast_reentrancy_lock(lt);
931 if (lt->reentrancy < AST_MAX_REENTRANCY) {
932 lt->file[lt->reentrancy] = filename;
933 lt->lineno[lt->reentrancy] = line;
934 lt->func[lt->reentrancy] = func;
935 lt->thread[lt->reentrancy] = pthread_self();
938 ast_reentrancy_unlock(lt);
940 ast_mark_lock_acquired(t);
942 } else if (t->tracking) {
944 if (lt->reentrancy) {
945 ast_reentrancy_lock(lt);
946 bt = <->backtrace[lt->reentrancy-1];
947 ast_reentrancy_unlock(lt);
951 ast_remove_lock_info(t, bt);
953 ast_remove_lock_info(t);
958 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
959 filename, line, func, strerror(res));
962 #endif /* DEBUG_THREADS */
967 int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
972 struct ast_lock_track *lt;
973 int canlog = strcmp(filename, "logger.c") & t->tracking;
975 struct ast_bt *bt = NULL;
978 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
979 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
980 /* Don't warn abount uninitialized lock.
981 * Simple try to initialize it.
982 * May be not needed in linux system.
984 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
985 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
986 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
987 filename, line, func, name);
991 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
993 if (t->tracking && !t->track) {
994 ast_reentrancy_init(&t->track);
1000 ast_reentrancy_lock(lt);
1001 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1002 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1003 bt = <->backtrace[lt->reentrancy];
1005 ast_reentrancy_unlock(lt);
1006 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1008 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1011 #endif /* DEBUG_THREADS */
1013 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
1015 time_t seconds = time(NULL);
1016 time_t wait_time, reported_wait = 0;
1018 res = pthread_rwlock_trywrlock(&t->lock);
1020 wait_time = time(NULL) - seconds;
1021 if (wait_time > reported_wait && (wait_time % 5) == 0) {
1022 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
1023 filename, line, func, (int)wait_time, name);
1025 ast_reentrancy_lock(lt);
1027 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
1029 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
1030 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1031 lt->func[lt->reentrancy-1], name);
1033 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
1035 ast_reentrancy_unlock(lt);
1037 reported_wait = wait_time;
1041 } while (res == EBUSY);
1043 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1044 res = pthread_rwlock_wrlock(&t->lock);
1045 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1047 #ifdef DEBUG_THREADS
1048 if (!res && t->tracking) {
1049 ast_reentrancy_lock(lt);
1050 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1051 lt->file[lt->reentrancy] = filename;
1052 lt->lineno[lt->reentrancy] = line;
1053 lt->func[lt->reentrancy] = func;
1054 lt->thread[lt->reentrancy] = pthread_self();
1057 ast_reentrancy_unlock(lt);
1059 ast_mark_lock_acquired(t);
1061 } else if (t->tracking) {
1063 if (lt->reentrancy) {
1064 ast_reentrancy_lock(lt);
1065 bt = <->backtrace[lt->reentrancy-1];
1066 ast_reentrancy_unlock(lt);
1071 ast_remove_lock_info(t, bt);
1075 ast_remove_lock_info(t);
1080 __ast_mutex_logger("%s line %d (%s): Error obtaining write lock: %s\n",
1081 filename, line, func, strerror(res));
1084 #endif /* DEBUG_THREADS */
1089 int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1090 const struct timespec *abs_timeout)
1094 #ifdef DEBUG_THREADS
1095 struct ast_lock_track *lt;
1096 int canlog = strcmp(filename, "logger.c") & t->tracking;
1098 struct ast_bt *bt = NULL;
1101 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1102 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1103 /* Don't warn abount uninitialized lock.
1104 * Simple try to initialize it.
1105 * May be not needed in linux system.
1107 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1108 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1109 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1110 filename, line, func, name);
1114 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1116 if (t->tracking && !t->track) {
1117 ast_reentrancy_init(&t->track);
1123 ast_reentrancy_lock(lt);
1124 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1125 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1126 bt = <->backtrace[lt->reentrancy];
1128 ast_reentrancy_unlock(lt);
1129 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1131 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1134 #endif /* DEBUG_THREADS */
1136 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1137 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1140 struct timeval _start = ast_tvnow(), _diff;
1142 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1145 _diff = ast_tvsub(ast_tvnow(), _start);
1146 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1154 #ifdef DEBUG_THREADS
1155 if (!res && t->tracking) {
1156 ast_reentrancy_lock(lt);
1157 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1158 lt->file[lt->reentrancy] = filename;
1159 lt->lineno[lt->reentrancy] = line;
1160 lt->func[lt->reentrancy] = func;
1161 lt->thread[lt->reentrancy] = pthread_self();
1164 ast_reentrancy_unlock(lt);
1166 ast_mark_lock_acquired(t);
1168 } else if (t->tracking) {
1170 if (lt->reentrancy) {
1171 ast_reentrancy_lock(lt);
1172 bt = <->backtrace[lt->reentrancy-1];
1173 ast_reentrancy_unlock(lt);
1177 ast_remove_lock_info(t, bt);
1179 ast_remove_lock_info(t);
1183 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1184 filename, line, func, strerror(res));
1187 #endif /* DEBUG_THREADS */
1192 int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1193 const struct timespec *abs_timeout)
1197 #ifdef DEBUG_THREADS
1198 struct ast_lock_track *lt;
1199 int canlog = strcmp(filename, "logger.c") & t->tracking;
1201 struct ast_bt *bt = NULL;
1204 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1205 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1206 /* Don't warn abount uninitialized lock.
1207 * Simple try to initialize it.
1208 * May be not needed in linux system.
1210 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1211 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1212 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1213 filename, line, func, name);
1217 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1219 if (t->tracking && !t->track) {
1220 ast_reentrancy_init(&t->track);
1226 ast_reentrancy_lock(lt);
1227 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1228 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1229 bt = <->backtrace[lt->reentrancy];
1231 ast_reentrancy_unlock(lt);
1232 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1234 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1237 #endif /* DEBUG_THREADS */
1239 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1240 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1243 struct timeval _start = ast_tvnow(), _diff;
1245 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1248 _diff = ast_tvsub(ast_tvnow(), _start);
1249 if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1257 #ifdef DEBUG_THREADS
1258 if (!res && t->tracking) {
1259 ast_reentrancy_lock(lt);
1260 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1261 lt->file[lt->reentrancy] = filename;
1262 lt->lineno[lt->reentrancy] = line;
1263 lt->func[lt->reentrancy] = func;
1264 lt->thread[lt->reentrancy] = pthread_self();
1267 ast_reentrancy_unlock(lt);
1269 ast_mark_lock_acquired(t);
1271 } else if (t->tracking) {
1273 if (lt->reentrancy) {
1274 ast_reentrancy_lock(lt);
1275 bt = <->backtrace[lt->reentrancy-1];
1276 ast_reentrancy_unlock(lt);
1281 ast_remove_lock_info(t, bt);
1285 ast_remove_lock_info(t);
1290 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1291 filename, line, func, strerror(res));
1294 #endif /* DEBUG_THREADS */
1299 int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1303 #ifdef DEBUG_THREADS
1304 struct ast_lock_track *lt;
1306 struct ast_bt *bt = NULL;
1308 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1309 int canlog = strcmp(filename, "logger.c") & t->tracking;
1311 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1312 /* Don't warn abount uninitialized lock.
1313 * Simple try to initialize it.
1314 * May be not needed in linux system.
1316 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1317 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1318 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1319 filename, line, func, name);
1323 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1325 if (t->tracking && !t->track) {
1326 ast_reentrancy_init(&t->track);
1332 ast_reentrancy_lock(lt);
1333 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1334 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1335 bt = <->backtrace[lt->reentrancy];
1337 ast_reentrancy_unlock(lt);
1338 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1340 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
1343 #endif /* DEBUG_THREADS */
1345 res = pthread_rwlock_tryrdlock(&t->lock);
1347 #ifdef DEBUG_THREADS
1348 if (!res && t->tracking) {
1349 ast_reentrancy_lock(lt);
1350 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1351 lt->file[lt->reentrancy] = filename;
1352 lt->lineno[lt->reentrancy] = line;
1353 lt->func[lt->reentrancy] = func;
1354 lt->thread[lt->reentrancy] = pthread_self();
1357 ast_reentrancy_unlock(lt);
1359 ast_mark_lock_acquired(t);
1361 } else if (t->tracking) {
1362 ast_mark_lock_failed(t);
1364 #endif /* DEBUG_THREADS */
1369 int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1373 #ifdef DEBUG_THREADS
1374 struct ast_lock_track *lt;
1376 struct ast_bt *bt = NULL;
1378 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1379 int canlog = strcmp(filename, "logger.c") & t->tracking;
1381 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1382 /* Don't warn abount uninitialized lock.
1383 * Simple try to initialize it.
1384 * May be not needed in linux system.
1386 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1387 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1388 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1389 filename, line, func, name);
1393 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1395 if (t->tracking && !t->track) {
1396 ast_reentrancy_init(&t->track);
1402 ast_reentrancy_lock(lt);
1403 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1404 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1405 bt = <->backtrace[lt->reentrancy];
1407 ast_reentrancy_unlock(lt);
1408 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1410 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1413 #endif /* DEBUG_THREADS */
1415 res = pthread_rwlock_trywrlock(&t->lock);
1417 #ifdef DEBUG_THREADS
1418 if (!res && t->tracking) {
1419 ast_reentrancy_lock(lt);
1420 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1421 lt->file[lt->reentrancy] = filename;
1422 lt->lineno[lt->reentrancy] = line;
1423 lt->func[lt->reentrancy] = func;
1424 lt->thread[lt->reentrancy] = pthread_self();
1427 ast_reentrancy_unlock(lt);
1428 ast_mark_lock_acquired(t);
1429 } else if (t->tracking) {
1430 ast_mark_lock_failed(t);
1432 #endif /* DEBUG_THREADS */