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) {
349 }
while (res == EBUSY);
352#ifdef HAVE_MTX_PROFILE
363 ast_reentrancy_lock(lt);
371 log_mutex_error(canlog,
"%s line %d (%s): '%s' really deep reentrancy!\n",
372 filename, lineno, func, mutex_name);
374 ast_reentrancy_unlock(lt);
375 ast_mark_lock_acquired(t);
379 ast_reentrancy_lock(lt);
381 ast_reentrancy_unlock(lt);
386 ast_remove_lock_info(t, bt);
389 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining mutex: %s\n",
390 filename, lineno, func, strerror(res));
404 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
405 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
417 ast_reentrancy_lock(lt);
422 ast_reentrancy_unlock(lt);
424 ast_store_lock_info(
AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
432 ast_reentrancy_lock(lt);
440 log_mutex_error(canlog,
"%s line %d (%s): '%s' really deep reentrancy!\n",
441 filename, lineno, func, mutex_name);
443 ast_reentrancy_unlock(lt);
444 ast_mark_lock_acquired(t);
460 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
463#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
465 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
466 filename, lineno, func, mutex_name);
472 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
474 ast_reentrancy_lock(lt);
476 log_mutex_error(canlog,
"%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
477 filename, lineno, func, mutex_name);
478 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
487 log_mutex_error(canlog,
"%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
488 filename, lineno, func, mutex_name);
504 ast_reentrancy_unlock(lt);
506 ast_remove_lock_info(t, bt);
519 if (res && strcmp(filename,
"logger.c")) {
521 mutex_name, filename, lineno, func, strerror(res));
527 log_mutex_error(canlog,
"%s line %d (%s): Error releasing mutex: %s\n",
528 filename, lineno, func, strerror(res));
538 const char *cond_name,
ast_cond_t *
cond, pthread_condattr_t *cond_attr)
564 ast_reentrancy_lock(lt);
580 ast_reentrancy_unlock(lt);
585 const char *cond_name,
const char *mutex_name,
593 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
595#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
597 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
604 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
606 ast_reentrancy_lock(lt);
608 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
610 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
617 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
627 ast_reentrancy_unlock(lt);
629 ast_suspend_lock_info(t);
637 log_mutex_error(canlog,
"%s line %d (%s): Error waiting on condition mutex '%s'\n",
641 restore_lock_tracking(lt, <_orig);
642 ast_restore_lock_info(t);
658 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
660#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
662 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
669 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
671 ast_reentrancy_lock(lt);
673 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
675 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
682 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
692 ast_reentrancy_unlock(lt);
694 ast_suspend_lock_info(t);
701 if (res && (res != ETIMEDOUT)) {
702 log_mutex_error(canlog,
"%s line %d (%s): Error waiting on condition mutex '%s'\n",
706 restore_lock_tracking(lt, <_orig);
707 ast_restore_lock_info(t);
718 pthread_rwlockattr_t attr;
720#if defined(DEBUG_THREADS) && defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && \
721 defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
723 int canlog = tracking && strcmp(filename,
"logger.c");
725 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
732#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
734 t->flags.tracking = tracking;
738 pthread_rwlockattr_init(&attr);
739#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
740 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
742 res = pthread_rwlock_init(&t->
lock, &attr);
743 pthread_rwlockattr_destroy(&attr);
753 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
754 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
756#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
758 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
767 res = pthread_rwlock_destroy(&t->
lock);
771 log_mutex_error(canlog,
"%s line %d (%s): Error destroying rwlock %s: %s\n",
772 filename,
lineno,
func, rwlock_name, strerror(res));
774#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
778 ast_reentrancy_lock(lt);
779 lt->
file[0] = filename;
787 ast_reentrancy_unlock(lt);
788 delete_reentrancy_cs(&t->track);
801 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
805#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
807 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
808 filename, line, func,
name);
814 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
816 ast_reentrancy_lock(lt);
819 pthread_t self = pthread_self();
842 log_mutex_error(canlog,
"%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
843 filename, line, func,
name);
847 ast_reentrancy_unlock(lt);
849 ast_remove_lock_info(t, bt);
853 res = pthread_rwlock_unlock(&t->
lock);
857 log_mutex_error(canlog,
"%s line %d (%s): Error releasing rwlock: %s\n",
858 filename, line, func, strerror(res));
871#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
872 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
876 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
888 ast_reentrancy_lock(lt);
893 ast_reentrancy_unlock(lt);
895 ast_store_lock_info(
AST_RDLOCK, filename, line, func,
name, t, bt);
899#if defined(DETECT_DEADLOCKS)
901 time_t seconds = time(
NULL);
902 time_t wait_time, reported_wait = 0;
904 res = pthread_rwlock_tryrdlock(&t->
lock);
906 wait_time = time(
NULL) - seconds;
907 if (wait_time > reported_wait && (wait_time % 5) == 0) {
908 log_mutex_error(canlog,
"%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
909 filename, line, func, (
int)wait_time,
name);
912 ast_reentrancy_lock(lt);
916 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
922 ast_reentrancy_unlock(lt);
925 reported_wait = wait_time;
929 }
while (res == EBUSY);
932 res = pthread_rwlock_rdlock(&t->
lock);
937 ast_reentrancy_lock(lt);
945 ast_reentrancy_unlock(lt);
946 ast_mark_lock_acquired(t);
950 ast_reentrancy_lock(lt);
952 ast_reentrancy_unlock(lt);
957 ast_remove_lock_info(t, bt);
961 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining read lock: %s\n",
962 filename, line, func, strerror(res));
975#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
976 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
980 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
992 ast_reentrancy_lock(lt);
997 ast_reentrancy_unlock(lt);
999 ast_store_lock_info(
AST_WRLOCK, filename, line, func,
name, t, bt);
1003#ifdef DETECT_DEADLOCKS
1005 time_t seconds = time(
NULL);
1006 time_t wait_time, reported_wait = 0;
1008 res = pthread_rwlock_trywrlock(&t->
lock);
1010 wait_time = time(
NULL) - seconds;
1011 if (wait_time > reported_wait && (wait_time % 5) == 0) {
1012 log_mutex_error(canlog,
"%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
1013 filename, line, func, (
int)wait_time,
name);
1016 ast_reentrancy_lock(lt);
1020 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
1026 ast_reentrancy_unlock(lt);
1029 reported_wait = wait_time;
1033 }
while (res == EBUSY);
1036 res = pthread_rwlock_wrlock(&t->
lock);
1041 ast_reentrancy_lock(lt);
1049 ast_reentrancy_unlock(lt);
1050 ast_mark_lock_acquired(t);
1054 ast_reentrancy_lock(lt);
1056 ast_reentrancy_unlock(lt);
1061 ast_remove_lock_info(t, bt);
1064 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining write lock: %s\n",
1065 filename, line, func, strerror(res));
1074 const struct timespec *abs_timeout)
1079 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1080 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
1092 ast_reentrancy_lock(lt);
1097 ast_reentrancy_unlock(lt);
1099 ast_store_lock_info(
AST_WRLOCK, filename, line, func,
name, t, bt);
1103#ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1104 res = pthread_rwlock_timedrdlock(&t->
lock, abs_timeout);
1107 struct timeval _now;
1109 if (!(res = pthread_rwlock_tryrdlock(&t->
lock))) {
1113 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1123 ast_reentrancy_lock(lt);
1131 ast_reentrancy_unlock(lt);
1132 ast_mark_lock_acquired(t);
1136 ast_reentrancy_lock(lt);
1138 ast_reentrancy_unlock(lt);
1143 ast_remove_lock_info(t, bt);
1146 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining read lock: %s\n",
1147 filename, line, func, strerror(res));
1156 const struct timespec *abs_timeout)
1161 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1162 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
1174 ast_reentrancy_lock(lt);
1179 ast_reentrancy_unlock(lt);
1181 ast_store_lock_info(
AST_WRLOCK, filename, line, func,
name, t, bt);
1185#ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1186 res = pthread_rwlock_timedwrlock(&t->
lock, abs_timeout);
1189 struct timeval _now;
1191 if (!(res = pthread_rwlock_trywrlock(&t->
lock))) {
1195 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1205 ast_reentrancy_lock(lt);
1213 ast_reentrancy_unlock(lt);
1214 ast_mark_lock_acquired(t);
1218 ast_reentrancy_lock(lt);
1220 ast_reentrancy_unlock(lt);
1225 ast_remove_lock_info(t, bt);
1228 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining read lock: %s\n",
1229 filename, line, func, strerror(res));
1242 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1254 ast_reentrancy_lock(lt);
1259 ast_reentrancy_unlock(lt);
1261 ast_store_lock_info(
AST_RDLOCK, filename, line, func,
name, t, bt);
1265 res = pthread_rwlock_tryrdlock(&t->
lock);
1269 ast_reentrancy_lock(lt);
1277 ast_reentrancy_unlock(lt);
1278 ast_mark_lock_acquired(t);
1292 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1304 ast_reentrancy_lock(lt);
1309 ast_reentrancy_unlock(lt);
1311 ast_store_lock_info(
AST_WRLOCK, filename, line, func,
name, t, bt);
1315 res = pthread_rwlock_trywrlock(&t->
lock);
1319 ast_reentrancy_lock(lt);
1327 ast_reentrancy_unlock(lt);
1328 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().