30#ifdef HAVE_MTX_PROFILE
32static int mtx_prof = -1;
33static 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
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)
69static void __dump_backtrace(
struct ast_bt *bt,
int canlog)
77 log_mutex_error(canlog,
"%s\n", strings[i]);
90 pthread_mutexattr_t reentr_attr;
111 fprintf(stderr,
"%s: Failed to allocate lock tracking\n", __func__);
112#if defined(DO_CRASH) || defined(THREAD_CRASH)
120 pthread_mutexattr_init(&reentr_attr);
123 pthread_mutexattr_destroy(&reentr_attr);
130static inline void delete_reentrancy_cs(
struct ast_lock_track **plt)
149 pthread_mutexattr_t attr;
151#if defined(DEBUG_THREADS) && defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && \
152 defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
154 int canlog = tracking && strcmp(filename,
"logger.c");
156 log_mutex_error(canlog,
"%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
163#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
165 t->flags.tracking = tracking;
169 pthread_mutexattr_init(&attr);
172 pthread_mutexattr_destroy(&attr);
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)
194 log_mutex_error(canlog,
"%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
208 log_mutex_error(canlog,
"%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
212 log_mutex_error(canlog,
"%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
215 ast_reentrancy_lock(lt);
216 log_mutex_error(canlog,
"%s line %d (%s): Error: '%s' was locked here.\n",
221 ast_reentrancy_unlock(lt);
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;
247 ast_reentrancy_unlock(lt);
248 delete_reentrancy_cs(&t->track);
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);
277 ast_reentrancy_lock(lt);
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
297#ifdef HAVE_MTX_PROFILE
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);
311 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
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
358 ast_reentrancy_lock(lt);
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);
374 ast_reentrancy_lock(lt);
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));
399 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
400 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
412 ast_reentrancy_lock(lt);
417 ast_reentrancy_unlock(lt);
419 ast_store_lock_info(
AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
427 ast_reentrancy_lock(lt);
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);
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)
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);
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",
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);
499 ast_reentrancy_unlock(lt);
501 ast_remove_lock_info(t, bt);
509 log_mutex_error(canlog,
"%s line %d (%s): Error releasing mutex: %s\n",
510 filename, lineno, func, strerror(res));
520 const char *cond_name,
ast_cond_t *
cond, pthread_condattr_t *cond_attr)
546 ast_reentrancy_lock(lt);
562 ast_reentrancy_unlock(lt);
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)
579 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
586 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
588 ast_reentrancy_lock(lt);
590 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
592 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
599 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
609 ast_reentrancy_unlock(lt);
611 ast_suspend_lock_info(t);
619 log_mutex_error(canlog,
"%s line %d (%s): Error waiting on condition mutex '%s'\n",
623 restore_lock_tracking(lt, <_orig);
624 ast_restore_lock_info(t);
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)
644 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
651 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
653 ast_reentrancy_lock(lt);
655 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
657 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
664 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
674 ast_reentrancy_unlock(lt);
676 ast_suspend_lock_info(t);
683 if (res && (res != ETIMEDOUT)) {
684 log_mutex_error(canlog,
"%s line %d (%s): Error waiting on condition mutex '%s'\n",
688 restore_lock_tracking(lt, <_orig);
689 ast_restore_lock_info(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)
705 int canlog = tracking && strcmp(filename,
"logger.c");
707 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
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);
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)
740 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
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;
769 ast_reentrancy_unlock(lt);
770 delete_reentrancy_cs(&t->track);
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)
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);
801 pthread_t self = pthread_self();
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));
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);
870 ast_reentrancy_lock(lt);
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);
898 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
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);
927 ast_reentrancy_unlock(lt);
928 ast_mark_lock_acquired(t);
932 ast_reentrancy_lock(lt);
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));
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);
974 ast_reentrancy_lock(lt);
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);
1002 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
1008 ast_reentrancy_unlock(lt);
1011 reported_wait = wait_time;
1015 }
while (res == EBUSY);
1018 res = pthread_rwlock_wrlock(&t->
lock);
1023 ast_reentrancy_lock(lt);
1031 ast_reentrancy_unlock(lt);
1032 ast_mark_lock_acquired(t);
1036 ast_reentrancy_lock(lt);
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));
1056 const struct timespec *abs_timeout)
1061 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1062 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
1074 ast_reentrancy_lock(lt);
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)) {
1105 ast_reentrancy_lock(lt);
1113 ast_reentrancy_unlock(lt);
1114 ast_mark_lock_acquired(t);
1118 ast_reentrancy_lock(lt);
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));
1138 const struct timespec *abs_timeout)
1143 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1144 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
1156 ast_reentrancy_lock(lt);
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)) {
1187 ast_reentrancy_lock(lt);
1195 ast_reentrancy_unlock(lt);
1196 ast_mark_lock_acquired(t);
1200 ast_reentrancy_lock(lt);
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));
1224 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1236 ast_reentrancy_lock(lt);
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);
1251 ast_reentrancy_lock(lt);
1259 ast_reentrancy_unlock(lt);
1260 ast_mark_lock_acquired(t);
1274 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1286 ast_reentrancy_lock(lt);
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);
1301 ast_reentrancy_lock(lt);
1309 ast_reentrancy_unlock(lt);
1310 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
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
#define EVENT_FLAG_SYSTEM
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().