2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2010, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief General Asterisk locking.
25 <support_level>core</support_level>
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32 #include "asterisk/utils.h"
33 #include "asterisk/lock.h"
35 /* Allow direct use of pthread_mutex_* / pthread_cond_* */
36 #undef pthread_mutex_init
37 #undef pthread_mutex_destroy
38 #undef pthread_mutex_lock
39 #undef pthread_mutex_trylock
40 #undef pthread_mutex_t
41 #undef pthread_mutex_unlock
42 #undef pthread_cond_init
43 #undef pthread_cond_signal
44 #undef pthread_cond_broadcast
45 #undef pthread_cond_destroy
46 #undef pthread_cond_wait
47 #undef pthread_cond_timedwait
49 #if defined(DEBUG_THREADS) && defined(HAVE_BKTR)
50 static void __dump_backtrace(struct ast_bt *bt, int canlog)
55 strings = backtrace_symbols(bt->addresses, bt->num_frames);
57 for (i = 0; i < bt->num_frames; i++) {
58 __ast_mutex_logger("%s\n", strings[i]);
61 ast_std_free(strings);
63 #endif /* defined(DEBUG_THREADS) && defined(HAVE_BKTR) */
65 int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func,
66 const char *mutex_name, ast_mutex_t *t)
69 pthread_mutexattr_t attr;
73 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
74 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
76 int canlog = strcmp(filename, "logger.c") & track;
77 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
78 filename, lineno, func, mutex_name);
84 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
86 if ((t->tracking = tracking)) {
87 ast_reentrancy_init(&t->track);
89 #endif /* DEBUG_THREADS */
91 pthread_mutexattr_init(&attr);
92 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
94 res = pthread_mutex_init(&t->mutex, &attr);
95 pthread_mutexattr_destroy(&attr);
99 int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func,
100 const char *mutex_name, ast_mutex_t *t)
105 struct ast_lock_track *lt;
106 int canlog = strcmp(filename, "logger.c") & t->tracking;
108 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
109 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
110 /* Don't try to uninitialize non initialized mutex
111 * This may no effect on linux
112 * And always ganerate core on *BSD with
114 * This not error condition if the mutex created on the fly.
116 __ast_mutex_logger("%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
117 filename, lineno, func, mutex_name);
122 if (t->tracking && !t->track) {
123 ast_reentrancy_init(&t->track);
127 res = pthread_mutex_trylock(&t->mutex);
130 pthread_mutex_unlock(&t->mutex);
133 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
134 filename, lineno, func, mutex_name);
137 __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
138 filename, lineno, func, mutex_name);
140 ast_reentrancy_lock(lt);
141 __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
142 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
144 __dump_backtrace(<->backtrace[ROFFSET], canlog);
146 ast_reentrancy_unlock(lt);
150 #endif /* DEBUG_THREADS */
152 res = pthread_mutex_destroy(&t->mutex);
156 __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
157 filename, lineno, func, mutex_name, strerror(res));
160 ast_reentrancy_lock(lt);
161 lt->file[0] = filename;
162 lt->lineno[0] = lineno;
167 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
169 ast_reentrancy_unlock(lt);
170 delete_reentrancy_cs(&t->track);
172 #endif /* DEBUG_THREADS */
177 int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
178 const char* mutex_name, ast_mutex_t *t)
183 struct ast_lock_track *lt;
184 int canlog = strcmp(filename, "logger.c") & t->tracking;
186 struct ast_bt *bt = NULL;
189 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
190 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
191 /* Don't warn abount uninitialized mutex.
192 * Simple try to initialize it.
193 * May be not needed in linux system.
195 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
196 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
197 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
198 filename, lineno, func, mutex_name);
202 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
204 if (t->tracking && !t->track) {
205 ast_reentrancy_init(&t->track);
211 ast_reentrancy_lock(lt);
212 if (lt->reentrancy != AST_MAX_REENTRANCY) {
213 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
214 bt = <->backtrace[lt->reentrancy];
216 ast_reentrancy_unlock(lt);
217 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
219 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
222 #endif /* DEBUG_THREADS */
224 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
226 time_t seconds = time(NULL);
227 time_t wait_time, reported_wait = 0;
229 #ifdef HAVE_MTX_PROFILE
230 ast_mark(mtx_prof, 1);
232 res = pthread_mutex_trylock(&t->mutex);
233 #ifdef HAVE_MTX_PROFILE
234 ast_mark(mtx_prof, 0);
237 wait_time = time(NULL) - seconds;
238 if (wait_time > reported_wait && (wait_time % 5) == 0) {
239 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
240 filename, lineno, func, (int) wait_time, mutex_name);
241 ast_reentrancy_lock(lt);
243 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
245 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
246 lt->file[ROFFSET], lt->lineno[ROFFSET],
247 lt->func[ROFFSET], mutex_name);
249 __dump_backtrace(<->backtrace[ROFFSET], canlog);
251 ast_reentrancy_unlock(lt);
252 reported_wait = wait_time;
256 } while (res == EBUSY);
258 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
259 #ifdef HAVE_MTX_PROFILE
260 ast_mark(mtx_prof, 1);
261 res = pthread_mutex_trylock(&t->mutex);
262 ast_mark(mtx_prof, 0);
265 res = pthread_mutex_lock(&t->mutex);
266 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
269 if (t->tracking && !res) {
270 ast_reentrancy_lock(lt);
271 if (lt->reentrancy < AST_MAX_REENTRANCY) {
272 lt->file[lt->reentrancy] = filename;
273 lt->lineno[lt->reentrancy] = lineno;
274 lt->func[lt->reentrancy] = func;
275 lt->thread[lt->reentrancy] = pthread_self();
278 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
279 filename, lineno, func, mutex_name);
281 ast_reentrancy_unlock(lt);
283 ast_mark_lock_acquired(t);
285 } else if (t->tracking) {
287 if (lt->reentrancy) {
288 ast_reentrancy_lock(lt);
289 bt = <->backtrace[lt->reentrancy-1];
290 ast_reentrancy_unlock(lt);
294 ast_remove_lock_info(t, bt);
296 ast_remove_lock_info(t);
300 __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
301 filename, lineno, func, strerror(res));
304 #endif /* DEBUG_THREADS */
309 int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
310 const char* mutex_name, ast_mutex_t *t)
315 struct ast_lock_track *lt;
316 int canlog = strcmp(filename, "logger.c") & t->tracking;
318 struct ast_bt *bt = NULL;
321 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
322 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
323 /* Don't warn abount uninitialized mutex.
324 * Simple try to initialize it.
325 * May be not needed in linux system.
327 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
328 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
329 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
330 filename, lineno, func, mutex_name);
334 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
336 if (t->tracking && !t->track) {
337 ast_reentrancy_init(&t->track);
343 ast_reentrancy_lock(lt);
344 if (lt->reentrancy != AST_MAX_REENTRANCY) {
345 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
346 bt = <->backtrace[lt->reentrancy];
348 ast_reentrancy_unlock(lt);
349 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
351 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
354 #endif /* DEBUG_THREADS */
356 res = pthread_mutex_trylock(&t->mutex);
359 if (t->tracking && !res) {
360 ast_reentrancy_lock(lt);
361 if (lt->reentrancy < AST_MAX_REENTRANCY) {
362 lt->file[lt->reentrancy] = filename;
363 lt->lineno[lt->reentrancy] = lineno;
364 lt->func[lt->reentrancy] = func;
365 lt->thread[lt->reentrancy] = pthread_self();
368 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
369 filename, lineno, func, mutex_name);
371 ast_reentrancy_unlock(lt);
373 ast_mark_lock_acquired(t);
375 } else if (t->tracking) {
376 ast_mark_lock_failed(t);
378 #endif /* DEBUG_THREADS */
383 int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func,
384 const char *mutex_name, ast_mutex_t *t)
389 struct ast_lock_track *lt;
390 int canlog = strcmp(filename, "logger.c") & t->tracking;
392 struct ast_bt *bt = NULL;
395 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
396 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
397 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
398 filename, lineno, func, mutex_name);
399 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
400 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
401 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
402 filename, lineno, func, mutex_name);
406 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
408 if (t->tracking && !t->track) {
409 ast_reentrancy_init(&t->track);
414 ast_reentrancy_lock(lt);
415 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
416 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
417 filename, lineno, func, mutex_name);
418 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
419 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
421 __dump_backtrace(<->backtrace[ROFFSET], canlog);
426 if (--lt->reentrancy < 0) {
427 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
428 filename, lineno, func, mutex_name);
432 if (lt->reentrancy < AST_MAX_REENTRANCY) {
433 lt->file[lt->reentrancy] = NULL;
434 lt->lineno[lt->reentrancy] = 0;
435 lt->func[lt->reentrancy] = NULL;
436 lt->thread[lt->reentrancy] = 0;
440 if (lt->reentrancy) {
441 bt = <->backtrace[lt->reentrancy - 1];
444 ast_reentrancy_unlock(lt);
447 ast_remove_lock_info(t, bt);
449 ast_remove_lock_info(t);
452 #endif /* DEBUG_THREADS */
454 res = pthread_mutex_unlock(&t->mutex);
458 __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
459 filename, lineno, func, strerror(res));
462 #endif /* DEBUG_THREADS */
468 int __ast_cond_init(const char *filename, int lineno, const char *func,
469 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
471 return pthread_cond_init(cond, cond_attr);
474 int __ast_cond_signal(const char *filename, int lineno, const char *func,
475 const char *cond_name, ast_cond_t *cond)
477 return pthread_cond_signal(cond);
480 int __ast_cond_broadcast(const char *filename, int lineno, const char *func,
481 const char *cond_name, ast_cond_t *cond)
483 return pthread_cond_broadcast(cond);
486 int __ast_cond_destroy(const char *filename, int lineno, const char *func,
487 const char *cond_name, ast_cond_t *cond)
489 return pthread_cond_destroy(cond);
492 int __ast_cond_wait(const char *filename, int lineno, const char *func,
493 const char *cond_name, const char *mutex_name,
494 ast_cond_t *cond, ast_mutex_t *t)
499 struct ast_lock_track *lt;
500 int canlog = strcmp(filename, "logger.c") & t->tracking;
502 struct ast_bt *bt = NULL;
505 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
506 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
507 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
508 filename, lineno, func, mutex_name);
509 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
510 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
511 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
512 filename, lineno, func, mutex_name);
516 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
518 if (t->tracking && !t->track) {
519 ast_reentrancy_init(&t->track);
524 ast_reentrancy_lock(lt);
525 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
526 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
527 filename, lineno, func, mutex_name);
528 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
529 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
531 __dump_backtrace(<->backtrace[ROFFSET], canlog);
536 if (--lt->reentrancy < 0) {
537 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
538 filename, lineno, func, mutex_name);
542 if (lt->reentrancy < AST_MAX_REENTRANCY) {
543 lt->file[lt->reentrancy] = NULL;
544 lt->lineno[lt->reentrancy] = 0;
545 lt->func[lt->reentrancy] = NULL;
546 lt->thread[lt->reentrancy] = 0;
550 if (lt->reentrancy) {
551 bt = <->backtrace[lt->reentrancy - 1];
554 ast_reentrancy_unlock(lt);
557 ast_remove_lock_info(t, bt);
559 ast_remove_lock_info(t);
562 #endif /* DEBUG_THREADS */
564 res = pthread_cond_wait(cond, &t->mutex);
568 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
569 filename, lineno, func, strerror(res));
571 } else if (t->tracking) {
572 ast_reentrancy_lock(lt);
573 if (lt->reentrancy < AST_MAX_REENTRANCY) {
574 lt->file[lt->reentrancy] = filename;
575 lt->lineno[lt->reentrancy] = lineno;
576 lt->func[lt->reentrancy] = func;
577 lt->thread[lt->reentrancy] = pthread_self();
579 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
580 bt = <->backtrace[lt->reentrancy];
584 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
585 filename, lineno, func, mutex_name);
587 ast_reentrancy_unlock(lt);
590 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
592 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
595 #endif /* DEBUG_THREADS */
600 int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
601 const char *cond_name, const char *mutex_name, ast_cond_t *cond,
602 ast_mutex_t *t, const struct timespec *abstime)
607 struct ast_lock_track *lt;
608 int canlog = strcmp(filename, "logger.c") & t->tracking;
610 struct ast_bt *bt = NULL;
613 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
614 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
615 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
616 filename, lineno, func, mutex_name);
617 res = __ast_pthread_mutex_init(t->tracking, filename, lineno, func, mutex_name, t);
618 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
619 __ast_mutex_logger("%s line %d (%s): Error: mutex '%s' is uninitialized and unable to initialize.\n",
620 filename, lineno, func, mutex_name);
624 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
626 if (t->tracking && !t->track) {
627 ast_reentrancy_init(&t->track);
632 ast_reentrancy_lock(lt);
633 if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
634 __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
635 filename, lineno, func, mutex_name);
636 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
637 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
639 __dump_backtrace(<->backtrace[ROFFSET], canlog);
644 if (--lt->reentrancy < 0) {
645 __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
646 filename, lineno, func, mutex_name);
650 if (lt->reentrancy < AST_MAX_REENTRANCY) {
651 lt->file[lt->reentrancy] = NULL;
652 lt->lineno[lt->reentrancy] = 0;
653 lt->func[lt->reentrancy] = NULL;
654 lt->thread[lt->reentrancy] = 0;
657 if (lt->reentrancy) {
658 bt = <->backtrace[lt->reentrancy - 1];
661 ast_reentrancy_unlock(lt);
664 ast_remove_lock_info(t, bt);
666 ast_remove_lock_info(t);
669 #endif /* DEBUG_THREADS */
671 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
674 if (res && (res != ETIMEDOUT)) {
675 __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
676 filename, lineno, func, strerror(res));
678 } else if (t->tracking) {
679 ast_reentrancy_lock(lt);
680 if (lt->reentrancy < AST_MAX_REENTRANCY) {
681 lt->file[lt->reentrancy] = filename;
682 lt->lineno[lt->reentrancy] = lineno;
683 lt->func[lt->reentrancy] = func;
684 lt->thread[lt->reentrancy] = pthread_self();
686 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
687 bt = <->backtrace[lt->reentrancy];
691 __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
692 filename, lineno, func, mutex_name);
694 ast_reentrancy_unlock(lt);
697 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
699 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
702 #endif /* DEBUG_THREADS */
707 int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
710 pthread_rwlockattr_t attr;
714 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
715 int canlog = strcmp(filename, "logger.c") & t->tracking;
717 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
718 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
719 filename, lineno, func, rwlock_name);
722 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
724 if ((t->tracking = tracking)) {
725 ast_reentrancy_init(&t->track);
727 #endif /* DEBUG_THREADS */
729 pthread_rwlockattr_init(&attr);
731 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
732 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
735 res = pthread_rwlock_init(&t->lock, &attr);
736 pthread_rwlockattr_destroy(&attr);
740 int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
745 struct ast_lock_track *lt = t->track;
746 int canlog = strcmp(filename, "logger.c") & t->tracking;
748 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
749 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
750 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
751 filename, lineno, func, rwlock_name);
754 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
756 #endif /* DEBUG_THREADS */
758 res = pthread_rwlock_destroy(&t->lock);
762 __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
763 filename, lineno, func, rwlock_name, strerror(res));
765 if (t->tracking && lt) {
766 ast_reentrancy_lock(lt);
767 lt->file[0] = filename;
768 lt->lineno[0] = lineno;
773 memset(<->backtrace[0], 0, sizeof(lt->backtrace[0]));
775 ast_reentrancy_unlock(lt);
776 delete_reentrancy_cs(&t->track);
778 #endif /* DEBUG_THREADS */
783 int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
788 struct ast_lock_track *lt;
789 int canlog = strcmp(filename, "logger.c") & t->tracking;
791 struct ast_bt *bt = NULL;
796 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
797 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
798 __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
799 filename, line, func, name);
800 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
801 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
802 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
803 filename, line, func, name);
807 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
809 if (t->tracking && !t->track) {
810 ast_reentrancy_init(&t->track);
815 ast_reentrancy_lock(lt);
816 if (lt->reentrancy) {
818 pthread_t self = pthread_self();
819 for (i = lt->reentrancy - 1; i >= 0; --i) {
820 if (lt->thread[i] == self) {
822 if (i != lt->reentrancy - 1) {
823 lt->file[i] = lt->file[lt->reentrancy - 1];
824 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
825 lt->func[i] = lt->func[lt->reentrancy - 1];
826 lt->thread[i] = lt->thread[lt->reentrancy - 1];
829 bt = <->backtrace[i];
831 lt->file[lt->reentrancy - 1] = NULL;
832 lt->lineno[lt->reentrancy - 1] = 0;
833 lt->func[lt->reentrancy - 1] = NULL;
834 lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
840 if (lock_found && --lt->reentrancy < 0) {
841 __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
842 filename, line, func, name);
846 ast_reentrancy_unlock(lt);
849 ast_remove_lock_info(t, bt);
851 ast_remove_lock_info(t);
854 #endif /* DEBUG_THREADS */
856 res = pthread_rwlock_unlock(&t->lock);
860 __ast_mutex_logger("%s line %d (%s): Error releasing rwlock: %s\n",
861 filename, line, func, strerror(res));
864 #endif /* DEBUG_THREADS */
869 int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
874 struct ast_lock_track *lt;
875 int canlog = strcmp(filename, "logger.c") & t->tracking;
877 struct ast_bt *bt = NULL;
880 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
881 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
882 /* Don't warn abount uninitialized lock.
883 * Simple try to initialize it.
884 * May be not needed in linux system.
886 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
887 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
888 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
889 filename, line, func, name);
893 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
895 if (t->tracking && !t->track) {
896 ast_reentrancy_init(&t->track);
902 ast_reentrancy_lock(lt);
903 if (lt->reentrancy != AST_MAX_REENTRANCY) {
904 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
905 bt = <->backtrace[lt->reentrancy];
907 ast_reentrancy_unlock(lt);
908 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
910 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
913 #endif /* DEBUG_THREADS */
915 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
917 time_t seconds = time(NULL);
918 time_t wait_time, reported_wait = 0;
920 res = pthread_rwlock_tryrdlock(&t->lock);
922 wait_time = time(NULL) - seconds;
923 if (wait_time > reported_wait && (wait_time % 5) == 0) {
924 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
925 filename, line, func, (int)wait_time, name);
927 ast_reentrancy_lock(lt);
929 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
931 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
932 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
933 lt->func[lt->reentrancy-1], name);
935 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
937 ast_reentrancy_unlock(lt);
939 reported_wait = wait_time;
943 } while (res == EBUSY);
945 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
946 res = pthread_rwlock_rdlock(&t->lock);
947 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
950 if (!res && t->tracking) {
951 ast_reentrancy_lock(lt);
952 if (lt->reentrancy < AST_MAX_REENTRANCY) {
953 lt->file[lt->reentrancy] = filename;
954 lt->lineno[lt->reentrancy] = line;
955 lt->func[lt->reentrancy] = func;
956 lt->thread[lt->reentrancy] = pthread_self();
959 ast_reentrancy_unlock(lt);
961 ast_mark_lock_acquired(t);
963 } else if (t->tracking) {
965 if (lt->reentrancy) {
966 ast_reentrancy_lock(lt);
967 bt = <->backtrace[lt->reentrancy-1];
968 ast_reentrancy_unlock(lt);
972 ast_remove_lock_info(t, bt);
974 ast_remove_lock_info(t);
979 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
980 filename, line, func, strerror(res));
983 #endif /* DEBUG_THREADS */
988 int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
993 struct ast_lock_track *lt;
994 int canlog = strcmp(filename, "logger.c") & t->tracking;
996 struct ast_bt *bt = NULL;
999 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1000 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1001 /* Don't warn abount uninitialized lock.
1002 * Simple try to initialize it.
1003 * May be not needed in linux system.
1005 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1006 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1007 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1008 filename, line, func, name);
1012 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1014 if (t->tracking && !t->track) {
1015 ast_reentrancy_init(&t->track);
1021 ast_reentrancy_lock(lt);
1022 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1023 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1024 bt = <->backtrace[lt->reentrancy];
1026 ast_reentrancy_unlock(lt);
1027 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1029 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1032 #endif /* DEBUG_THREADS */
1034 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
1036 time_t seconds = time(NULL);
1037 time_t wait_time, reported_wait = 0;
1039 res = pthread_rwlock_trywrlock(&t->lock);
1041 wait_time = time(NULL) - seconds;
1042 if (wait_time > reported_wait && (wait_time % 5) == 0) {
1043 __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
1044 filename, line, func, (int)wait_time, name);
1046 ast_reentrancy_lock(lt);
1048 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
1050 __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
1051 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1052 lt->func[lt->reentrancy-1], name);
1054 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
1056 ast_reentrancy_unlock(lt);
1058 reported_wait = wait_time;
1062 } while (res == EBUSY);
1064 #else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1065 res = pthread_rwlock_wrlock(&t->lock);
1066 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
1068 #ifdef DEBUG_THREADS
1069 if (!res && t->tracking) {
1070 ast_reentrancy_lock(lt);
1071 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1072 lt->file[lt->reentrancy] = filename;
1073 lt->lineno[lt->reentrancy] = line;
1074 lt->func[lt->reentrancy] = func;
1075 lt->thread[lt->reentrancy] = pthread_self();
1078 ast_reentrancy_unlock(lt);
1080 ast_mark_lock_acquired(t);
1082 } else if (t->tracking) {
1084 if (lt->reentrancy) {
1085 ast_reentrancy_lock(lt);
1086 bt = <->backtrace[lt->reentrancy-1];
1087 ast_reentrancy_unlock(lt);
1092 ast_remove_lock_info(t, bt);
1096 ast_remove_lock_info(t);
1101 __ast_mutex_logger("%s line %d (%s): Error obtaining write lock: %s\n",
1102 filename, line, func, strerror(res));
1105 #endif /* DEBUG_THREADS */
1110 int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1111 const struct timespec *abs_timeout)
1115 #ifdef DEBUG_THREADS
1116 struct ast_lock_track *lt;
1117 int canlog = strcmp(filename, "logger.c") & t->tracking;
1119 struct ast_bt *bt = NULL;
1122 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1123 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1124 /* Don't warn abount uninitialized lock.
1125 * Simple try to initialize it.
1126 * May be not needed in linux system.
1128 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1129 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1130 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1131 filename, line, func, name);
1135 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1137 if (t->tracking && !t->track) {
1138 ast_reentrancy_init(&t->track);
1144 ast_reentrancy_lock(lt);
1145 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1146 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1147 bt = <->backtrace[lt->reentrancy];
1149 ast_reentrancy_unlock(lt);
1150 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1152 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1155 #endif /* DEBUG_THREADS */
1157 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1158 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1161 struct timeval _now;
1163 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1167 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1175 #ifdef DEBUG_THREADS
1176 if (!res && t->tracking) {
1177 ast_reentrancy_lock(lt);
1178 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1179 lt->file[lt->reentrancy] = filename;
1180 lt->lineno[lt->reentrancy] = line;
1181 lt->func[lt->reentrancy] = func;
1182 lt->thread[lt->reentrancy] = pthread_self();
1185 ast_reentrancy_unlock(lt);
1187 ast_mark_lock_acquired(t);
1189 } else if (t->tracking) {
1191 if (lt->reentrancy) {
1192 ast_reentrancy_lock(lt);
1193 bt = <->backtrace[lt->reentrancy-1];
1194 ast_reentrancy_unlock(lt);
1198 ast_remove_lock_info(t, bt);
1200 ast_remove_lock_info(t);
1204 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1205 filename, line, func, strerror(res));
1208 #endif /* DEBUG_THREADS */
1213 int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
1214 const struct timespec *abs_timeout)
1218 #ifdef DEBUG_THREADS
1219 struct ast_lock_track *lt;
1220 int canlog = strcmp(filename, "logger.c") & t->tracking;
1222 struct ast_bt *bt = NULL;
1225 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1226 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1227 /* Don't warn abount uninitialized lock.
1228 * Simple try to initialize it.
1229 * May be not needed in linux system.
1231 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1232 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1233 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1234 filename, line, func, name);
1238 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1240 if (t->tracking && !t->track) {
1241 ast_reentrancy_init(&t->track);
1247 ast_reentrancy_lock(lt);
1248 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1249 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1250 bt = <->backtrace[lt->reentrancy];
1252 ast_reentrancy_unlock(lt);
1253 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1255 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1258 #endif /* DEBUG_THREADS */
1260 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1261 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1264 struct timeval _now;
1266 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1270 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1278 #ifdef DEBUG_THREADS
1279 if (!res && t->tracking) {
1280 ast_reentrancy_lock(lt);
1281 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1282 lt->file[lt->reentrancy] = filename;
1283 lt->lineno[lt->reentrancy] = line;
1284 lt->func[lt->reentrancy] = func;
1285 lt->thread[lt->reentrancy] = pthread_self();
1288 ast_reentrancy_unlock(lt);
1290 ast_mark_lock_acquired(t);
1292 } else if (t->tracking) {
1294 if (lt->reentrancy) {
1295 ast_reentrancy_lock(lt);
1296 bt = <->backtrace[lt->reentrancy-1];
1297 ast_reentrancy_unlock(lt);
1302 ast_remove_lock_info(t, bt);
1306 ast_remove_lock_info(t);
1311 __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
1312 filename, line, func, strerror(res));
1315 #endif /* DEBUG_THREADS */
1320 int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1324 #ifdef DEBUG_THREADS
1325 struct ast_lock_track *lt;
1327 struct ast_bt *bt = NULL;
1329 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1330 int canlog = strcmp(filename, "logger.c") & t->tracking;
1332 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1333 /* Don't warn abount uninitialized lock.
1334 * Simple try to initialize it.
1335 * May be not needed in linux system.
1337 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1338 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1339 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1340 filename, line, func, name);
1344 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1346 if (t->tracking && !t->track) {
1347 ast_reentrancy_init(&t->track);
1353 ast_reentrancy_lock(lt);
1354 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1355 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1356 bt = <->backtrace[lt->reentrancy];
1358 ast_reentrancy_unlock(lt);
1359 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1361 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
1364 #endif /* DEBUG_THREADS */
1366 res = pthread_rwlock_tryrdlock(&t->lock);
1368 #ifdef DEBUG_THREADS
1369 if (!res && t->tracking) {
1370 ast_reentrancy_lock(lt);
1371 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1372 lt->file[lt->reentrancy] = filename;
1373 lt->lineno[lt->reentrancy] = line;
1374 lt->func[lt->reentrancy] = func;
1375 lt->thread[lt->reentrancy] = pthread_self();
1378 ast_reentrancy_unlock(lt);
1380 ast_mark_lock_acquired(t);
1382 } else if (t->tracking) {
1383 ast_mark_lock_failed(t);
1385 #endif /* DEBUG_THREADS */
1390 int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
1394 #ifdef DEBUG_THREADS
1395 struct ast_lock_track *lt;
1397 struct ast_bt *bt = NULL;
1399 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
1400 int canlog = strcmp(filename, "logger.c") & t->tracking;
1402 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1403 /* Don't warn abount uninitialized lock.
1404 * Simple try to initialize it.
1405 * May be not needed in linux system.
1407 res = __ast_rwlock_init(t->tracking, filename, line, func, name, t);
1408 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
1409 __ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
1410 filename, line, func, name);
1414 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
1416 if (t->tracking && !t->track) {
1417 ast_reentrancy_init(&t->track);
1423 ast_reentrancy_lock(lt);
1424 if (lt->reentrancy != AST_MAX_REENTRANCY) {
1425 ast_bt_get_addresses(<->backtrace[lt->reentrancy]);
1426 bt = <->backtrace[lt->reentrancy];
1428 ast_reentrancy_unlock(lt);
1429 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1431 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
1434 #endif /* DEBUG_THREADS */
1436 res = pthread_rwlock_trywrlock(&t->lock);
1438 #ifdef DEBUG_THREADS
1439 if (!res && t->tracking) {
1440 ast_reentrancy_lock(lt);
1441 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1442 lt->file[lt->reentrancy] = filename;
1443 lt->lineno[lt->reentrancy] = line;
1444 lt->func[lt->reentrancy] = func;
1445 lt->thread[lt->reentrancy] = pthread_self();
1448 ast_reentrancy_unlock(lt);
1449 ast_mark_lock_acquired(t);
1450 } else if (t->tracking) {
1451 ast_mark_lock_failed(t);
1453 #endif /* DEBUG_THREADS */