mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-15 17:27:02 +00:00
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: https://origsvn.digium.com/svn/asterisk/trunk@118173 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
6
CHANGES
6
CHANGES
@@ -744,3 +744,9 @@ Miscellaneous
|
|||||||
turned on, via the CHANNEL(trace) dialplan function. Could be useful for
|
turned on, via the CHANNEL(trace) dialplan function. Could be useful for
|
||||||
dialplan debugging.
|
dialplan debugging.
|
||||||
* iLBC source code no longer included (see UPGRADE.txt for details)
|
* 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.
|
||||||
|
@@ -51,6 +51,8 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#include <execinfo.h>
|
||||||
|
|
||||||
#include "asterisk/logger.h"
|
#include "asterisk/logger.h"
|
||||||
|
|
||||||
/* internal macro to profile mutexes. Only computes the delay on
|
/* internal macro to profile mutexes. Only computes the delay on
|
||||||
@@ -108,9 +110,15 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#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 { PTHREAD_MUTEX_INIT_VALUE, 1, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
|
||||||
#define AST_MUTEX_INIT_VALUE_NOTRACKING \
|
#define AST_MUTEX_INIT_VALUE_NOTRACKING \
|
||||||
{ PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
|
{ PTHREAD_MUTEX_INIT_VALUE, 0, { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE }
|
||||||
|
#endif
|
||||||
|
|
||||||
#define AST_MAX_REENTRANCY 10
|
#define AST_MAX_REENTRANCY 10
|
||||||
|
|
||||||
@@ -125,6 +133,9 @@ struct ast_mutex_info {
|
|||||||
int reentrancy;
|
int reentrancy;
|
||||||
const char *func[AST_MAX_REENTRANCY];
|
const char *func[AST_MAX_REENTRANCY];
|
||||||
pthread_t thread[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;
|
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.
|
* on the lock. ast_mark_lock_acquired() will mark it as held by this thread.
|
||||||
*/
|
*/
|
||||||
#if !defined(LOW_MEMORY)
|
#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,
|
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);
|
||||||
|
#endif /* HAVE_BKTR */
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
#define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS,BUD)
|
||||||
#else
|
#else
|
||||||
#define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS)
|
#define ast_store_lock_info(I,DONT,CARE,ABOUT,THE,PARAMETERS)
|
||||||
#endif
|
#endif /* HAVE_BKTR */
|
||||||
|
#endif /* !defined(LOW_MEMORY) */
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Mark the last lock as acquired
|
* \brief Mark the last lock as acquired
|
||||||
@@ -181,13 +202,35 @@ void ast_mark_lock_failed(void *lock_addr);
|
|||||||
* be removed from the current thread's lock info struct.
|
* be removed from the current thread's lock info struct.
|
||||||
*/
|
*/
|
||||||
#if !defined(LOW_MEMORY)
|
#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);
|
void ast_remove_lock_info(void *lock_addr);
|
||||||
|
#endif /* HAVE_BKTR */
|
||||||
|
#else
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
#define ast_remove_lock_info(ignore,me)
|
||||||
#else
|
#else
|
||||||
#define ast_remove_lock_info(ignore)
|
#define ast_remove_lock_info(ignore)
|
||||||
|
#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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief log info for the current lock with ast_log().
|
* \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->lineno[i] = 0;
|
||||||
p_ast_mutex->func[i] = NULL;
|
p_ast_mutex->func[i] = NULL;
|
||||||
p_ast_mutex->thread[i] = 0;
|
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;
|
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_reentrancy_lock(t);
|
||||||
__ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
|
__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);
|
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);
|
ast_reentrancy_unlock(t);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -325,6 +374,9 @@ static inline int __ast_pthread_mutex_destroy(const char *filename, int lineno,
|
|||||||
t->func[0] = func;
|
t->func[0] = func;
|
||||||
t->reentrancy = 0;
|
t->reentrancy = 0;
|
||||||
t->thread[0] = 0;
|
t->thread[0] = 0;
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
memset(&t->backtrace[0], 0, sizeof(t->backtrace[0]));
|
||||||
|
#endif
|
||||||
ast_reentrancy_unlock(t);
|
ast_reentrancy_unlock(t);
|
||||||
delete_reentrancy_cs(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 res;
|
||||||
int canlog = strcmp(filename, "logger.c") & t->track;
|
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 defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
|
||||||
if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
|
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 */
|
#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);
|
ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DETECT_DEADLOCKS
|
#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",
|
__ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
|
||||||
filename, lineno, func, (int) wait_time, mutex_name);
|
filename, lineno, func, (int) wait_time, mutex_name);
|
||||||
ast_reentrancy_lock(t);
|
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",
|
__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
|
||||||
t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
|
t->file[t->reentrancy-1], t->lineno[t->reentrancy-1],
|
||||||
t->func[t->reentrancy-1], mutex_name);
|
t->func[t->reentrancy-1], mutex_name);
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
__dump_backtrace(&t->backtrace[t->reentrancy-1], canlog);
|
||||||
|
#endif
|
||||||
ast_reentrancy_unlock(t);
|
ast_reentrancy_unlock(t);
|
||||||
reported_wait = wait_time;
|
reported_wait = wait_time;
|
||||||
}
|
}
|
||||||
@@ -409,8 +479,20 @@ static inline int __ast_pthread_mutex_lock(const char *filename, int lineno, con
|
|||||||
if (t->track)
|
if (t->track)
|
||||||
ast_mark_lock_acquired(&t->mutex);
|
ast_mark_lock_acquired(&t->mutex);
|
||||||
} else {
|
} 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)
|
if (t->track)
|
||||||
ast_remove_lock_info(&t->mutex);
|
ast_remove_lock_info(&t->mutex);
|
||||||
|
#endif
|
||||||
__ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
|
__ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
|
||||||
filename, lineno, func, strerror(res));
|
filename, lineno, func, strerror(res));
|
||||||
DO_THREAD_CRASH;
|
DO_THREAD_CRASH;
|
||||||
@@ -424,6 +506,9 @@ static inline int __ast_pthread_mutex_trylock(const char *filename, int lineno,
|
|||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
int canlog = strcmp(filename, "logger.c") & t->track;
|
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 defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
|
||||||
if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
|
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 */
|
#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);
|
ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (!(res = pthread_mutex_trylock(&t->mutex))) {
|
if (!(res = pthread_mutex_trylock(&t->mutex))) {
|
||||||
ast_reentrancy_lock(t);
|
ast_reentrancy_lock(t);
|
||||||
@@ -470,6 +564,9 @@ static inline int __ast_pthread_mutex_unlock(const char *filename, int lineno, c
|
|||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
int canlog = strcmp(filename, "logger.c") & t->track;
|
int canlog = strcmp(filename, "logger.c") & t->track;
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
struct ast_bt *bt = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
||||||
if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
|
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);
|
filename, lineno, func, mutex_name);
|
||||||
__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
|
__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);
|
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;
|
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->func[t->reentrancy] = NULL;
|
||||||
t->thread[t->reentrancy] = 0;
|
t->thread[t->reentrancy] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
if (t->reentrancy) {
|
||||||
|
bt = &t->backtrace[t->reentrancy - 1];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
ast_reentrancy_unlock(t);
|
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);
|
ast_remove_lock_info(&t->mutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
if ((res = pthread_mutex_unlock(&t->mutex))) {
|
if ((res = pthread_mutex_unlock(&t->mutex))) {
|
||||||
__ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
|
__ast_mutex_logger("%s line %d (%s): Error releasing mutex: %s\n",
|
||||||
filename, lineno, func, strerror(res));
|
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 res;
|
||||||
int canlog = strcmp(filename, "logger.c") & t->track;
|
int canlog = strcmp(filename, "logger.c") & t->track;
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
struct ast_bt *bt = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
||||||
if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
|
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);
|
filename, lineno, func, mutex_name);
|
||||||
__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
|
__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);
|
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;
|
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->func[t->reentrancy] = NULL;
|
||||||
t->thread[t->reentrancy] = 0;
|
t->thread[t->reentrancy] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
if (t->reentrancy) {
|
||||||
|
bt = &t->backtrace[t->reentrancy - 1];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
ast_reentrancy_unlock(t);
|
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);
|
ast_remove_lock_info(&t->mutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if ((res = pthread_cond_wait(cond, &t->mutex))) {
|
if ((res = pthread_cond_wait(cond, &t->mutex))) {
|
||||||
__ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
|
__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->lineno[t->reentrancy] = lineno;
|
||||||
t->func[t->reentrancy] = func;
|
t->func[t->reentrancy] = func;
|
||||||
t->thread[t->reentrancy] = pthread_self();
|
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++;
|
t->reentrancy++;
|
||||||
} else {
|
} else {
|
||||||
__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
|
__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);
|
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);
|
ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -620,6 +756,9 @@ static inline int __ast_cond_timedwait(const char *filename, int lineno, const c
|
|||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
int canlog = strcmp(filename, "logger.c") & t->track;
|
int canlog = strcmp(filename, "logger.c") & t->track;
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
struct ast_bt *bt = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
||||||
if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
|
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);
|
filename, lineno, func, mutex_name);
|
||||||
__ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
|
__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);
|
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;
|
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->func[t->reentrancy] = NULL;
|
||||||
t->thread[t->reentrancy] = 0;
|
t->thread[t->reentrancy] = 0;
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
if (t->reentrancy) {
|
||||||
|
bt = &t->backtrace[t->reentrancy - 1];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
ast_reentrancy_unlock(t);
|
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);
|
ast_remove_lock_info(&t->mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((res = pthread_cond_timedwait(cond, &t->mutex, abstime)) && (res != ETIMEDOUT)) {
|
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",
|
__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->lineno[t->reentrancy] = lineno;
|
||||||
t->func[t->reentrancy] = func;
|
t->func[t->reentrancy] = func;
|
||||||
t->thread[t->reentrancy] = pthread_self();
|
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++;
|
t->reentrancy++;
|
||||||
} else {
|
} else {
|
||||||
__ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
|
__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);
|
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);
|
ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, &t->mutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -696,8 +856,265 @@ 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_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)
|
#define ast_cond_timedwait(cond, mutex, time) __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
|
||||||
|
|
||||||
#else /* !DEBUG_THREADS */
|
struct ast_rwlock_info {
|
||||||
|
pthread_rwlock_t lock;
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
struct ast_bt backtrace;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
#define ast_rwlock_unlock(a) _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||||
|
#define ast_rwlock_rdlock(a) _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||||
|
#define ast_rwlock_wrlock(a) _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
pthread_rwlockattr_t attr;
|
||||||
|
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
||||||
|
int canlog = strcmp(filename, "logger.c");
|
||||||
|
|
||||||
|
if (*prwlock != ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
||||||
|
__ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
|
||||||
|
filename, lineno, func, rwlock_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
|
||||||
|
pthread_rwlockattr_init(&attr);
|
||||||
|
|
||||||
|
#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
|
||||||
|
pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
res = pthread_rwlock_init(&prwlock->lock, &attr);
|
||||||
|
pthread_rwlockattr_destroy(&attr);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
int canlog = strcmp(filename, "logger.c");
|
||||||
|
|
||||||
|
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
||||||
|
if (*prwlock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
||||||
|
__ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
|
||||||
|
filename, lineno, func, rwlock_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name,
|
||||||
|
const char *file, int line, const char *func)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
||||||
|
int canlog = strcmp(file, "logger.c");
|
||||||
|
|
||||||
|
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
||||||
|
__ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
|
||||||
|
file, line, func, name);
|
||||||
|
res = __ast_rwlock_init(file, line, func, name, lock);
|
||||||
|
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
||||||
|
__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
|
||||||
|
file, line, func, name);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name,
|
||||||
|
const char *file, int line, const char *func)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
||||||
|
int canlog = strcmp(file, "logger.c");
|
||||||
|
|
||||||
|
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
||||||
|
/* Don't warn abount uninitialized lock.
|
||||||
|
* Simple try to initialize it.
|
||||||
|
* May be not needed in linux system.
|
||||||
|
*/
|
||||||
|
res = __ast_rwlock_init(file, line, func, name, lock);
|
||||||
|
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
||||||
|
__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
|
||||||
|
file, line, func, name);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#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);
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name,
|
||||||
|
const char *file, int line, const char *func)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
||||||
|
int canlog = strcmp(file, "logger.c");
|
||||||
|
|
||||||
|
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
||||||
|
/* Don't warn abount uninitialized lock.
|
||||||
|
* Simple try to initialize it.
|
||||||
|
* May be not needed in linux system.
|
||||||
|
*/
|
||||||
|
res = __ast_rwlock_init(file, line, func, name, lock);
|
||||||
|
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
||||||
|
__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
|
||||||
|
file, line, func, name);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#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);
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name,
|
||||||
|
const char *file, int line, const char *func)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
||||||
|
int canlog = strcmp(file, "logger.c");
|
||||||
|
|
||||||
|
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
||||||
|
/* Don't warn abount uninitialized lock.
|
||||||
|
* Simple try to initialize it.
|
||||||
|
* May be not needed in linux system.
|
||||||
|
*/
|
||||||
|
res = __ast_rwlock_init(file, line, func, name, lock);
|
||||||
|
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
||||||
|
__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
|
||||||
|
file, line, func, name);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#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);
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name,
|
||||||
|
const char *file, int line, const char *func)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
||||||
|
int canlog = strcmp(file, "logger.c");
|
||||||
|
|
||||||
|
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
||||||
|
/* Don't warn abount uninitialized lock.
|
||||||
|
* Simple try to initialize it.
|
||||||
|
* May be not needed in linux system.
|
||||||
|
*/
|
||||||
|
res = __ast_rwlock_init(file, line, func, name, lock);
|
||||||
|
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
||||||
|
__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
|
||||||
|
file, line, func, name);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#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);
|
||||||
|
#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;
|
typedef pthread_mutex_t ast_mutex_t;
|
||||||
|
|
||||||
@@ -773,6 +1190,61 @@ static inline int ast_cond_timedwait(ast_cond_t *cond, ast_mutex_t *t, const str
|
|||||||
return pthread_cond_timedwait(cond, t, 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;
|
||||||
|
pthread_rwlockattr_t attr;
|
||||||
|
|
||||||
|
pthread_rwlockattr_init(&attr);
|
||||||
|
|
||||||
|
#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
|
||||||
|
pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
res = pthread_rwlock_init(prwlock, &attr);
|
||||||
|
pthread_rwlockattr_destroy(&attr);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
|
||||||
|
{
|
||||||
|
return pthread_rwlock_destroy(prwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
|
||||||
|
{
|
||||||
|
return pthread_rwlock_unlock(prwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
|
||||||
|
{
|
||||||
|
return pthread_rwlock_rdlock(prwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
|
||||||
|
{
|
||||||
|
return pthread_rwlock_tryrdlock(prwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
|
||||||
|
{
|
||||||
|
return pthread_rwlock_wrlock(prwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
|
||||||
|
{
|
||||||
|
return pthread_rwlock_trywrlock(prwlock);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* !DEBUG_THREADS */
|
#endif /* !DEBUG_THREADS */
|
||||||
|
|
||||||
#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
|
#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
|
||||||
@@ -826,274 +1298,6 @@ static void __attribute__ ((destructor)) fini_##mutex(void) \
|
|||||||
#define pthread_create __use_ast_pthread_create_instead__
|
#define pthread_create __use_ast_pthread_create_instead__
|
||||||
#endif
|
#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 }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DEBUG_THREADS
|
|
||||||
|
|
||||||
#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)
|
|
||||||
#define ast_rwlock_unlock(a) _ast_rwlock_unlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
||||||
#define ast_rwlock_rdlock(a) _ast_rwlock_rdlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
||||||
#define ast_rwlock_wrlock(a) _ast_rwlock_wrlock(a, # a, __FILE__, __LINE__, __PRETTY_FUNCTION__)
|
|
||||||
#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__)
|
|
||||||
|
|
||||||
|
|
||||||
static inline int __ast_rwlock_init(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
pthread_rwlockattr_t attr;
|
|
||||||
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
|
||||||
int canlog = strcmp(filename, "logger.c");
|
|
||||||
|
|
||||||
if (*prwlock != ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
|
||||||
__ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
|
|
||||||
filename, lineno, func, rwlock_name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
|
|
||||||
pthread_rwlockattr_init(&attr);
|
|
||||||
|
|
||||||
#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
|
|
||||||
pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
res = pthread_rwlock_init(prwlock, &attr);
|
|
||||||
pthread_rwlockattr_destroy(&attr);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *prwlock)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
int canlog = strcmp(filename, "logger.c");
|
|
||||||
|
|
||||||
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
|
||||||
if (*prwlock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
|
||||||
__ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
|
|
||||||
filename, lineno, func, rwlock_name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
|
|
||||||
|
|
||||||
if ((res = pthread_rwlock_destroy(prwlock)))
|
|
||||||
__ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
|
|
||||||
filename, lineno, func, rwlock_name, strerror(res));
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline int _ast_rwlock_unlock(ast_rwlock_t *lock, const char *name,
|
|
||||||
const char *file, int line, const char *func)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
|
||||||
int canlog = strcmp(file, "logger.c");
|
|
||||||
|
|
||||||
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
|
||||||
__ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
|
|
||||||
file, line, func, name);
|
|
||||||
res = __ast_rwlock_init(file, line, func, name, lock);
|
|
||||||
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
|
||||||
__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
|
|
||||||
file, line, func, name);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
|
|
||||||
|
|
||||||
res = pthread_rwlock_unlock(lock);
|
|
||||||
ast_remove_lock_info(lock);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline int _ast_rwlock_rdlock(ast_rwlock_t *lock, const char *name,
|
|
||||||
const char *file, int line, const char *func)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
|
||||||
int canlog = strcmp(file, "logger.c");
|
|
||||||
|
|
||||||
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
|
||||||
/* Don't warn abount uninitialized lock.
|
|
||||||
* Simple try to initialize it.
|
|
||||||
* May be not needed in linux system.
|
|
||||||
*/
|
|
||||||
res = __ast_rwlock_init(file, line, func, name, lock);
|
|
||||||
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
|
||||||
__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
|
|
||||||
file, line, func, name);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
|
|
||||||
|
|
||||||
ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
|
|
||||||
res = pthread_rwlock_rdlock(lock);
|
|
||||||
if (!res)
|
|
||||||
ast_mark_lock_acquired(lock);
|
|
||||||
else
|
|
||||||
ast_remove_lock_info(lock);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline int _ast_rwlock_wrlock(ast_rwlock_t *lock, const char *name,
|
|
||||||
const char *file, int line, const char *func)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
|
||||||
int canlog = strcmp(file, "logger.c");
|
|
||||||
|
|
||||||
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
|
||||||
/* Don't warn abount uninitialized lock.
|
|
||||||
* Simple try to initialize it.
|
|
||||||
* May be not needed in linux system.
|
|
||||||
*/
|
|
||||||
res = __ast_rwlock_init(file, line, func, name, lock);
|
|
||||||
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
|
||||||
__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
|
|
||||||
file, line, func, name);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
|
|
||||||
|
|
||||||
ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
|
|
||||||
res = pthread_rwlock_wrlock(lock);
|
|
||||||
if (!res)
|
|
||||||
ast_mark_lock_acquired(lock);
|
|
||||||
else
|
|
||||||
ast_remove_lock_info(lock);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline int _ast_rwlock_tryrdlock(ast_rwlock_t *lock, const char *name,
|
|
||||||
const char *file, int line, const char *func)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
|
||||||
int canlog = strcmp(file, "logger.c");
|
|
||||||
|
|
||||||
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
|
||||||
/* Don't warn abount uninitialized lock.
|
|
||||||
* Simple try to initialize it.
|
|
||||||
* May be not needed in linux system.
|
|
||||||
*/
|
|
||||||
res = __ast_rwlock_init(file, line, func, name, lock);
|
|
||||||
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
|
||||||
__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
|
|
||||||
file, line, func, name);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
|
|
||||||
|
|
||||||
ast_store_lock_info(AST_RDLOCK, file, line, func, name, lock);
|
|
||||||
res = pthread_rwlock_tryrdlock(lock);
|
|
||||||
if (!res)
|
|
||||||
ast_mark_lock_acquired(lock);
|
|
||||||
else
|
|
||||||
ast_remove_lock_info(lock);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline int _ast_rwlock_trywrlock(ast_rwlock_t *lock, const char *name,
|
|
||||||
const char *file, int line, const char *func)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
|
|
||||||
int canlog = strcmp(file, "logger.c");
|
|
||||||
|
|
||||||
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
|
||||||
/* Don't warn abount uninitialized lock.
|
|
||||||
* Simple try to initialize it.
|
|
||||||
* May be not needed in linux system.
|
|
||||||
*/
|
|
||||||
res = __ast_rwlock_init(file, line, func, name, lock);
|
|
||||||
if (*lock == ((ast_rwlock_t) AST_RWLOCK_INIT_VALUE)) {
|
|
||||||
__ast_mutex_logger("%s line %d (%s): Error: rwlock '%s' is uninitialized and unable to initialize.\n",
|
|
||||||
file, line, func, name);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
|
|
||||||
|
|
||||||
ast_store_lock_info(AST_WRLOCK, file, line, func, name, lock);
|
|
||||||
res = pthread_rwlock_trywrlock(lock);
|
|
||||||
if (!res)
|
|
||||||
ast_mark_lock_acquired(lock);
|
|
||||||
else
|
|
||||||
ast_remove_lock_info(lock);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* !DEBUG_THREADS */
|
|
||||||
|
|
||||||
static inline int ast_rwlock_init(ast_rwlock_t *prwlock)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
pthread_rwlockattr_t attr;
|
|
||||||
|
|
||||||
pthread_rwlockattr_init(&attr);
|
|
||||||
|
|
||||||
#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
|
|
||||||
pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
res = pthread_rwlock_init(prwlock, &attr);
|
|
||||||
pthread_rwlockattr_destroy(&attr);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ast_rwlock_destroy(ast_rwlock_t *prwlock)
|
|
||||||
{
|
|
||||||
return pthread_rwlock_destroy(prwlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ast_rwlock_unlock(ast_rwlock_t *prwlock)
|
|
||||||
{
|
|
||||||
return pthread_rwlock_unlock(prwlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ast_rwlock_rdlock(ast_rwlock_t *prwlock)
|
|
||||||
{
|
|
||||||
return pthread_rwlock_rdlock(prwlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ast_rwlock_tryrdlock(ast_rwlock_t *prwlock)
|
|
||||||
{
|
|
||||||
return pthread_rwlock_tryrdlock(prwlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ast_rwlock_wrlock(ast_rwlock_t *prwlock)
|
|
||||||
{
|
|
||||||
return pthread_rwlock_wrlock(prwlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int ast_rwlock_trywrlock(ast_rwlock_t *prwlock)
|
|
||||||
{
|
|
||||||
return pthread_rwlock_trywrlock(prwlock);
|
|
||||||
}
|
|
||||||
#endif /* !DEBUG_THREADS */
|
|
||||||
|
|
||||||
/* Statically declared read/write locks */
|
/* Statically declared read/write locks */
|
||||||
|
|
||||||
#ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
|
#ifndef HAVE_PTHREAD_RWLOCK_INITIALIZER
|
||||||
|
@@ -219,6 +219,50 @@ unsigned int ast_verbose_get_by_file(const char *file);
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} 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)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -1127,30 +1127,67 @@ void ast_log(int level, const char *file, int line, const char *function, const
|
|||||||
return;
|
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)
|
void ast_backtrace(void)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_BKTR
|
#ifdef HAVE_BKTR
|
||||||
int count = 0, i = 0;
|
struct ast_bt *backtrace;
|
||||||
void **addresses;
|
int i = 0;
|
||||||
char **strings;
|
char **strings;
|
||||||
|
|
||||||
if ((addresses = ast_calloc(MAX_BACKTRACE_FRAMES, sizeof(*addresses)))) {
|
if (!(backtrace = ast_bt_create())) {
|
||||||
count = backtrace(addresses, MAX_BACKTRACE_FRAMES);
|
ast_log(LOG_WARNING, "Unable to allocate space for backtrace structure\n");
|
||||||
if ((strings = backtrace_symbols(addresses, count))) {
|
return;
|
||||||
ast_debug(1, "Got %d backtrace record%c\n", count, count != 1 ? 's' : ' ');
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
#if __WORDSIZE == 32
|
|
||||||
ast_log(LOG_DEBUG, "#%d: [%08X] %s\n", i, (unsigned int)addresses[i], strings[i]);
|
|
||||||
#elif __WORDSIZE == 64
|
|
||||||
ast_log(LOG_DEBUG, "#%d: [%016lX] %s\n", i, (unsigned long)addresses[i], strings[i]);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
free(strings);
|
|
||||||
} else {
|
|
||||||
ast_debug(1, "Could not allocate memory for backtrace\n");
|
|
||||||
}
|
|
||||||
ast_free(addresses);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)backtrace->addresses[i], strings[i]);
|
||||||
|
#elif __WORDSIZE == 64
|
||||||
|
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_bt_destroy(backtrace);
|
||||||
#else
|
#else
|
||||||
ast_log(LOG_WARNING, "Must run configure with '--with-execinfo' for stack backtraces.\n");
|
ast_log(LOG_WARNING, "Must run configure with '--with-execinfo' for stack backtraces.\n");
|
||||||
#endif
|
#endif
|
||||||
|
50
main/utils.c
50
main/utils.c
@@ -540,6 +540,9 @@ struct thr_lock_info {
|
|||||||
enum ast_lock_type type;
|
enum ast_lock_type type;
|
||||||
/*! This thread is waiting on this lock */
|
/*! This thread is waiting on this lock */
|
||||||
int pending:2;
|
int pending:2;
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
struct ast_bt *backtrace;
|
||||||
|
#endif
|
||||||
} locks[AST_MAX_LOCKS];
|
} locks[AST_MAX_LOCKS];
|
||||||
/*! This is the number of locks currently held by this thread.
|
/*! 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
|
* 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
|
* \brief The thread storage key for per-thread lock info
|
||||||
*/
|
*/
|
||||||
AST_THREADSTORAGE_CUSTOM(thread_lock_info, NULL, lock_info_destroy);
|
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,
|
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)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
struct thr_lock_info *lock_info;
|
struct thr_lock_info *lock_info;
|
||||||
int i;
|
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++) {
|
for (i = 0; i < lock_info->num_locks; i++) {
|
||||||
if (lock_info->locks[i].lock_addr == lock_addr) {
|
if (lock_info->locks[i].lock_addr == lock_addr) {
|
||||||
lock_info->locks[i].times_locked++;
|
lock_info->locks[i].times_locked++;
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
lock_info->locks[i].backtrace = bt;
|
||||||
|
#endif
|
||||||
pthread_mutex_unlock(&lock_info->lock);
|
pthread_mutex_unlock(&lock_info->lock);
|
||||||
return;
|
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].times_locked = 1;
|
||||||
lock_info->locks[i].type = type;
|
lock_info->locks[i].type = type;
|
||||||
lock_info->locks[i].pending = 1;
|
lock_info->locks[i].pending = 1;
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
lock_info->locks[i].backtrace = bt;
|
||||||
|
#endif
|
||||||
lock_info->num_locks++;
|
lock_info->num_locks++;
|
||||||
|
|
||||||
pthread_mutex_unlock(&lock_info->lock);
|
pthread_mutex_unlock(&lock_info->lock);
|
||||||
@@ -661,8 +674,11 @@ void ast_mark_lock_failed(void *lock_addr)
|
|||||||
}
|
}
|
||||||
pthread_mutex_unlock(&lock_info->lock);
|
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)
|
void ast_remove_lock_info(void *lock_addr)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
struct thr_lock_info *lock_info;
|
struct thr_lock_info *lock_info;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -685,6 +701,9 @@ void ast_remove_lock_info(void *lock_addr)
|
|||||||
|
|
||||||
if (lock_info->locks[i].times_locked > 1) {
|
if (lock_info->locks[i].times_locked > 1) {
|
||||||
lock_info->locks[i].times_locked--;
|
lock_info->locks[i].times_locked--;
|
||||||
|
#ifdef HAVE_BKTR
|
||||||
|
lock_info->locks[i].backtrace = bt;
|
||||||
|
#endif
|
||||||
pthread_mutex_unlock(&lock_info->lock);
|
pthread_mutex_unlock(&lock_info->lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -714,6 +733,30 @@ static const char *locktype2str(enum ast_lock_type type)
|
|||||||
return "UNKNOWN";
|
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)
|
static void append_lock_information(struct ast_str **str, struct thr_lock_info *lock_info, int i)
|
||||||
{
|
{
|
||||||
int j;
|
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].func, lock_info->locks[i].lock_name,
|
||||||
lock_info->locks[i].lock_addr,
|
lock_info->locks[i].lock_addr,
|
||||||
lock_info->locks[i].times_locked);
|
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)
|
if (!lock_info->locks[i].pending || lock_info->locks[i].pending == -1)
|
||||||
return;
|
return;
|
||||||
|
@@ -578,7 +578,16 @@ unsigned int ast_hashtab_hash_contexts(const void *obj)
|
|||||||
void ast_mark_lock_acquired(void *lock_addr)
|
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)
|
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)
|
int line_num, const char *func, const char *lock_name, void *lock_addr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* HAVE_BKTR */
|
||||||
#endif
|
#endif /* !defined(LOW_MEMORY) */
|
||||||
|
#endif /* DEBUG_THREADS */
|
||||||
|
@@ -86,6 +86,21 @@ enum ast_lock_type {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
#if !defined(LOW_MEMORY)
|
#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);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/* not a lot to do in a standalone w/o threading! */
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
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);
|
||||||
void ast_store_lock_info(enum ast_lock_type type, const char *filename,
|
void ast_store_lock_info(enum ast_lock_type type, const char *filename,
|
||||||
@@ -94,14 +109,15 @@ void ast_store_lock_info(enum ast_lock_type type, const char *filename,
|
|||||||
/* not a lot to do in a standalone w/o threading! */
|
/* not a lot to do in a standalone w/o threading! */
|
||||||
}
|
}
|
||||||
|
|
||||||
void ast_mark_lock_acquired(void *);
|
void ast_remove_lock_info(void *lock_addr);
|
||||||
void ast_mark_lock_acquired(void *foo)
|
void ast_remove_lock_info(void *lock_addr)
|
||||||
{
|
{
|
||||||
/* not a lot to do in a standalone w/o threading! */
|
/* not a lot to do in a standalone w/o threading! */
|
||||||
}
|
}
|
||||||
|
#endif /* HAVE_BKTR */
|
||||||
|
|
||||||
void ast_remove_lock_info(void *lock_addr);
|
void ast_mark_lock_acquired(void *);
|
||||||
void ast_remove_lock_info(void *lock_addr)
|
void ast_mark_lock_acquired(void *foo)
|
||||||
{
|
{
|
||||||
/* not a lot to do in a standalone w/o threading! */
|
/* not a lot to do in a standalone w/o threading! */
|
||||||
}
|
}
|
||||||
|
@@ -705,7 +705,16 @@ unsigned int ast_hashtab_hash_contexts(const void *obj)
|
|||||||
void ast_mark_lock_acquired(void *lock_addr)
|
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)
|
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)
|
int line_num, const char *func, const char *lock_name, void *lock_addr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* HAVE_BKTR */
|
||||||
#endif
|
#endif /* !defined(LOW_MEMORY) */
|
||||||
|
#endif /* DEBUG_THREADS */
|
||||||
|
@@ -366,3 +366,23 @@ void ast_register_thread(char *name)
|
|||||||
void ast_unregister_thread(void *id)
|
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
|
||||||
|
@@ -378,3 +378,20 @@ void ast_register_thread(char *name)
|
|||||||
void ast_unregister_thread(void *id)
|
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
|
||||||
|
@@ -269,3 +269,22 @@ void ast_register_thread(char *name)
|
|||||||
void ast_unregister_thread(void *id)
|
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
|
||||||
|
Reference in New Issue
Block a user