30 #ifdef HAVE_MTX_PROFILE
32 static int mtx_prof = -1;
33 static void __attribute__((constructor)) __mtx_init(
void)
43 #undef pthread_mutex_init
44 #undef pthread_mutex_destroy
45 #undef pthread_mutex_lock
46 #undef pthread_mutex_trylock
47 #undef pthread_mutex_t
48 #undef pthread_mutex_unlock
49 #undef pthread_cond_init
50 #undef pthread_cond_signal
51 #undef pthread_cond_broadcast
52 #undef pthread_cond_destroy
53 #undef pthread_cond_wait
54 #undef pthread_cond_timedwait
56 #if defined(DEBUG_THREADS)
57 #define log_mutex_error(canlog, ...) \
60 ast_log(LOG_ERROR, __VA_ARGS__); \
62 fprintf(stderr, __VA_ARGS__); \
67 #if defined(DEBUG_THREADS) && defined(HAVE_BKTR)
68 static void __dump_backtrace(
struct ast_bt *bt,
int canlog)
76 log_mutex_error(canlog,
"%s\n", strings[i]);
89 pthread_mutexattr_t reentr_attr;
110 fprintf(stderr,
"%s: Failed to allocate lock tracking\n", __func__);
111 #if defined(DO_CRASH) || defined(THREAD_CRASH)
119 pthread_mutexattr_init(&reentr_attr);
122 pthread_mutexattr_destroy(&reentr_attr);
129 static inline void delete_reentrancy_cs(
struct ast_lock_track **plt)
148 pthread_mutexattr_t attr;
151 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
153 int canlog = tracking && strcmp(filename,
"logger.c");
155 log_mutex_error(canlog,
"%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
163 t->flags.tracking = tracking;
167 pthread_mutexattr_init(&attr);
170 pthread_mutexattr_destroy(&attr);
181 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
182 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
184 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
192 log_mutex_error(canlog,
"%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
206 log_mutex_error(canlog,
"%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
210 log_mutex_error(canlog,
"%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
213 ast_reentrancy_lock(lt);
214 log_mutex_error(canlog,
"%s line %d (%s): Error: '%s' was locked here.\n",
219 ast_reentrancy_unlock(lt);
229 log_mutex_error(canlog,
"%s line %d (%s): Error destroying mutex %s: %s\n",
230 filename,
lineno,
func, mutex_name, strerror(res));
232 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
236 ast_reentrancy_lock(lt);
237 lt->
file[0] = filename;
245 ast_reentrancy_unlock(lt);
246 delete_reentrancy_cs(&t->track);
259 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
260 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
272 ast_reentrancy_lock(lt);
277 ast_reentrancy_unlock(lt);
279 ast_store_lock_info(
AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
283 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
285 time_t seconds = time(
NULL);
286 time_t wait_time, reported_wait = 0;
288 #ifdef HAVE_MTX_PROFILE
292 #ifdef HAVE_MTX_PROFILE
296 wait_time = time(
NULL) - seconds;
297 if (wait_time > reported_wait && (wait_time % 5) == 0) {
298 log_mutex_error(canlog,
"%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
299 filename, lineno, func, (
int) wait_time, mutex_name);
301 ast_reentrancy_lock(lt);
305 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
311 ast_reentrancy_unlock(lt);
313 reported_wait = wait_time;
317 }
while (res == EBUSY);
320 #ifdef HAVE_MTX_PROFILE
331 ast_reentrancy_lock(lt);
339 log_mutex_error(canlog,
"%s line %d (%s): '%s' really deep reentrancy!\n",
340 filename, lineno, func, mutex_name);
342 ast_reentrancy_unlock(lt);
343 ast_mark_lock_acquired(t);
347 ast_reentrancy_lock(lt);
349 ast_reentrancy_unlock(lt);
354 ast_remove_lock_info(t, bt);
357 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining mutex: %s\n",
358 filename, lineno, func, strerror(res));
372 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
373 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
385 ast_reentrancy_lock(lt);
390 ast_reentrancy_unlock(lt);
392 ast_store_lock_info(
AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
400 ast_reentrancy_lock(lt);
408 log_mutex_error(canlog,
"%s line %d (%s): '%s' really deep reentrancy!\n",
409 filename, lineno, func, mutex_name);
411 ast_reentrancy_unlock(lt);
412 ast_mark_lock_acquired(t);
428 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
431 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
433 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
434 filename, lineno, func, mutex_name);
440 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
442 ast_reentrancy_lock(lt);
444 log_mutex_error(canlog,
"%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
445 filename, lineno, func, mutex_name);
446 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
455 log_mutex_error(canlog,
"%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
456 filename, lineno, func, mutex_name);
472 ast_reentrancy_unlock(lt);
474 ast_remove_lock_info(t, bt);
482 log_mutex_error(canlog,
"%s line %d (%s): Error releasing mutex: %s\n",
483 filename, lineno, func, strerror(res));
493 const char *cond_name,
ast_cond_t *
cond, pthread_condattr_t *cond_attr)
519 ast_reentrancy_lock(lt);
535 ast_reentrancy_unlock(lt);
540 const char *cond_name,
const char *mutex_name,
548 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
550 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
552 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
559 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
561 ast_reentrancy_lock(lt);
563 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
565 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
572 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
582 ast_reentrancy_unlock(lt);
584 ast_suspend_lock_info(t);
592 log_mutex_error(canlog,
"%s line %d (%s): Error waiting on condition mutex '%s'\n",
596 restore_lock_tracking(lt, <_orig);
597 ast_restore_lock_info(t);
613 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
615 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
617 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
624 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
626 ast_reentrancy_lock(lt);
628 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
630 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
637 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
647 ast_reentrancy_unlock(lt);
649 ast_suspend_lock_info(t);
656 if (res && (res != ETIMEDOUT)) {
657 log_mutex_error(canlog,
"%s line %d (%s): Error waiting on condition mutex '%s'\n",
661 restore_lock_tracking(lt, <_orig);
662 ast_restore_lock_info(t);
672 pthread_rwlockattr_t attr;
675 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
677 int canlog = tracking && strcmp(filename,
"logger.c");
679 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
687 t->flags.tracking = tracking;
691 pthread_rwlockattr_init(&attr);
692 #ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
693 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
695 res = pthread_rwlock_init(&t->
lock, &attr);
696 pthread_rwlockattr_destroy(&attr);
706 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
707 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
709 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
711 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
720 res = pthread_rwlock_destroy(&t->
lock);
724 log_mutex_error(canlog,
"%s line %d (%s): Error destroying rwlock %s: %s\n",
725 filename,
lineno,
func, rwlock_name, strerror(res));
727 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
731 ast_reentrancy_lock(lt);
732 lt->
file[0] = filename;
740 ast_reentrancy_unlock(lt);
741 delete_reentrancy_cs(&t->track);
754 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
758 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
760 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
761 filename, line, func,
name);
767 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
769 ast_reentrancy_lock(lt);
772 pthread_t
self = pthread_self();
795 log_mutex_error(canlog,
"%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
796 filename, line, func,
name);
800 ast_reentrancy_unlock(lt);
802 ast_remove_lock_info(t, bt);
806 res = pthread_rwlock_unlock(&t->
lock);
810 log_mutex_error(canlog,
"%s line %d (%s): Error releasing rwlock: %s\n",
811 filename, line, func, strerror(res));
824 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
825 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
837 ast_reentrancy_lock(lt);
842 ast_reentrancy_unlock(lt);
844 ast_store_lock_info(
AST_RDLOCK, filename, line, func,
name, t, bt);
848 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
850 time_t seconds = time(
NULL);
851 time_t wait_time, reported_wait = 0;
853 res = pthread_rwlock_tryrdlock(&t->
lock);
855 wait_time = time(
NULL) - seconds;
856 if (wait_time > reported_wait && (wait_time % 5) == 0) {
857 log_mutex_error(canlog,
"%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
858 filename, line, func, (
int)wait_time,
name);
860 ast_reentrancy_lock(lt);
864 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
870 ast_reentrancy_unlock(lt);
872 reported_wait = wait_time;
876 }
while (res == EBUSY);
879 res = pthread_rwlock_rdlock(&t->
lock);
884 ast_reentrancy_lock(lt);
892 ast_reentrancy_unlock(lt);
893 ast_mark_lock_acquired(t);
897 ast_reentrancy_lock(lt);
899 ast_reentrancy_unlock(lt);
904 ast_remove_lock_info(t, bt);
908 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining read lock: %s\n",
909 filename, line, func, strerror(res));
922 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
923 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
935 ast_reentrancy_lock(lt);
940 ast_reentrancy_unlock(lt);
942 ast_store_lock_info(
AST_WRLOCK, filename, line, func,
name, t, bt);
946 #if defined(DETECT_DEADLOCKS) && defined(DEBUG_THREADS)
948 time_t seconds = time(
NULL);
949 time_t wait_time, reported_wait = 0;
951 res = pthread_rwlock_trywrlock(&t->
lock);
953 wait_time = time(
NULL) - seconds;
954 if (wait_time > reported_wait && (wait_time % 5) == 0) {
955 log_mutex_error(canlog,
"%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
956 filename, line, func, (
int)wait_time,
name);
958 ast_reentrancy_lock(lt);
962 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
968 ast_reentrancy_unlock(lt);
970 reported_wait = wait_time;
974 }
while (res == EBUSY);
977 res = pthread_rwlock_wrlock(&t->
lock);
982 ast_reentrancy_lock(lt);
990 ast_reentrancy_unlock(lt);
991 ast_mark_lock_acquired(t);
995 ast_reentrancy_lock(lt);
997 ast_reentrancy_unlock(lt);
1002 ast_remove_lock_info(t, bt);
1005 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining write lock: %s\n",
1006 filename, line, func, strerror(res));
1015 const struct timespec *abs_timeout)
1019 #ifdef DEBUG_THREADS
1020 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1021 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
1033 ast_reentrancy_lock(lt);
1038 ast_reentrancy_unlock(lt);
1040 ast_store_lock_info(
AST_WRLOCK, filename, line, func,
name, t, bt);
1044 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1045 res = pthread_rwlock_timedrdlock(&t->
lock, abs_timeout);
1048 struct timeval _now;
1050 if (!(res = pthread_rwlock_tryrdlock(&t->
lock))) {
1054 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1062 #ifdef DEBUG_THREADS
1064 ast_reentrancy_lock(lt);
1072 ast_reentrancy_unlock(lt);
1073 ast_mark_lock_acquired(t);
1077 ast_reentrancy_lock(lt);
1079 ast_reentrancy_unlock(lt);
1084 ast_remove_lock_info(t, bt);
1087 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining read lock: %s\n",
1088 filename, line, func, strerror(res));
1097 const struct timespec *abs_timeout)
1101 #ifdef DEBUG_THREADS
1102 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1103 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
1115 ast_reentrancy_lock(lt);
1120 ast_reentrancy_unlock(lt);
1122 ast_store_lock_info(
AST_WRLOCK, filename, line, func,
name, t, bt);
1126 #ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1127 res = pthread_rwlock_timedwrlock(&t->
lock, abs_timeout);
1130 struct timeval _now;
1132 if (!(res = pthread_rwlock_trywrlock(&t->
lock))) {
1136 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1144 #ifdef DEBUG_THREADS
1146 ast_reentrancy_lock(lt);
1154 ast_reentrancy_unlock(lt);
1155 ast_mark_lock_acquired(t);
1159 ast_reentrancy_lock(lt);
1161 ast_reentrancy_unlock(lt);
1166 ast_remove_lock_info(t, bt);
1169 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining read lock: %s\n",
1170 filename, line, func, strerror(res));
1182 #ifdef DEBUG_THREADS
1183 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1195 ast_reentrancy_lock(lt);
1200 ast_reentrancy_unlock(lt);
1202 ast_store_lock_info(
AST_RDLOCK, filename, line, func,
name, t, bt);
1206 res = pthread_rwlock_tryrdlock(&t->
lock);
1208 #ifdef DEBUG_THREADS
1210 ast_reentrancy_lock(lt);
1218 ast_reentrancy_unlock(lt);
1219 ast_mark_lock_acquired(t);
1232 #ifdef DEBUG_THREADS
1233 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1245 ast_reentrancy_lock(lt);
1250 ast_reentrancy_unlock(lt);
1252 ast_store_lock_info(
AST_WRLOCK, filename, line, func,
name, t, bt);
1256 res = pthread_rwlock_trywrlock(&t->
lock);
1258 #ifdef DEBUG_THREADS
1260 ast_reentrancy_lock(lt);
1268 ast_reentrancy_unlock(lt);
1269 ast_mark_lock_acquired(t);
Asterisk main include file. File version handling, generic pbx functions.
int ast_add_profile(const char *, uint64_t scale)
support for event profiling
int64_t ast_mark(int, int start1_stop0)
void ast_std_free(void *ptr)
void * ast_std_calloc(size_t nmemb, size_t size) attribute_malloc
#define ast_bt_get_addresses(bt)
void ast_mark_lock_failed(void *lock_addr)
int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name, const struct timespec *abs_timeout)
int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
int __ast_cond_broadcast(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name, const struct timespec *abs_timeout)
int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
int __ast_cond_init(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
int __ast_cond_wait(const char *filename, int lineno, const char *func, const char *cond_name, const char *mutex_name, ast_cond_t *cond, ast_mutex_t *t)
int __ast_cond_timedwait(const char *filename, int lineno, const char *func, const char *cond_name, const char *mutex_name, ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
int __ast_cond_signal(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
int __ast_cond_destroy(const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Asterisk locking-related definitions:
#define AST_MAX_REENTRANCY
#define __AST_RWLOCK_INIT_VALUE
#define pthread_cond_broadcast
#define pthread_mutex_trylock
#define AST_PTHREADT_NULL
#define pthread_mutex_lock
pthread_cond_t ast_cond_t
#define pthread_mutex_unlock
#define pthread_mutex_destroy
#define pthread_cond_destroy
#define pthread_cond_signal
#define AST_MUTEX_DEFINE_STATIC(mutex)
#define pthread_mutex_init
#define pthread_cond_init
#define pthread_cond_timedwait
#define pthread_cond_wait
A structure to hold backtrace information. This structure provides an easy means to store backtrace i...
void * addresses[AST_MAX_BT_FRAMES]
volatile unsigned int setup
Lock tracking information.
struct ast_bt backtrace[AST_MAX_REENTRANCY]
pthread_t thread_id[AST_MAX_REENTRANCY]
int lineno[AST_MAX_REENTRANCY]
pthread_mutex_t reentr_mutex
const char * file[AST_MAX_REENTRANCY]
const char * func[AST_MAX_REENTRANCY]
Structure for mutex and tracking information.
Structure for rwlock and tracking information.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().