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);
514 log_mutex_error(canlog,
"%s line %d (%s): Error releasing mutex: %s\n",
515 filename, lineno, func, strerror(res));
525 const char *cond_name,
ast_cond_t *
cond, pthread_condattr_t *cond_attr)
551 ast_reentrancy_lock(lt);
567 ast_reentrancy_unlock(lt);
572 const char *cond_name,
const char *mutex_name,
580 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
582#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
584 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
591 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
593 ast_reentrancy_lock(lt);
595 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
597 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
604 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
614 ast_reentrancy_unlock(lt);
616 ast_suspend_lock_info(t);
624 log_mutex_error(canlog,
"%s line %d (%s): Error waiting on condition mutex '%s'\n",
628 restore_lock_tracking(lt, <_orig);
629 ast_restore_lock_info(t);
645 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
647#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
649 log_mutex_error(canlog,
"%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
656 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
658 ast_reentrancy_lock(lt);
660 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
662 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
669 log_mutex_error(canlog,
"%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
679 ast_reentrancy_unlock(lt);
681 ast_suspend_lock_info(t);
688 if (res && (res != ETIMEDOUT)) {
689 log_mutex_error(canlog,
"%s line %d (%s): Error waiting on condition mutex '%s'\n",
693 restore_lock_tracking(lt, <_orig);
694 ast_restore_lock_info(t);
705 pthread_rwlockattr_t attr;
707#if defined(DEBUG_THREADS) && defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && \
708 defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
710 int canlog = tracking && strcmp(filename,
"logger.c");
712 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
719#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
721 t->flags.tracking = tracking;
725 pthread_rwlockattr_init(&attr);
726#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
727 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
729 res = pthread_rwlock_init(&t->
lock, &attr);
730 pthread_rwlockattr_destroy(&attr);
740 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
741 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
743#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
745 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
754 res = pthread_rwlock_destroy(&t->
lock);
758 log_mutex_error(canlog,
"%s line %d (%s): Error destroying rwlock %s: %s\n",
759 filename,
lineno,
func, rwlock_name, strerror(res));
761#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
765 ast_reentrancy_lock(lt);
766 lt->
file[0] = filename;
774 ast_reentrancy_unlock(lt);
775 delete_reentrancy_cs(&t->track);
788 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
792#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
794 log_mutex_error(canlog,
"%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
795 filename, line, func,
name);
801 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
803 ast_reentrancy_lock(lt);
806 pthread_t self = pthread_self();
829 log_mutex_error(canlog,
"%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
830 filename, line, func,
name);
834 ast_reentrancy_unlock(lt);
836 ast_remove_lock_info(t, bt);
840 res = pthread_rwlock_unlock(&t->
lock);
844 log_mutex_error(canlog,
"%s line %d (%s): Error releasing rwlock: %s\n",
845 filename, line, func, strerror(res));
858#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
859 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
863 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
875 ast_reentrancy_lock(lt);
880 ast_reentrancy_unlock(lt);
882 ast_store_lock_info(
AST_RDLOCK, filename, line, func,
name, t, bt);
886#if defined(DETECT_DEADLOCKS)
888 time_t seconds = time(
NULL);
889 time_t wait_time, reported_wait = 0;
891 res = pthread_rwlock_tryrdlock(&t->
lock);
893 wait_time = time(
NULL) - seconds;
894 if (wait_time > reported_wait && (wait_time % 5) == 0) {
895 log_mutex_error(canlog,
"%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
896 filename, line, func, (
int)wait_time,
name);
899 ast_reentrancy_lock(lt);
903 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
909 ast_reentrancy_unlock(lt);
912 reported_wait = wait_time;
916 }
while (res == EBUSY);
919 res = pthread_rwlock_rdlock(&t->
lock);
924 ast_reentrancy_lock(lt);
932 ast_reentrancy_unlock(lt);
933 ast_mark_lock_acquired(t);
937 ast_reentrancy_lock(lt);
939 ast_reentrancy_unlock(lt);
944 ast_remove_lock_info(t, bt);
948 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining read lock: %s\n",
949 filename, line, func, strerror(res));
962#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
963 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
967 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
979 ast_reentrancy_lock(lt);
984 ast_reentrancy_unlock(lt);
986 ast_store_lock_info(
AST_WRLOCK, filename, line, func,
name, t, bt);
990#ifdef DETECT_DEADLOCKS
992 time_t seconds = time(
NULL);
993 time_t wait_time, reported_wait = 0;
995 res = pthread_rwlock_trywrlock(&t->
lock);
997 wait_time = time(
NULL) - seconds;
998 if (wait_time > reported_wait && (wait_time % 5) == 0) {
999 log_mutex_error(canlog,
"%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
1000 filename, line, func, (
int)wait_time,
name);
1003 ast_reentrancy_lock(lt);
1007 log_mutex_error(canlog,
"%s line %d (%s): '%s' was locked here.\n",
1013 ast_reentrancy_unlock(lt);
1016 reported_wait = wait_time;
1020 }
while (res == EBUSY);
1023 res = pthread_rwlock_wrlock(&t->
lock);
1028 ast_reentrancy_lock(lt);
1036 ast_reentrancy_unlock(lt);
1037 ast_mark_lock_acquired(t);
1041 ast_reentrancy_lock(lt);
1043 ast_reentrancy_unlock(lt);
1048 ast_remove_lock_info(t, bt);
1051 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining write lock: %s\n",
1052 filename, line, func, strerror(res));
1061 const struct timespec *abs_timeout)
1066 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1067 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
1079 ast_reentrancy_lock(lt);
1084 ast_reentrancy_unlock(lt);
1086 ast_store_lock_info(
AST_WRLOCK, filename, line, func,
name, t, bt);
1090#ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1091 res = pthread_rwlock_timedrdlock(&t->
lock, abs_timeout);
1094 struct timeval _now;
1096 if (!(res = pthread_rwlock_tryrdlock(&t->
lock))) {
1100 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1110 ast_reentrancy_lock(lt);
1118 ast_reentrancy_unlock(lt);
1119 ast_mark_lock_acquired(t);
1123 ast_reentrancy_lock(lt);
1125 ast_reentrancy_unlock(lt);
1130 ast_remove_lock_info(t, bt);
1133 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining read lock: %s\n",
1134 filename, line, func, strerror(res));
1143 const struct timespec *abs_timeout)
1148 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1149 int canlog = t->flags.tracking && strcmp(filename,
"logger.c");
1161 ast_reentrancy_lock(lt);
1166 ast_reentrancy_unlock(lt);
1168 ast_store_lock_info(
AST_WRLOCK, filename, line, func,
name, t, bt);
1172#ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1173 res = pthread_rwlock_timedwrlock(&t->
lock, abs_timeout);
1176 struct timeval _now;
1178 if (!(res = pthread_rwlock_trywrlock(&t->
lock))) {
1182 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1192 ast_reentrancy_lock(lt);
1200 ast_reentrancy_unlock(lt);
1201 ast_mark_lock_acquired(t);
1205 ast_reentrancy_lock(lt);
1207 ast_reentrancy_unlock(lt);
1212 ast_remove_lock_info(t, bt);
1215 log_mutex_error(canlog,
"%s line %d (%s): Error obtaining read lock: %s\n",
1216 filename, line, func, strerror(res));
1229 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1241 ast_reentrancy_lock(lt);
1246 ast_reentrancy_unlock(lt);
1248 ast_store_lock_info(
AST_RDLOCK, filename, line, func,
name, t, bt);
1252 res = pthread_rwlock_tryrdlock(&t->
lock);
1256 ast_reentrancy_lock(lt);
1264 ast_reentrancy_unlock(lt);
1265 ast_mark_lock_acquired(t);
1279 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1291 ast_reentrancy_lock(lt);
1296 ast_reentrancy_unlock(lt);
1298 ast_store_lock_info(
AST_WRLOCK, filename, line, func,
name, t, bt);
1302 res = pthread_rwlock_trywrlock(&t->
lock);
1306 ast_reentrancy_lock(lt);
1314 ast_reentrancy_unlock(lt);
1315 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().