diff options
author | mmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-05-23 22:35:50 +0000 |
---|---|---|
committer | mmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-05-23 22:35:50 +0000 |
commit | c0ca2a427bbbe205b9fd8d7a2c8b119cb56c6c80 (patch) | |
tree | c8d0825b33b156cc9ea02bc81363305f700e8393 | |
parent | 972905a6358c269996d5d7abaa89a4f2d5d350fa (diff) |
A new feature thanks to the fine folks at Switchvox!
If a deadlock is detected, then the typical lock information will be
printed along with a backtrace of the stack for the offending threads.
Use of this requires compiling with DETECT_DEADLOCKS and having glibc
installed.
Furthermore, issuing the "core show locks" CLI command will print the
normal lock information as well as a backtraces for each lock. This
requires that DEBUG_THREADS is enabled and that glibc is installed.
All the backtrace features may be disabled by running the configure
script with --without-execinfo as an argument
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@118173 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r-- | CHANGES | 6 | ||||
-rw-r--r-- | include/asterisk/lock.h | 532 | ||||
-rw-r--r-- | include/asterisk/logger.h | 44 | ||||
-rw-r--r-- | main/logger.c | 65 | ||||
-rw-r--r-- | main/utils.c | 50 | ||||
-rw-r--r-- | utils/ael_main.c | 14 | ||||
-rw-r--r-- | utils/check_expr.c | 24 | ||||
-rw-r--r-- | utils/conf2ael.c | 14 | ||||
-rw-r--r-- | utils/hashtest.c | 20 | ||||
-rw-r--r-- | utils/hashtest2.c | 17 | ||||
-rw-r--r-- | utils/refcounter.c | 19 |
11 files changed, 617 insertions, 188 deletions
@@ -744,3 +744,9 @@ Miscellaneous turned on, via the CHANNEL(trace) dialplan function. Could be useful for dialplan debugging. * iLBC source code no longer included (see UPGRADE.txt for details) + * If compiled with DETECT_DEADLOCKS enabled and if you have glibc, then if + deadlock is detected, a backtrace of the stack which led to the lock calls + will be output to the CLI. + * If compiled with DEBUG_THREADS enabled and if you have glibc, then issuing + the "core show locks" CLI command will give lock information output as well + as a backtrace of the stack which led to the lock calls. diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h index cbc2926b3..d78a83437 100644 --- a/include/asterisk/lock.h +++ b/include/asterisk/lock.h @@ -51,6 +51,8 @@ #include <pthread.h> #include <sys/param.h> +#include <execinfo.h> + #include "asterisk/logger.h" /* internal macro to profile mutexes. Only computes the delay on @@ -108,9 +110,15 @@ #include <errno.h> +#ifdef HAVE_BKTR +#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_MUTEX_INIT_VALUE } +#define AST_MUTEX_INIT_VALUE_NOTRACKING \ + { PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_MUTEX_INIT_VALUE } +#else #define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE } #define AST_MUTEX_INIT_VALUE_NOTRACKING \ { PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE } +#endif #define AST_MAX_REENTRANCY 10 @@ -125,6 +133,9 @@ struct ast_mutex_info { int reentrancy; const char *func[AST_MAX_REENTRANCY]; pthread_t thread[AST_MAX_REENTRANCY]; +#ifdef HAVE_BKTR + struct ast_bt backtrace[AST_MAX_REENTRANCY]; +#endif pthread_mutex_t reentr_mutex; }; @@ -149,12 +160,22 @@ enum ast_lock_type { * on the lock. ast_mark_lock_acquired() will mark it as held by this thread. */ #if !defined(LOW_MEMORY) +#ifdef HAVE_BKTR +void ast_store_lock_info(enum ast_lock_type type, const char *filename, + int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt); +#else void ast_store_lock_info(enum ast_lock_type type, const char *filename, int line_num, const char *func, const char *lock_name, void *lock_addr); +#endif /* HAVE_BKTR */ + #else -#define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS) -#endif +#ifdef HAVE_BKTR +#define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS,BUD) +#else +#define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS) +#endif /* HAVE_BKTR */ +#endif /* !defined(LOW_MEMORY) */ /*! * \brief Mark the last lock as acquired @@ -181,12 +202,34 @@ void ast_mark_lock_failed(void *lock_addr); * be removed from the current thread's lock info struct. */ #if !defined(LOW_MEMORY) +#ifdef HAVE_BKTR +void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt); +#else void ast_remove_lock_info(void *lock_addr); +#endif /* HAVE_BKTR */ +#else +#ifdef HAVE_BKTR +#define ast_remove_lock_info(ignore,me) #else #define ast_remove_lock_info(ignore) -#endif +#endif /* HAVE_BKTR */ +#endif /* !defined(LOW_MEMORY) */ + +#ifdef HAVE_BKTR +static inline void __dump_backtrace(struct ast_bt *bt, int canlog) +{ + char **strings; + + size_t i; + strings = backtrace_symbols(bt->addresses, bt->num_frames); + for (i = 0; i < bt->num_frames; i++) + __ast_mutex_logger("%s\n", strings[i]); + + free(strings); +} +#endif /*! * \brief log info for the current lock with ast_log(). @@ -223,6 +266,9 @@ static inline void ast_reentrancy_init(ast_mutex_t *p_ast_mutex) p_ast_mutex->lineno[i] = 0; p_ast_mutex->func[i] = NULL; p_ast_mutex->thread[i] = 0; +#ifdef HAVE_BKTR + memset(&p_ast_mutex->backtrace[i], 0, sizeof(p_ast_mutex->backtrace[i])); +#endif } p_ast_mutex->reentrancy = 0; @@ -308,6 +354,9 @@ static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, ast_reentrancy_lock(t); __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n", t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name); +#ifdef HAVE_BKTR + __dump_backtrace(&t->backtrace[t->reentrancy-1], canlog); +#endif ast_reentrancy_unlock(t); break; } @@ -325,6 +374,9 @@ static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno, t->func[0] = func; t->reentrancy = 0; t->thread[0] = 0; +#ifdef HAVE_BKTR + memset(&t->backtrace[0], 0, sizeof(t->backtrace[0])); +#endif ast_reentrancy_unlock(t); delete_reentrancy_cs(t); @@ -336,6 +388,9 @@ static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, con { int res; int canlog = strcmp(filename, "logger.c") & t->track; +#ifdef HAVE_BKTR + struct ast_bt *bt = NULL; +#endif #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { @@ -352,8 +407,17 @@ static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, con } #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ - if (t->track) + if (t->track) { +#ifdef HAVE_BKTR + ast_reentrancy_lock(t); + ast_bt_get_addresses(&t->backtrace[t->reentrancy]); + bt = &t->backtrace[t->reentrancy]; + ast_reentrancy_unlock(t); + ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex, bt); +#else ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex); +#endif + } #ifdef DETECT_DEADLOCKS { @@ -373,9 +437,15 @@ static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, con __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n", filename, lineno, func, (int) wait_time, mutex_name); ast_reentrancy_lock(t); +#ifdef HAVE_BKTR + __dump_backtrace(&t->backtrace[t->reentrancy], canlog); +#endif __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name); +#ifdef HAVE_BKTR + __dump_backtrace(&t->backtrace[t->reentrancy-1], canlog); +#endif ast_reentrancy_unlock(t); reported_wait = wait_time; } @@ -409,8 +479,20 @@ static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, con if (t->track) ast_mark_lock_acquired(&t->mutex); } else { +#ifdef HAVE_BKTR + if (t->reentrancy) { + ast_reentrancy_lock(t); + bt = &t->backtrace[t->reentrancy-1]; + ast_reentrancy_unlock(t); + } else { + bt = NULL; + } + if (t->track) + ast_remove_lock_info(&t->mutex, bt); +#else if (t->track) ast_remove_lock_info(&t->mutex); +#endif __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n", filename, lineno, func, strerror(res)); DO_THREAD_CRASH; @@ -424,6 +506,9 @@ static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, { int res; int canlog = strcmp(filename, "logger.c") & t->track; +#ifdef HAVE_BKTR + struct ast_bt *bt = NULL; +#endif #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { @@ -440,8 +525,17 @@ static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno, } #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ - if (t->track) + if (t->track) { +#ifdef HAVE_BKTR + ast_reentrancy_lock(t); + ast_bt_get_addresses(&t->backtrace[t->reentrancy]); + bt = &t->backtrace[t->reentrancy]; + ast_reentrancy_unlock(t); + ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex, bt); +#else ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex); +#endif + } if (!(res = pthread_mutex_trylock(&t->mutex))) { ast_reentrancy_lock(t); @@ -470,6 +564,9 @@ static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, c { int res; int canlog = strcmp(filename, "logger.c") & t->track; +#ifdef HAVE_BKTR + struct ast_bt *bt = NULL; +#endif #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { @@ -490,6 +587,9 @@ static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, c filename, lineno, func, mutex_name); __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name); +#ifdef HAVE_BKTR + __dump_backtrace(&t->backtrace[t->reentrancy-1], canlog); +#endif DO_THREAD_CRASH; } @@ -505,11 +605,21 @@ static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, c t->func[t->reentrancy] = NULL; t->thread[t->reentrancy] = 0; } + +#ifdef HAVE_BKTR + if (t->reentrancy) { + bt = &t->backtrace[t->reentrancy - 1]; + } +#endif ast_reentrancy_unlock(t); - if (t->track) + if (t->track) { +#ifdef HAVE_BKTR + ast_remove_lock_info(&t->mutex, bt); +#else ast_remove_lock_info(&t->mutex); - +#endif + } if ((res = pthread_mutex_unlock(&t->mutex))) { __ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n", filename, lineno, func, strerror(res)); @@ -549,6 +659,9 @@ static inline int __ast_cond_wait(const char *filename, int lineno, const char * { int res; int canlog = strcmp(filename, "logger.c") & t->track; +#ifdef HAVE_BKTR + struct ast_bt *bt = NULL; +#endif #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { @@ -569,6 +682,9 @@ static inline int __ast_cond_wait(const char *filename, int lineno, const char * filename, lineno, func, mutex_name); __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name); +#ifdef HAVE_BKTR + __dump_backtrace(&t->backtrace[t->reentrancy-1], canlog); +#endif DO_THREAD_CRASH; } @@ -584,10 +700,21 @@ static inline int __ast_cond_wait(const char *filename, int lineno, const char * t->func[t->reentrancy] = NULL; t->thread[t->reentrancy] = 0; } + +#ifdef HAVE_BKTR + if (t->reentrancy) { + bt = &t->backtrace[t->reentrancy - 1]; + } +#endif ast_reentrancy_unlock(t); - if (t->track) + if (t->track) { +#ifdef HAVE_BKTR + ast_remove_lock_info(&t->mutex, bt); +#else ast_remove_lock_info(&t->mutex); +#endif + } if ((res = pthread_cond_wait(cond, &t->mutex))) { __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", @@ -600,6 +727,10 @@ static inline int __ast_cond_wait(const char *filename, int lineno, const char * t->lineno[t->reentrancy] = lineno; t->func[t->reentrancy] = func; t->thread[t->reentrancy] = pthread_self(); +#ifdef HAVE_BKTR + ast_bt_get_addresses(&t->backtrace[t->reentrancy]); + bt = &t->backtrace[t->reentrancy]; +#endif t->reentrancy++; } else { __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n", @@ -607,8 +738,13 @@ static inline int __ast_cond_wait(const char *filename, int lineno, const char * } ast_reentrancy_unlock(t); - if (t->track) + if (t->track) { +#ifdef HAVE_BKTR + ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex, bt); +#else ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex); +#endif + } } return res; @@ -620,6 +756,9 @@ static inline int __ast_cond_timedwait(const char *filename, int lineno, const c { int res; int canlog = strcmp(filename, "logger.c") & t->track; +#ifdef HAVE_BKTR + struct ast_bt *bt = NULL; +#endif #ifdef AST_MUTEX_INIT_W_CONSTRUCTORS if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { @@ -640,6 +779,9 @@ static inline int __ast_cond_timedwait(const char *filename, int lineno, const c filename, lineno, func, mutex_name); __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n", t->file[t->reentrancy-1], t->lineno[t->reentrancy-1], t->func[t->reentrancy-1], mutex_name); +#ifdef HAVE_BKTR + __dump_backtrace(&t->backtrace[t->reentrancy-1], canlog); +#endif DO_THREAD_CRASH; } @@ -655,10 +797,19 @@ static inline int __ast_cond_timedwait(const char *filename, int lineno, const c t->func[t->reentrancy] = NULL; t->thread[t->reentrancy] = 0; } +#ifdef HAVE_BKTR + if (t->reentrancy) { + bt = &t->backtrace[t->reentrancy - 1]; + } +#endif ast_reentrancy_unlock(t); if (t->track) +#ifdef HAVE_BKTR + ast_remove_lock_info(&t->mutex, bt); +#else ast_remove_lock_info(&t->mutex); +#endif if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) { __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n", @@ -671,6 +822,10 @@ static inline int __ast_cond_timedwait(const char *filename, int lineno, const c t->lineno[t->reentrancy] = lineno; t->func[t->reentrancy] = func; t->thread[t->reentrancy] = pthread_self(); +#ifdef HAVE_BKTR + ast_bt_get_addresses(&t->backtrace[t->reentrancy]); + bt = &t->backtrace[t->reentrancy]; +#endif t->reentrancy++; } else { __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n", @@ -678,8 +833,13 @@ static inline int __ast_cond_timedwait(const char *filename, int lineno, const c } ast_reentrancy_unlock(t); - if (t->track) + if (t->track) { +#ifdef HAVE_BKTR + ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex, bt); +#else ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex); +#endif + } } return res; @@ -696,151 +856,14 @@ static inline int __ast_cond_timedwait(const char *filename, int lineno, const c #define ast_cond_wait(cond, mutex) __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex) #define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time) -#else /* !DEBUG_THREADS */ - - -typedef pthread_mutex_t ast_mutex_t; - -#define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE) -#define AST_MUTEX_INIT_VALUE_NOTRACKING ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE) - -#define ast_mutex_init_notracking(m) ast_mutex_init(m) - -static inline int ast_mutex_init(ast_mutex_t *pmutex) -{ - int res; - pthread_mutexattr_t attr; - - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, AST_MUTEX_KIND); - - res = pthread_mutex_init(pmutex, &attr); - pthread_mutexattr_destroy(&attr); - return res; -} - -#define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a) - -static inline int ast_mutex_unlock(ast_mutex_t *pmutex) -{ - return pthread_mutex_unlock(pmutex); -} - -static inline int ast_mutex_destroy(ast_mutex_t *pmutex) -{ - return pthread_mutex_destroy(pmutex); -} - -static inline int ast_mutex_lock(ast_mutex_t *pmutex) -{ - __MTX_PROF(pmutex); -} - -static inline int ast_mutex_trylock(ast_mutex_t *pmutex) -{ - return pthread_mutex_trylock(pmutex); -} - -typedef pthread_cond_t ast_cond_t; - -static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr) -{ - return pthread_cond_init(cond, cond_attr); -} - -static inline int ast_cond_signal(ast_cond_t *cond) -{ - return pthread_cond_signal(cond); -} - -static inline int ast_cond_broadcast(ast_cond_t *cond) -{ - return pthread_cond_broadcast(cond); -} - -static inline int ast_cond_destroy(ast_cond_t *cond) -{ - return pthread_cond_destroy(cond); -} - -static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t) -{ - return pthread_cond_wait(cond, t); -} - -static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime) -{ - return pthread_cond_timedwait(cond, t, abstime); -} - -#endif /* !DEBUG_THREADS */ - -#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) -/* - * If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope constructors - * and destructors to create/destroy global mutexes. - */ -#define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \ - scope ast_mutex_t mutex = init_val; \ -static void __attribute__ ((constructor)) init_##mutex(void) \ -{ \ - if (track) \ - ast_mutex_init(&mutex); \ - else \ - ast_mutex_init_notracking(&mutex); \ -} \ - \ -static void __attribute__ ((destructor)) fini_##mutex(void) \ -{ \ - ast_mutex_destroy(&mutex); \ -} -#else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */ -/* By default, use static initialization of mutexes. */ -#define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) scope ast_mutex_t mutex = init_val -#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ - -#ifndef __CYGWIN__ /* temporary disabled for cygwin */ -#define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t -#define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t -#endif -#define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock -#define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock -#define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock -#define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init -#define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy -#define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init -#define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy -#define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal -#define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast -#define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait -#define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait - -#define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1) -#define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0) - -#define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__ - -#define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__ - -#ifndef __linux__ -#define pthread_create __use_ast_pthread_create_instead__ -#endif - -/* - * Same as above, definitions of ast_rwlock_t for the various cases: - * simple wrappers for the pthread equivalent in the non-debug case, - * more sophisticated tracking in the debug case. - */ - -typedef pthread_rwlock_t ast_rwlock_t; - -#ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER -#define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER -#else -#define AST_RWLOCK_INIT_VALUE { 0 } +struct ast_rwlock_info { + pthread_rwlock_t lock; +#ifdef HAVE_BKTR + struct ast_bt backtrace; #endif +}; -#ifdef DEBUG_THREADS +typedef struct ast_rwlock_info ast_rwlock_t; #define ast_rwlock_init(rwlock) __ast_rwlock_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock) #define ast_rwlock_destroy(rwlock) __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock) @@ -850,6 +873,19 @@ typedef pthread_rwlock_t ast_rwlock_t; #define ast_rwlock_tryrdlock(a) _ast_rwlock_tryrdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__) #define ast_rwlock_trywrlock(a) _ast_rwlock_trywrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__) +#ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER +#ifdef HAVE_BKTR +#define AST_RWLOCK_INIT_VALUE { PTHREAD_RWLOCK_INITIALIZER, {{0,},} } +#else +#define AST_RWLOCK_INIT_VALUE { PTHREAD_RWLOCK_INITIALIZER } +#endif /* HAVE_BKTR */ +#else /* HAVE_PTHREAD_RWLOCK_INITIALIZER */ +#ifdef HAVE_BKTR +#define AST_RWLOCK_INIT_VALUE { 0 , {0,},}} +#else +#define AST_RWLOCK_INIT_VALUE { 0 } +#endif /* HAVE_BKTR */ +#endif /* HAVE_PTHREAD_RWLOCK_INITIALIZER */ static inline int __ast_rwlock_init(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock) { @@ -870,7 +906,7 @@ static inline int __ast_rwlock_init(const char *filename, int lineno, const char pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP); #endif - res = pthread_rwlock_init(prwlock, &attr); + res = pthread_rwlock_init(&prwlock->lock, &attr); pthread_rwlockattr_destroy(&attr); return res; } @@ -889,7 +925,7 @@ static inline int __ast_rwlock_destroy(const char *filename, int lineno, const c } #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ - if ((res = pthread_rwlock_destroy(prwlock))) + if ((res = pthread_rwlock_destroy(&prwlock->lock))) __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n", filename, lineno, func, rwlock_name, strerror(res)); @@ -916,8 +952,13 @@ static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name, } #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ - res = pthread_rwlock_unlock(lock); + res = pthread_rwlock_unlock(&lock->lock); +#ifdef HAVE_BKTR + memset(&lock->backtrace, 0, sizeof(lock->backtrace)); + ast_remove_lock_info(lock, NULL); +#else ast_remove_lock_info(lock); +#endif return res; } @@ -942,13 +983,20 @@ static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name, } } #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ - +#ifdef HAVE_BKTR + ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock, &lock->backtrace); +#else ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock); - res = pthread_rwlock_rdlock(lock); +#endif + res = pthread_rwlock_rdlock(&lock->lock); if (!res) ast_mark_lock_acquired(lock); else +#ifdef HAVE_BKTR + ast_remove_lock_info(lock, NULL); +#else ast_remove_lock_info(lock); +#endif return res; } @@ -973,13 +1021,20 @@ static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name, } } #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ - +#ifdef HAVE_BKTR + ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock, &lock->backtrace); +#else ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock); - res = pthread_rwlock_wrlock(lock); +#endif + res = pthread_rwlock_wrlock(&lock->lock); if (!res) ast_mark_lock_acquired(lock); else +#ifdef HAVE_BKTR + ast_remove_lock_info(lock, NULL); +#else ast_remove_lock_info(lock); +#endif return res; } @@ -1004,13 +1059,20 @@ static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name, } } #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ - +#ifdef HAVE_BKTR + ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock, &lock->backtrace); +#else ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock); - res = pthread_rwlock_tryrdlock(lock); +#endif + res = pthread_rwlock_tryrdlock(&lock->lock); if (!res) ast_mark_lock_acquired(lock); else +#ifdef HAVE_BKTR + ast_remove_lock_info(lock, NULL); +#else ast_remove_lock_info(lock); +#endif return res; } @@ -1035,18 +1097,108 @@ static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name, } } #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ - +#ifdef HAVE_BKTR + ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock, &lock->backtrace); +#else ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock); - res = pthread_rwlock_trywrlock(lock); +#endif + res = pthread_rwlock_trywrlock(&lock->lock); if (!res) ast_mark_lock_acquired(lock); else +#ifdef HAVE_BKTR + ast_remove_lock_info(lock, NULL); +#else ast_remove_lock_info(lock); +#endif return res; } #else /* !DEBUG_THREADS */ +typedef pthread_mutex_t ast_mutex_t; + +#define AST_MUTEX_INIT_VALUE ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE) +#define AST_MUTEX_INIT_VALUE_NOTRACKING ((ast_mutex_t) PTHREAD_MUTEX_INIT_VALUE) + +#define ast_mutex_init_notracking(m) ast_mutex_init(m) + +static inline int ast_mutex_init(ast_mutex_t *pmutex) +{ + int res; + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, AST_MUTEX_KIND); + + res = pthread_mutex_init(pmutex, &attr); + pthread_mutexattr_destroy(&attr); + return res; +} + +#define ast_pthread_mutex_init(pmutex,a) pthread_mutex_init(pmutex,a) + +static inline int ast_mutex_unlock(ast_mutex_t *pmutex) +{ + return pthread_mutex_unlock(pmutex); +} + +static inline int ast_mutex_destroy(ast_mutex_t *pmutex) +{ + return pthread_mutex_destroy(pmutex); +} + +static inline int ast_mutex_lock(ast_mutex_t *pmutex) +{ + __MTX_PROF(pmutex); +} + +static inline int ast_mutex_trylock(ast_mutex_t *pmutex) +{ + return pthread_mutex_trylock(pmutex); +} + +typedef pthread_cond_t ast_cond_t; + +static inline int ast_cond_init(ast_cond_t *cond, pthread_condattr_t *cond_attr) +{ + return pthread_cond_init(cond, cond_attr); +} + +static inline int ast_cond_signal(ast_cond_t *cond) +{ + return pthread_cond_signal(cond); +} + +static inline int ast_cond_broadcast(ast_cond_t *cond) +{ + return pthread_cond_broadcast(cond); +} + +static inline int ast_cond_destroy(ast_cond_t *cond) +{ + return pthread_cond_destroy(cond); +} + +static inline int ast_cond_wait(ast_cond_t *cond, ast_mutex_t *t) +{ + return pthread_cond_wait(cond, t); +} + +static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime) +{ + return pthread_cond_timedwait(cond, t, abstime); +} + + +typedef pthread_rwlock_t ast_rwlock_t; + +#ifdef HAVE_PTHREAD_RWLOCK_INITIALIZER +#define AST_RWLOCK_INIT_VALUE PTHREAD_RWLOCK_INITIALIZER +#else +#define AST_RWLOCK_INIT_VALUE { 0 } +#endif + static inline int ast_rwlock_init(ast_rwlock_t *prwlock) { int res; @@ -1092,8 +1244,60 @@ static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock) { return pthread_rwlock_trywrlock(prwlock); } + #endif /* !DEBUG_THREADS */ +#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) +/* + * If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope constructors + * and destructors to create/destroy global mutexes. + */ +#define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \ + scope ast_mutex_t mutex = init_val; \ +static void __attribute__ ((constructor)) init_##mutex(void) \ +{ \ + if (track) \ + ast_mutex_init(&mutex); \ + else \ + ast_mutex_init_notracking(&mutex); \ +} \ + \ +static void __attribute__ ((destructor)) fini_##mutex(void) \ +{ \ + ast_mutex_destroy(&mutex); \ +} +#else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */ +/* By default, use static initialization of mutexes. */ +#define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) scope ast_mutex_t mutex = init_val +#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ + +#ifndef __CYGWIN__ /* temporary disabled for cygwin */ +#define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t +#define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t +#endif +#define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock +#define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock +#define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock +#define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init +#define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy +#define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init +#define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy +#define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal +#define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast +#define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait +#define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait + +#define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1) +#define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0) + +#define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__ + +#define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__ + +#ifndef __linux__ +#define pthread_create __use_ast_pthread_create_instead__ +#endif + /* Statically declared read/write locks */ #ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER diff --git a/include/asterisk/logger.h b/include/asterisk/logger.h index 4995c54c2..2695efb99 100644 --- a/include/asterisk/logger.h +++ b/include/asterisk/logger.h @@ -219,6 +219,50 @@ unsigned int ast_verbose_get_by_file(const char *file); } \ } while (0) +#ifndef _LOGGER_BACKTRACE_H +#define _LOGGER_BACKTRACE_H +#ifdef HAVE_BKTR +#define AST_MAX_BT_FRAMES 32 +/* \brief + * + * A structure to hold backtrace information. This structure provides an easy means to + * store backtrace information or pass backtraces to other functions. + */ +struct ast_bt { + /*! The addresses of the stack frames. This is filled in by calling the glibc backtrace() function */ + void *addresses[AST_MAX_BT_FRAMES]; + /*! The number of stack frames in the backtrace */ + int num_frames; + /*! Tells if the ast_bt structure was dynamically allocated */ + unsigned int alloced:1; +}; + +/* \brief + * Allocates memory for an ast_bt and stores addresses and symbols. + * + * \return Returns NULL on failure, or the allocated ast_bt on success + */ +struct ast_bt *ast_bt_create(void); + +/* \brief + * Fill an allocated ast_bt with addresses + * + * \retval 0 Success + * \retval -1 Failure + */ +int ast_bt_get_addresses(struct ast_bt *bt); + +/* \brief + * + * Free dynamically allocated portions of an ast_bt + * + * \retval NULL. + */ +void *ast_bt_destroy(struct ast_bt *bt); + +#endif /* HAVE_BKTR */ +#endif /* _LOGGER_BACKTRACE_H */ + #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/main/logger.c b/main/logger.c index a4936badd..d20ac8bc5 100644 --- a/main/logger.c +++ b/main/logger.c @@ -1127,30 +1127,67 @@ void ast_log(int level, const char *file, int line, const char *function, const return; } +#ifdef HAVE_BKTR + +struct ast_bt *ast_bt_create(void) +{ + struct ast_bt *bt = ast_calloc(1, sizeof(*bt)); + if (!bt) { + ast_log(LOG_ERROR, "Unable to allocate memory for backtrace structure!\n"); + return NULL; + } + + bt->alloced = 1; + + ast_bt_get_addresses(bt); + + return bt; +} + +int ast_bt_get_addresses(struct ast_bt *bt) +{ + bt->num_frames = backtrace(bt->addresses, AST_MAX_BT_FRAMES); + + return 0; +} + +void *ast_bt_destroy(struct ast_bt *bt) +{ + if (bt->alloced) { + ast_free(bt); + } + + return NULL; +} + +#endif /* HAVE_BKTR */ + void ast_backtrace(void) { #ifdef HAVE_BKTR - int count = 0, i = 0; - void **addresses; + struct ast_bt *backtrace; + int i = 0; char **strings; - if ((addresses = ast_calloc(MAX_BACKTRACE_FRAMES, sizeof(*addresses)))) { - count = backtrace(addresses, MAX_BACKTRACE_FRAMES); - if ((strings = backtrace_symbols(addresses, count))) { - ast_debug(1, "Got %d backtrace record%c\n", count, count != 1 ? 's' : ' '); - for (i = 0; i < count; i++) { + if (!(backtrace = ast_bt_create())) { + ast_log(LOG_WARNING, "Unable to allocate space for backtrace structure\n"); + return; + } + + if ((strings = backtrace_symbols(backtrace->addresses, backtrace->num_frames))) { + ast_debug(1, "Got %d backtrace record%c\n", backtrace->num_frames, backtrace->num_frames != 1 ? 's' : ' '); + for (i = 0; i < backtrace->num_frames; i++) { #if __WORDSIZE == 32 - ast_log(LOG_DEBUG, "#%d: [%08X] %s\n", i, (unsigned int)addresses[i], strings[i]); + ast_log(LOG_DEBUG, "#%d: [%08X] %s\n", i, (unsigned int)backtrace->addresses[i], strings[i]); #elif __WORDSIZE == 64 - ast_log(LOG_DEBUG, "#%d: [%016lX] %s\n", i, (unsigned long)addresses[i], strings[i]); + ast_log(LOG_DEBUG, "#%d: [%016lX] %s\n", i, (unsigned long)backtrace->addresses[i], strings[i]); #endif - } - free(strings); - } else { - ast_debug(1, "Could not allocate memory for backtrace\n"); } - ast_free(addresses); + free(strings); + } else { + ast_debug(1, "Could not allocate memory for backtrace\n"); } + ast_bt_destroy(backtrace); #else ast_log(LOG_WARNING, "Must run configure with '--with-execinfo' for stack backtraces.\n"); #endif diff --git a/main/utils.c b/main/utils.c index 3946df9a9..dfa32eb58 100644 --- a/main/utils.c +++ b/main/utils.c @@ -540,6 +540,9 @@ struct thr_lock_info { enum ast_lock_type type; /*! This thread is waiting on this lock */ int pending:2; +#ifdef HAVE_BKTR + struct ast_bt *backtrace; +#endif } locks[AST_MAX_LOCKS]; /*! This is the number of locks currently held by this thread. * The index (num_locks - 1) has the info on the last one in the @@ -583,9 +586,13 @@ static void lock_info_destroy(void *data) * \brief The thread storage key for per-thread lock info */ AST_THREADSTORAGE_CUSTOM(thread_lock_info, NULL, lock_info_destroy); - +#ifdef HAVE_BKTR +void ast_store_lock_info(enum ast_lock_type type, const char *filename, + int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt) +#else void ast_store_lock_info(enum ast_lock_type type, const char *filename, int line_num, const char *func, const char *lock_name, void *lock_addr) +#endif { struct thr_lock_info *lock_info; int i; @@ -598,6 +605,9 @@ void ast_store_lock_info(enum ast_lock_type type, const char *filename, for (i = 0; i < lock_info->num_locks; i++) { if (lock_info->locks[i].lock_addr == lock_addr) { lock_info->locks[i].times_locked++; +#ifdef HAVE_BKTR + lock_info->locks[i].backtrace = bt; +#endif pthread_mutex_unlock(&lock_info->lock); return; } @@ -628,6 +638,9 @@ void ast_store_lock_info(enum ast_lock_type type, const char *filename, lock_info->locks[i].times_locked = 1; lock_info->locks[i].type = type; lock_info->locks[i].pending = 1; +#ifdef HAVE_BKTR + lock_info->locks[i].backtrace = bt; +#endif lock_info->num_locks++; pthread_mutex_unlock(&lock_info->lock); @@ -661,8 +674,11 @@ void ast_mark_lock_failed(void *lock_addr) } pthread_mutex_unlock(&lock_info->lock); } - +#ifdef HAVE_BKTR +void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt) +#else void ast_remove_lock_info(void *lock_addr) +#endif { struct thr_lock_info *lock_info; int i = 0; @@ -685,6 +701,9 @@ void ast_remove_lock_info(void *lock_addr) if (lock_info->locks[i].times_locked > 1) { lock_info->locks[i].times_locked--; +#ifdef HAVE_BKTR + lock_info->locks[i].backtrace = bt; +#endif pthread_mutex_unlock(&lock_info->lock); return; } @@ -714,6 +733,30 @@ static const char *locktype2str(enum ast_lock_type type) return "UNKNOWN"; } +#ifdef HAVE_BKTR +static void append_backtrace_information(struct ast_str **str, struct ast_bt *bt) +{ + char **symbols; + + if (!bt) { + ast_str_append(str, 0, "\tNo backtrace to print\n"); + return; + } + + if ((symbols = backtrace_symbols(bt->addresses, bt->num_frames))) { + int frame_iterator; + + for (frame_iterator = 0; frame_iterator < bt->num_frames; ++frame_iterator) { + ast_str_append(str, 0, "\t%s\n", symbols[frame_iterator]); + } + + free(symbols); + } else { + ast_str_append(str, 0, "\tCouldn't retrieve backtrace symbols\n"); + } +} +#endif + static void append_lock_information(struct ast_str **str, struct thr_lock_info *lock_info, int i) { int j; @@ -728,6 +771,9 @@ static void append_lock_information(struct ast_str **str, struct thr_lock_info * lock_info->locks[i].func, lock_info->locks[i].lock_name, lock_info->locks[i].lock_addr, lock_info->locks[i].times_locked); +#ifdef HAVE_BKTR + append_backtrace_information(str, lock_info->locks[i].backtrace); +#endif if (!lock_info->locks[i].pending || lock_info->locks[i].pending == -1) return; diff --git a/utils/ael_main.c b/utils/ael_main.c index f8477edd1..166fefb65 100644 --- a/utils/ael_main.c +++ b/utils/ael_main.c @@ -578,7 +578,16 @@ unsigned int ast_hashtab_hash_contexts(const void *obj) void ast_mark_lock_acquired(void *lock_addr) { } +#ifdef HAVE_BKTR +void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt) +{ +} +void ast_store_lock_info(enum ast_lock_type type, const char *filename, + int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt) +{ +} +#else void ast_remove_lock_info(void *lock_addr) { } @@ -587,5 +596,6 @@ void ast_store_lock_info(enum ast_lock_type type, const char *filename, int line_num, const char *func, const char *lock_name, void *lock_addr) { } -#endif -#endif +#endif /* HAVE_BKTR */ +#endif /* !defined(LOW_MEMORY) */ +#endif /* DEBUG_THREADS */ diff --git a/utils/check_expr.c b/utils/check_expr.c index 7b013f163..5293acc26 100644 --- a/utils/check_expr.c +++ b/utils/check_expr.c @@ -86,16 +86,25 @@ enum ast_lock_type { }; #endif #if !defined(LOW_MEMORY) +#ifdef HAVE_BKTR void ast_store_lock_info(enum ast_lock_type type, const char *filename, - int line_num, const char *func, const char *lock_name, void *lock_addr); + int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt); void ast_store_lock_info(enum ast_lock_type type, const char *filename, - int line_num, const char *func, const char *lock_name, void *lock_addr) + int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt) { /* not a lot to do in a standalone w/o threading! */ } -void ast_mark_lock_acquired(void *); -void ast_mark_lock_acquired(void *foo) +void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt); +void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt) +{ + /* not a lot to do in a standalone w/o threading! */ +} +#else +void ast_store_lock_info(enum ast_lock_type type, const char *filename, + int line_num, const char *func, const char *lock_name, void *lock_addr); +void ast_store_lock_info(enum ast_lock_type type, const char *filename, + int line_num, const char *func, const char *lock_name, void *lock_addr) { /* not a lot to do in a standalone w/o threading! */ } @@ -105,6 +114,13 @@ void ast_remove_lock_info(void *lock_addr) { /* not a lot to do in a standalone w/o threading! */ } +#endif /* HAVE_BKTR */ + +void ast_mark_lock_acquired(void *); +void ast_mark_lock_acquired(void *foo) +{ + /* not a lot to do in a standalone w/o threading! */ +} #endif static int global_lineno = 1; diff --git a/utils/conf2ael.c b/utils/conf2ael.c index 4572cbd5d..a55a79512 100644 --- a/utils/conf2ael.c +++ b/utils/conf2ael.c @@ -705,7 +705,16 @@ unsigned int ast_hashtab_hash_contexts(const void *obj) void ast_mark_lock_acquired(void *lock_addr) { } +#ifdef HAVE_BKTR +void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt) +{ +} +void ast_store_lock_info(enum ast_lock_type type, const char *filename, + int line_num, const char *func, const char *lock_name, void *lock_addr, struct ast_bt *bt) +{ +} +#else void ast_remove_lock_info(void *lock_addr) { } @@ -714,5 +723,6 @@ void ast_store_lock_info(enum ast_lock_type type, const char *filename, int line_num, const char *func, const char *lock_name, void *lock_addr) { } -#endif -#endif +#endif /* HAVE_BKTR */ +#endif /* !defined(LOW_MEMORY) */ +#endif /* DEBUG_THREADS */ diff --git a/utils/hashtest.c b/utils/hashtest.c index 95f463da7..7ff7a55b2 100644 --- a/utils/hashtest.c +++ b/utils/hashtest.c @@ -366,3 +366,23 @@ void ast_register_thread(char *name) void ast_unregister_thread(void *id) { } + +#ifdef HAVE_BKTR +struct ast_bt *ast_bt_create(void); +struct ast_bt *ast_bt_create(void) +{ + return NULL; +} + +int ast_bt_get_addresses(struct ast_bt *bt); +int ast_bt_get_addresses(struct ast_bt *bt) +{ + return 0; +} + +void *ast_bt_destroy(struct ast_bt *bt); +void *ast_bt_destroy(struct ast_bt *bt) +{ + return NULL; +} +#endif diff --git a/utils/hashtest2.c b/utils/hashtest2.c index 2865822ab..27ed30722 100644 --- a/utils/hashtest2.c +++ b/utils/hashtest2.c @@ -378,3 +378,20 @@ void ast_register_thread(char *name) void ast_unregister_thread(void *id) { } + +#ifdef HAVE_BKTR +struct ast_bt* ast_bt_create(void) +{ + return NULL; +} + +int ast_bt_get_addresses(struct ast_bt *bt) +{ + return -1; +} + +void *ast_bt_destroy(struct ast_bt *bt) +{ + return NULL; +} +#endif diff --git a/utils/refcounter.c b/utils/refcounter.c index 5e750619e..4712c26b6 100644 --- a/utils/refcounter.c +++ b/utils/refcounter.c @@ -269,3 +269,22 @@ void ast_register_thread(char *name) void ast_unregister_thread(void *id) { } +#ifdef HAVE_BKTR +struct ast_bt *ast_bt_create(void); +struct ast_bt *ast_bt_create(void) +{ + return NULL; +} + +int ast_bt_get_addresses(struct ast_bt *bt); +int ast_bt_get_addresses(struct ast_bt *bt) +{ + return 0; +} + +void *ast_bt_destroy(struct ast_bt *bt); +void *ast_bt_destroy(struct ast_bt *bt) +{ + return NULL; +} +#endif |