30 #ifdef HAVE_MTX_PROFILE
32 static int mtx_prof = -1;
33 static void __attribute__((constructor)) __mtx_init(
void)
44 #undef pthread_mutex_init
45 #undef pthread_mutex_destroy
46 #undef pthread_mutex_lock
47 #undef pthread_mutex_trylock
48 #undef pthread_mutex_t
49 #undef pthread_mutex_unlock
50 #undef pthread_cond_init
51 #undef pthread_cond_signal
52 #undef pthread_cond_broadcast
53 #undef pthread_cond_destroy
54 #undef pthread_cond_wait
55 #undef pthread_cond_timedwait
57 #if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
58 #define log_mutex_error(canlog, ...) \
61 ast_log(LOG_ERROR, __VA_ARGS__); \
63 fprintf(stderr, __VA_ARGS__); \
68 #if defined(DEBUG_THREADS) && defined(HAVE_BKTR)
69 static void __dump_backtrace(
struct ast_bt *bt,
int canlog)
77 log_mutex_error(canlog,
"%s\n", strings[i]);
80 ast_std_free(strings);
85 AST_MUTEX_DEFINE_STATIC(reentrancy_lock);
90 pthread_mutexattr_t reentr_attr;
97 pthread_mutex_lock(&reentrancy_lock.mutex);
100 pthread_mutex_unlock(&reentrancy_lock.mutex);
105 pthread_mutex_unlock(&reentrancy_lock.mutex);
109 lt = *plt = ast_std_calloc(1,
sizeof(*lt));
111 fprintf(stderr,
"%s: Failed to allocate lock tracking\n", __func__);
112 #if defined(DO_CRASH) || defined(THREAD_CRASH)
115 pthread_mutex_unlock(&reentrancy_lock.mutex);
120 pthread_mutexattr_init(&reentr_attr);
121 pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
122 pthread_mutex_init(<->reentr_mutex, &reentr_attr);
123 pthread_mutexattr_destroy(&reentr_attr);
126 pthread_mutex_unlock(&reentrancy_lock.mutex);
130 static inline void delete_reentrancy_cs(
struct ast_lock_track **plt)
138 pthread_mutex_destroy(<->reentr_mutex);
145 int __ast_pthread_mutex_init(
int tracking,
const char *filename,
int lineno,
const char *func,
149 pthread_mutexattr_t attr;
151 #if defined(DEBUG_THREADS) && defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && \
152 defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
153 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
154 int canlog = tracking && strcmp(filename,
"logger.c");
156 log_mutex_error(canlog,
"%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
157 filename, lineno, func, mutex_name);
163 #if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
165 t->flags.tracking = tracking;
169 pthread_mutexattr_init(&attr);
170 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
171 res = pthread_mutex_init(&t->mutex, &attr);
172 pthread_mutexattr_destroy(&attr);
177 int __ast_pthread_mutex_destroy(
const char *filename,
int lineno,
const char *func,
183 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
184 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
186 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
187 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
194 log_mutex_error(canlog,
"%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
195 filename, lineno, func, mutex_name);
202 res = pthread_mutex_trylock(&t->mutex);
205 pthread_mutex_unlock(&t->mutex);
208 log_mutex_error(canlog,
"%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
209 filename, lineno, func, mutex_name);
212 log_mutex_error(canlog,
"%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
213 filename, lineno, func, mutex_name);
215 ast_reentrancy_lock(lt);
216 log_mutex_error(canlog,
"%s line %d (%s): Error: '%s' was locked here.\n",
217 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
219 __dump_backtrace(<->backtrace[ROFFSET], canlog);
221 ast_reentrancy_unlock(lt);
227 res = pthread_mutex_destroy(&t->mutex);
231 log_mutex_error(canlog,
"%s line %d (%s): Error destroying mutex %s: %s\n",
232 filename, lineno, func, mutex_name, strerror(res));
234 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
238 ast_reentrancy_lock(lt);
239 lt->file[0] = filename;
240 lt->lineno[0] = lineno;
243 lt->thread_id[0] = 0;
245 memset(<->backtrace[0], 0,
sizeof(lt->backtrace[0]));
247 ast_reentrancy_unlock(lt);
248 delete_reentrancy_cs(&t->track);
255 int __ast_pthread_mutex_lock(
const char *filename,
int lineno,
const char *func,
260 #if defined(DETECT_DEADLOCKS) || defined(DEBUG_THREADS)
261 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
265 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
275 ast_bt_get_addresses(&tmp);
277 ast_reentrancy_lock(lt);
278 if (lt->reentrancy < AST_MAX_REENTRANCY) {
279 lt->backtrace[lt->reentrancy] = tmp;
280 bt = <->backtrace[lt->reentrancy];
282 ast_reentrancy_unlock(lt);
284 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
288 #if defined(DETECT_DEADLOCKS)
290 time_t seconds = time(NULL);
291 time_t wait_time, reported_wait = 0;
293 #ifdef HAVE_MTX_PROFILE
294 ast_mark(mtx_prof, 1);
296 res = pthread_mutex_trylock(&t->mutex);
297 #ifdef HAVE_MTX_PROFILE
298 ast_mark(mtx_prof, 0);
301 wait_time = time(NULL) - seconds;
302 if (wait_time > reported_wait && (wait_time % 5) == 0) {
303 log_mutex_error(canlog,
"%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
304 filename, lineno, func, (
int) wait_time, mutex_name);
307 ast_reentrancy_lock(lt);
309 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
311 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
312 lt->file[ROFFSET], lt->lineno[ROFFSET],
313 lt->func[ROFFSET], mutex_name);
315 __dump_backtrace(<->backtrace[ROFFSET], canlog);
317 ast_reentrancy_unlock(lt);
320 reported_wait = wait_time;
321 if ((
int) wait_time < 10) {
344 }
while (res == EBUSY);
347 #ifdef HAVE_MTX_PROFILE
348 ast_mark(mtx_prof, 1);
349 res = pthread_mutex_trylock(&t->mutex);
350 ast_mark(mtx_prof, 0);
353 res = pthread_mutex_lock(&t->mutex);
358 ast_reentrancy_lock(lt);
359 if (lt->reentrancy < AST_MAX_REENTRANCY) {
360 lt->file[lt->reentrancy] = filename;
361 lt->lineno[lt->reentrancy] = lineno;
362 lt->func[lt->reentrancy] = func;
363 lt->thread_id[lt->reentrancy] = pthread_self();
366 log_mutex_error(canlog,
"%s line %d (%s): '%s' really deep reentrancy!\n",
367 filename, lineno, func, mutex_name);
369 ast_reentrancy_unlock(lt);
370 ast_mark_lock_acquired(t);
373 if (lt->reentrancy) {
374 ast_reentrancy_lock(lt);
375 bt = <->backtrace[lt->reentrancy-1];
376 ast_reentrancy_unlock(lt);
381 ast_remove_lock_info(t, bt);
384 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining mutex: %s\n",
385 filename, lineno, func, strerror(res));
393 int __ast_pthread_mutex_trylock(
const char *filename,
int lineno,
const char *func,
399 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
400 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
410 ast_bt_get_addresses(&tmp);
412 ast_reentrancy_lock(lt);
413 if (lt->reentrancy < AST_MAX_REENTRANCY) {
414 lt->backtrace[lt->reentrancy] = tmp;
415 bt = <->backtrace[lt->reentrancy];
417 ast_reentrancy_unlock(lt);
419 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
423 res = pthread_mutex_trylock(&t->mutex);
427 ast_reentrancy_lock(lt);
428 if (lt->reentrancy < AST_MAX_REENTRANCY) {
429 lt->file[lt->reentrancy] = filename;
430 lt->lineno[lt->reentrancy] = lineno;
431 lt->func[lt->reentrancy] = func;
432 lt->thread_id[lt->reentrancy] = pthread_self();
435 log_mutex_error(canlog,
"%s line %d (%s): '%s' really deep reentrancy!\n",
436 filename, lineno, func, mutex_name);
438 ast_reentrancy_unlock(lt);
439 ast_mark_lock_acquired(t);
441 ast_mark_lock_failed(t);
448 int __ast_pthread_mutex_unlock(
const char *filename,
int lineno,
const char *func,
455 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
458 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
459 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
460 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
461 filename, lineno, func, mutex_name);
467 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
469 ast_reentrancy_lock(lt);
470 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
471 log_mutex_error(canlog,
"%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
472 filename, lineno, func, mutex_name);
473 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
474 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
476 __dump_backtrace(<->backtrace[ROFFSET], canlog);
481 if (--lt->reentrancy < 0) {
482 log_mutex_error(canlog,
"%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
483 filename, lineno, func, mutex_name);
487 if (lt->reentrancy < AST_MAX_REENTRANCY) {
488 lt->file[lt->reentrancy] = NULL;
489 lt->lineno[lt->reentrancy] = 0;
490 lt->func[lt->reentrancy] = NULL;
491 lt->thread_id[lt->reentrancy] = 0;
495 if (lt->reentrancy) {
496 bt = <->backtrace[lt->reentrancy - 1];
499 ast_reentrancy_unlock(lt);
501 ast_remove_lock_info(t, bt);
505 res = pthread_mutex_unlock(&t->mutex);
509 log_mutex_error(canlog,
"%s line %d (%s): Error releasing mutex: %s\n",
510 filename, lineno, func, strerror(res));
519 int __ast_cond_init(
const char *filename,
int lineno,
const char *func,
520 const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
522 return pthread_cond_init(cond, cond_attr);
525 int __ast_cond_signal(
const char *filename,
int lineno,
const char *func,
526 const char *cond_name, ast_cond_t *cond)
528 return pthread_cond_signal(cond);
531 int __ast_cond_broadcast(
const char *filename,
int lineno,
const char *func,
532 const char *cond_name, ast_cond_t *cond)
534 return pthread_cond_broadcast(cond);
537 int __ast_cond_destroy(
const char *filename,
int lineno,
const char *func,
538 const char *cond_name, ast_cond_t *cond)
540 return pthread_cond_destroy(cond);
546 ast_reentrancy_lock(lt);
553 memcpy(lt->file, lt_saved->file,
sizeof(lt->file));
554 memcpy(lt->lineno, lt_saved->lineno,
sizeof(lt->lineno));
555 lt->reentrancy = lt_saved->reentrancy;
556 memcpy(lt->func, lt_saved->func,
sizeof(lt->func));
557 memcpy(lt->thread_id, lt_saved->thread_id,
sizeof(lt->thread_id));
559 memcpy(lt->backtrace, lt_saved->backtrace,
sizeof(lt->backtrace));
562 ast_reentrancy_unlock(lt);
566 int __ast_cond_wait(
const char *filename,
int lineno,
const char *func,
567 const char *cond_name,
const char *mutex_name,
575 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
577 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
578 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
579 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
580 filename, lineno, func, mutex_name);
586 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
588 ast_reentrancy_lock(lt);
589 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
590 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
591 filename, lineno, func, mutex_name);
592 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
593 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
595 __dump_backtrace(<->backtrace[ROFFSET], canlog);
598 }
else if (lt->reentrancy <= 0) {
599 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
600 filename, lineno, func, mutex_name);
609 ast_reentrancy_unlock(lt);
611 ast_suspend_lock_info(t);
615 res = pthread_cond_wait(cond, &t->mutex);
619 log_mutex_error(canlog,
"%s line %d (%s): Error waiting on condition mutex '%s'\n",
620 filename, lineno, func, strerror(res));
623 restore_lock_tracking(lt, <_orig);
624 ast_restore_lock_info(t);
631 int __ast_cond_timedwait(
const char *filename,
int lineno,
const char *func,
632 const char *cond_name,
const char *mutex_name, ast_cond_t *cond,
640 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
642 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
643 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
644 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
645 filename, lineno, func, mutex_name);
651 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
653 ast_reentrancy_lock(lt);
654 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
655 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
656 filename, lineno, func, mutex_name);
657 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
658 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
660 __dump_backtrace(<->backtrace[ROFFSET], canlog);
663 }
else if (lt->reentrancy <= 0) {
664 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
665 filename, lineno, func, mutex_name);
674 ast_reentrancy_unlock(lt);
676 ast_suspend_lock_info(t);
680 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
683 if (res && (res != ETIMEDOUT)) {
684 log_mutex_error(canlog,
"%s line %d (%s): Error waiting on condition mutex '%s'\n",
685 filename, lineno, func, strerror(res));
688 restore_lock_tracking(lt, <_orig);
689 ast_restore_lock_info(t);
696 int __ast_rwlock_init(
int tracking,
const char *filename,
int lineno, \
697 const char *func,
const char *rwlock_name,
ast_rwlock_t *t)
700 pthread_rwlockattr_t attr;
702 #if defined(DEBUG_THREADS) && defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && \
703 defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
704 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
705 int canlog = tracking && strcmp(filename,
"logger.c");
707 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
708 filename, lineno, func, rwlock_name);
714 #if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
716 t->flags.tracking = tracking;
720 pthread_rwlockattr_init(&attr);
721 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
722 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
724 res = pthread_rwlock_init(&t->lock, &attr);
725 pthread_rwlockattr_destroy(&attr);
730 int __ast_rwlock_destroy(
const char *filename,
int lineno,
const char *func,
const char *rwlock_name,
ast_rwlock_t *t)
735 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
736 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
738 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
739 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
740 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
741 filename, lineno, func, rwlock_name);
749 res = pthread_rwlock_destroy(&t->lock);
753 log_mutex_error(canlog,
"%s line %d (%s): Error destroying rwlock %s: %s\n",
754 filename, lineno, func, rwlock_name, strerror(res));
756 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
760 ast_reentrancy_lock(lt);
761 lt->file[0] = filename;
762 lt->lineno[0] = lineno;
765 lt->thread_id[0] = 0;
767 memset(<->backtrace[0], 0,
sizeof(lt->backtrace[0]));
769 ast_reentrancy_unlock(lt);
770 delete_reentrancy_cs(&t->track);
777 int __ast_rwlock_unlock(
const char *filename,
int line,
const char *func,
ast_rwlock_t *t,
const char *name)
783 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
787 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
788 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
789 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
790 filename, line, func, name);
796 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
798 ast_reentrancy_lock(lt);
799 if (lt->reentrancy) {
801 pthread_t
self = pthread_self();
802 for (i = lt->reentrancy - 1; i >= 0; --i) {
803 if (lt->thread_id[i] ==
self) {
805 if (i != lt->reentrancy - 1) {
806 lt->file[i] = lt->file[lt->reentrancy - 1];
807 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
808 lt->func[i] = lt->func[lt->reentrancy - 1];
809 lt->thread_id[i] = lt->thread_id[lt->reentrancy - 1];
812 bt = <->backtrace[i];
814 lt->file[lt->reentrancy - 1] = NULL;
815 lt->lineno[lt->reentrancy - 1] = 0;
816 lt->func[lt->reentrancy - 1] = NULL;
817 lt->thread_id[lt->reentrancy - 1] = AST_PTHREADT_NULL;
823 if (lock_found && --lt->reentrancy < 0) {
824 log_mutex_error(canlog,
"%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
825 filename, line, func, name);
829 ast_reentrancy_unlock(lt);
831 ast_remove_lock_info(t, bt);
835 res = pthread_rwlock_unlock(&t->lock);
839 log_mutex_error(canlog,
"%s line %d (%s): Error releasing rwlock: %s\n",
840 filename, line, func, strerror(res));
848 int __ast_rwlock_rdlock(
const char *filename,
int line,
const char *func,
853 #if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
854 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
858 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
868 ast_bt_get_addresses(&tmp);
870 ast_reentrancy_lock(lt);
871 if (lt->reentrancy < AST_MAX_REENTRANCY) {
872 lt->backtrace[lt->reentrancy] = tmp;
873 bt = <->backtrace[lt->reentrancy];
875 ast_reentrancy_unlock(lt);
877 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
881 #if defined(DETECT_DEADLOCKS)
883 time_t seconds = time(NULL);
884 time_t wait_time, reported_wait = 0;
886 res = pthread_rwlock_tryrdlock(&t->lock);
888 wait_time = time(NULL) - seconds;
889 if (wait_time > reported_wait && (wait_time % 5) == 0) {
890 log_mutex_error(canlog,
"%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
891 filename, line, func, (
int)wait_time, name);
894 ast_reentrancy_lock(lt);
896 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
898 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
899 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
900 lt->func[lt->reentrancy-1], name);
902 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
904 ast_reentrancy_unlock(lt);
907 reported_wait = wait_time;
911 }
while (res == EBUSY);
914 res = pthread_rwlock_rdlock(&t->lock);
919 ast_reentrancy_lock(lt);
920 if (lt->reentrancy < AST_MAX_REENTRANCY) {
921 lt->file[lt->reentrancy] = filename;
922 lt->lineno[lt->reentrancy] = line;
923 lt->func[lt->reentrancy] = func;
924 lt->thread_id[lt->reentrancy] = pthread_self();
927 ast_reentrancy_unlock(lt);
928 ast_mark_lock_acquired(t);
931 if (lt->reentrancy) {
932 ast_reentrancy_lock(lt);
933 bt = <->backtrace[lt->reentrancy-1];
934 ast_reentrancy_unlock(lt);
939 ast_remove_lock_info(t, bt);
943 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining read lock: %s\n",
944 filename, line, func, strerror(res));
952 int __ast_rwlock_wrlock(
const char *filename,
int line,
const char *func, \
957 #if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
958 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
962 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
972 ast_bt_get_addresses(&tmp);
974 ast_reentrancy_lock(lt);
975 if (lt->reentrancy < AST_MAX_REENTRANCY) {
976 lt->backtrace[lt->reentrancy] = tmp;
977 bt = <->backtrace[lt->reentrancy];
979 ast_reentrancy_unlock(lt);
981 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
985 #ifdef DETECT_DEADLOCKS
987 time_t seconds = time(NULL);
988 time_t wait_time, reported_wait = 0;
990 res = pthread_rwlock_trywrlock(&t->lock);
992 wait_time = time(NULL) - seconds;
993 if (wait_time > reported_wait && (wait_time % 5) == 0) {
994 log_mutex_error(canlog,
"%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
995 filename, line, func, (
int)wait_time, name);
998 ast_reentrancy_lock(lt);
1000 __dump_backtrace(<->backtrace[lt->reentrancy], canlog);
1002 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
1003 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1004 lt->func[lt->reentrancy-1], name);
1006 __dump_backtrace(<->backtrace[lt->reentrancy-1], canlog);
1008 ast_reentrancy_unlock(lt);
1011 reported_wait = wait_time;
1015 }
while (res == EBUSY);
1018 res = pthread_rwlock_wrlock(&t->lock);
1021 #ifdef DEBUG_THREADS
1023 ast_reentrancy_lock(lt);
1024 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1025 lt->file[lt->reentrancy] = filename;
1026 lt->lineno[lt->reentrancy] = line;
1027 lt->func[lt->reentrancy] = func;
1028 lt->thread_id[lt->reentrancy] = pthread_self();
1031 ast_reentrancy_unlock(lt);
1032 ast_mark_lock_acquired(t);
1035 if (lt->reentrancy) {
1036 ast_reentrancy_lock(lt);
1037 bt = <->backtrace[lt->reentrancy-1];
1038 ast_reentrancy_unlock(lt);
1043 ast_remove_lock_info(t, bt);
1046 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining write lock: %s\n",
1047 filename, line, func, strerror(res));
1055 int __ast_rwlock_timedrdlock(
const char *filename,
int line,
const char *func,
ast_rwlock_t *t,
const char *name,
1056 const struct timespec *abs_timeout)
1060 #ifdef DEBUG_THREADS
1061 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1062 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
1063 struct ast_bt *bt = NULL;
1072 ast_bt_get_addresses(&tmp);
1074 ast_reentrancy_lock(lt);
1075 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1076 lt->backtrace[lt->reentrancy] = tmp;
1077 bt = <->backtrace[lt->reentrancy];
1079 ast_reentrancy_unlock(lt);
1081 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1085 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1086 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1089 struct timeval _now;
1091 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1095 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1103 #ifdef DEBUG_THREADS
1105 ast_reentrancy_lock(lt);
1106 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1107 lt->file[lt->reentrancy] = filename;
1108 lt->lineno[lt->reentrancy] = line;
1109 lt->func[lt->reentrancy] = func;
1110 lt->thread_id[lt->reentrancy] = pthread_self();
1113 ast_reentrancy_unlock(lt);
1114 ast_mark_lock_acquired(t);
1117 if (lt->reentrancy) {
1118 ast_reentrancy_lock(lt);
1119 bt = <->backtrace[lt->reentrancy-1];
1120 ast_reentrancy_unlock(lt);
1125 ast_remove_lock_info(t, bt);
1128 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining read lock: %s\n",
1129 filename, line, func, strerror(res));
1137 int __ast_rwlock_timedwrlock(
const char *filename,
int line,
const char *func,
ast_rwlock_t *t,
const char *name,
1138 const struct timespec *abs_timeout)
1142 #ifdef DEBUG_THREADS
1143 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1144 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
1145 struct ast_bt *bt = NULL;
1154 ast_bt_get_addresses(&tmp);
1156 ast_reentrancy_lock(lt);
1157 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1158 lt->backtrace[lt->reentrancy] = tmp;
1159 bt = <->backtrace[lt->reentrancy];
1161 ast_reentrancy_unlock(lt);
1163 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1167 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1168 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1171 struct timeval _now;
1173 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1177 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1185 #ifdef DEBUG_THREADS
1187 ast_reentrancy_lock(lt);
1188 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1189 lt->file[lt->reentrancy] = filename;
1190 lt->lineno[lt->reentrancy] = line;
1191 lt->func[lt->reentrancy] = func;
1192 lt->thread_id[lt->reentrancy] = pthread_self();
1195 ast_reentrancy_unlock(lt);
1196 ast_mark_lock_acquired(t);
1199 if (lt->reentrancy) {
1200 ast_reentrancy_lock(lt);
1201 bt = <->backtrace[lt->reentrancy-1];
1202 ast_reentrancy_unlock(lt);
1207 ast_remove_lock_info(t, bt);
1210 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining read lock: %s\n",
1211 filename, line, func, strerror(res));
1219 int __ast_rwlock_tryrdlock(
const char *filename,
int line,
const char *func,
ast_rwlock_t *t,
const char *name)
1223 #ifdef DEBUG_THREADS
1224 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1225 struct ast_bt *bt = NULL;
1234 ast_bt_get_addresses(&tmp);
1236 ast_reentrancy_lock(lt);
1237 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1238 lt->backtrace[lt->reentrancy] = tmp;
1239 bt = <->backtrace[lt->reentrancy];
1241 ast_reentrancy_unlock(lt);
1243 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1247 res = pthread_rwlock_tryrdlock(&t->lock);
1249 #ifdef DEBUG_THREADS
1251 ast_reentrancy_lock(lt);
1252 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1253 lt->file[lt->reentrancy] = filename;
1254 lt->lineno[lt->reentrancy] = line;
1255 lt->func[lt->reentrancy] = func;
1256 lt->thread_id[lt->reentrancy] = pthread_self();
1259 ast_reentrancy_unlock(lt);
1260 ast_mark_lock_acquired(t);
1262 ast_mark_lock_failed(t);
1269 int __ast_rwlock_trywrlock(
const char *filename,
int line,
const char *func,
ast_rwlock_t *t,
const char *name)
1273 #ifdef DEBUG_THREADS
1274 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1275 struct ast_bt *bt = NULL;
1284 ast_bt_get_addresses(&tmp);
1286 ast_reentrancy_lock(lt);
1287 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1288 lt->backtrace[lt->reentrancy] = tmp;
1289 bt = <->backtrace[lt->reentrancy];
1291 ast_reentrancy_unlock(lt);
1293 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1297 res = pthread_rwlock_trywrlock(&t->lock);
1299 #ifdef DEBUG_THREADS
1301 ast_reentrancy_lock(lt);
1302 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1303 lt->file[lt->reentrancy] = filename;
1304 lt->lineno[lt->reentrancy] = line;
1305 lt->func[lt->reentrancy] = func;
1306 lt->thread_id[lt->reentrancy] = pthread_self();
1309 ast_reentrancy_unlock(lt);
1310 ast_mark_lock_acquired(t);
1312 ast_mark_lock_failed(t);
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
A structure to hold backtrace information. This structure provides an easy means to store backtrace i...
Lock tracking information.
volatile unsigned int setup
int ast_add_profile(const char *, uint64_t scale)
support for event profiling
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
void * addresses[AST_MAX_BT_FRAMES]
Structure for rwlock and tracking information.
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Structure for mutex and tracking information.