summaryrefslogtreecommitdiff
path: root/main/utils.c
diff options
context:
space:
mode:
authorDavid M. Lee <dlee@digium.com>2013-09-09 20:13:40 +0000
committerDavid M. Lee <dlee@digium.com>2013-09-09 20:13:40 +0000
commitc2e6e1ef49d8e8745c9e4b6be2601b210a34506f (patch)
tree000084953c842ca083e688bcf8f36eed0cfd9747 /main/utils.c
parent0bcc676d09bbf11e02368ababe280795de61746d (diff)
Fix DEBUG_THREADS when lock is acquired in __constructor__
This patch fixes some long-standing bugs in debug threads that were exacerbated with recent Optional API work in Asterisk 12. With debug threads enabled, on some systems, there's a lock ordering problem between our mutex and glibc's mutex protecting its module list (Ubuntu Lucid, glibc 2.11.1 in this instance). In one thread, the module list will be locked before acquiring our mutex. In another thread, our mutex will be locked before locking the module list (which happens in the depths of calling backtrace()). This patch fixes this issue by moving backtrace() calls outside of critical sections that have the mutex acquired. The bigger change was to reentrancy tracking for ast_cond_{timed,}wait, which wrongly assumed that waiting on the mutex was equivalent to a single unlock (it actually suspends all recursive locks on the mutex). (closes issue ASTERISK-22455) Review: https://reviewboard.asterisk.org/r/2824/ ........ Merged revisions 398648 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 398649 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 398651 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@398652 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/utils.c')
-rw-r--r--main/utils.c97
1 files changed, 83 insertions, 14 deletions
diff --git a/main/utils.c b/main/utils.c
index 300d057d9..e2c5e2c3f 100644
--- a/main/utils.c
+++ b/main/utils.c
@@ -597,6 +597,8 @@ struct thr_lock_info {
enum ast_lock_type type;
/*! This thread is waiting on this lock */
int pending:2;
+ /*! A condition has suspended this lock */
+ int suspended:1;
#ifdef HAVE_BKTR
struct ast_bt *backtrace;
#endif
@@ -783,6 +785,60 @@ int ast_find_lock_info(void *lock_addr, char *filename, size_t filename_size, in
return 0;
}
+void ast_suspend_lock_info(void *lock_addr)
+{
+ struct thr_lock_info *lock_info;
+ int i = 0;
+
+ if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info)))) {
+ return;
+ }
+
+ pthread_mutex_lock(&lock_info->lock);
+
+ for (i = lock_info->num_locks - 1; i >= 0; i--) {
+ if (lock_info->locks[i].lock_addr == lock_addr)
+ break;
+ }
+
+ if (i == -1) {
+ /* Lock not found :( */
+ pthread_mutex_unlock(&lock_info->lock);
+ return;
+ }
+
+ lock_info->locks[i].suspended = 1;
+
+ pthread_mutex_unlock(&lock_info->lock);
+}
+
+void ast_restore_lock_info(void *lock_addr)
+{
+ struct thr_lock_info *lock_info;
+ int i = 0;
+
+ if (!(lock_info = ast_threadstorage_get(&thread_lock_info, sizeof(*lock_info))))
+ return;
+
+ pthread_mutex_lock(&lock_info->lock);
+
+ for (i = lock_info->num_locks - 1; i >= 0; i--) {
+ if (lock_info->locks[i].lock_addr == lock_addr)
+ break;
+ }
+
+ if (i == -1) {
+ /* Lock not found :( */
+ pthread_mutex_unlock(&lock_info->lock);
+ return;
+ }
+
+ lock_info->locks[i].suspended = 0;
+
+ pthread_mutex_unlock(&lock_info->lock);
+}
+
+
#ifdef HAVE_BKTR
void ast_remove_lock_info(void *lock_addr, struct ast_bt *bt)
#else
@@ -876,7 +932,7 @@ static void append_lock_information(struct ast_str **str, struct thr_lock_info *
ast_mutex_t *lock;
struct ast_lock_track *lt;
- ast_str_append(str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d)\n",
+ ast_str_append(str, 0, "=== ---> %sLock #%d (%s): %s %d %s %s %p (%d%s)\n",
lock_info->locks[i].pending > 0 ? "Waiting for " :
lock_info->locks[i].pending < 0 ? "Tried and failed to get " : "", i,
lock_info->locks[i].file,
@@ -884,7 +940,8 @@ static void append_lock_information(struct ast_str **str, struct thr_lock_info *
lock_info->locks[i].line_num,
lock_info->locks[i].func, lock_info->locks[i].lock_name,
lock_info->locks[i].lock_addr,
- lock_info->locks[i].times_locked);
+ lock_info->locks[i].times_locked,
+ lock_info->locks[i].suspended ? " - suspended" : "");
#ifdef HAVE_BKTR
append_backtrace_information(str, lock_info->locks[i].backtrace);
#endif
@@ -982,20 +1039,32 @@ struct ast_str *ast_dump_locks(void)
pthread_mutex_lock(&lock_infos_lock.mutex);
AST_LIST_TRAVERSE(&lock_infos, lock_info, entry) {
int i;
- if (lock_info->num_locks) {
- ast_str_append(&str, 0, "=== Thread ID: 0x%lx (%s)\n", (long) lock_info->thread_id,
- lock_info->thread_name);
- pthread_mutex_lock(&lock_info->lock);
- for (i = 0; str && i < lock_info->num_locks; i++) {
- append_lock_information(&str, lock_info, i);
+ int header_printed = 0;
+ pthread_mutex_lock(&lock_info->lock);
+ for (i = 0; str && i < lock_info->num_locks; i++) {
+ /* Don't show suspended locks */
+ if (lock_info->locks[i].suspended) {
+ continue;
}
- pthread_mutex_unlock(&lock_info->lock);
- if (!str)
- break;
+
+ if (!header_printed) {
+ ast_str_append(&str, 0, "=== Thread ID: 0x%lx (%s)\n", (long) lock_info->thread_id,
+ lock_info->thread_name);
+ header_printed = 1;
+ }
+
+ append_lock_information(&str, lock_info, i);
+ }
+ pthread_mutex_unlock(&lock_info->lock);
+ if (!str) {
+ break;
+ }
+ if (header_printed) {
ast_str_append(&str, 0, "=== -------------------------------------------------------------------\n"
- "===\n");
- if (!str)
- break;
+ "===\n");
+ }
+ if (!str) {
+ break;
}
}
pthread_mutex_unlock(&lock_infos_lock.mutex);