Revert -r411073. It didn't help and blew up the system.
[asterisk/asterisk.git] / main / lock.c
index f988377..d66e01b 100644 (file)
  * \brief General Asterisk locking.
  */
 
+/*** MODULEINFO
+       <support_level>core</support_level>
+ ***/
+
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#include "asterisk/utils.h"
 #include "asterisk/lock.h"
 
 /* Allow direct use of pthread_mutex_* / pthread_cond_* */
@@ -41,6 +46,22 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #undef pthread_cond_wait
 #undef pthread_cond_timedwait
 
+#if defined(DEBUG_THREADS) && defined(HAVE_BKTR)
+static void __dump_backtrace(struct ast_bt *bt, int canlog)
+{
+       char **strings;
+       ssize_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]);
+       }
+
+       ast_std_free(strings);
+}
+#endif /* defined(DEBUG_THREADS) && defined(HAVE_BKTR) */
+
 int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, const char *func,
                                                const char *mutex_name, ast_mutex_t *t)
 {
@@ -48,6 +69,7 @@ int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, con
        pthread_mutexattr_t  attr;
 
 #ifdef DEBUG_THREADS
+       t->track = NULL;
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
        if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
 /*
@@ -61,8 +83,9 @@ int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, con
 
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-       ast_reentrancy_init(&t->track);
-       t->tracking = tracking;
+       if ((t->tracking = tracking)) {
+               ast_reentrancy_init(&t->track);
+       }
 #endif /* DEBUG_THREADS */
 
        pthread_mutexattr_init(&attr);
@@ -96,7 +119,10 @@ int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *fu
        }
 #endif
 
-       lt = &t->track;
+       if (t->tracking && !t->track) {
+               ast_reentrancy_init(&t->track);
+       }
+       lt = t->track;
 
        res = pthread_mutex_trylock(&t->mutex);
        switch (res) {
@@ -110,13 +136,15 @@ int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *fu
        case EBUSY:
                __ast_mutex_logger("%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
                                   filename, lineno, func, mutex_name);
-               ast_reentrancy_lock(lt);
-               __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
-                           lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
+               if (t->tracking) {
+                       ast_reentrancy_lock(lt);
+                       __ast_mutex_logger("%s line %d (%s): Error: '%s' was locked here.\n",
+                                   lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
 #ifdef HAVE_BKTR
-               __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
+                       __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
 #endif
-               ast_reentrancy_unlock(lt);
+                       ast_reentrancy_unlock(lt);
+               }
                break;
        }
 #endif /* DEBUG_THREADS */
@@ -128,29 +156,31 @@ int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *fu
                __ast_mutex_logger("%s line %d (%s): Error destroying mutex %s: %s\n",
                                   filename, lineno, func, mutex_name, strerror(res));
        }
-       ast_reentrancy_lock(lt);
-       lt->file[0] = filename;
-       lt->lineno[0] = lineno;
-       lt->func[0] = func;
-       lt->reentrancy = 0;
-       lt->thread[0] = 0;
+       if (t->tracking) {
+               ast_reentrancy_lock(lt);
+               lt->file[0] = filename;
+               lt->lineno[0] = lineno;
+               lt->func[0] = func;
+               lt->reentrancy = 0;
+               lt->thread[0] = 0;
 #ifdef HAVE_BKTR
-       memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
+               memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
 #endif
-       ast_reentrancy_unlock(lt);
-       delete_reentrancy_cs(lt);
+               ast_reentrancy_unlock(lt);
+               delete_reentrancy_cs(&t->track);
+       }
 #endif /* DEBUG_THREADS */
 
        return res;
 }
 
 int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
-                                           const char* mutex_name, ast_mutex_t *t)
+                               const char* mutex_name, ast_mutex_t *t)
 {
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = &t->track;
+       struct ast_lock_track *lt;
        int canlog = strcmp(filename, "logger.c") & t->tracking;
 #ifdef HAVE_BKTR
        struct ast_bt *bt = NULL;
@@ -171,14 +201,27 @@ int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
+       if (t->tracking && !t->track) {
+               ast_reentrancy_init(&t->track);
+       }
+       lt = t->track;
+
        if (t->tracking) {
 #ifdef HAVE_BKTR
+               struct ast_bt tmp;
+
+               /* The implementation of backtrace() may have its own locks.
+                * Capture the backtrace outside of the reentrancy lock to
+                * avoid deadlocks. See ASTERISK-22455. */
+               ast_bt_get_addresses(&tmp);
+
                ast_reentrancy_lock(lt);
                if (lt->reentrancy != AST_MAX_REENTRANCY) {
-                       ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+                       lt->backtrace[lt->reentrancy] = tmp;
                        bt = &lt->backtrace[lt->reentrancy];
                }
                ast_reentrancy_unlock(lt);
+
                ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
 #else
                ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
@@ -231,7 +274,7 @@ int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
 
 #ifdef DEBUG_THREADS
-       if (!res) {
+       if (t->tracking && !res) {
                ast_reentrancy_lock(lt);
                if (lt->reentrancy < AST_MAX_REENTRANCY) {
                        lt->file[lt->reentrancy] = filename;
@@ -247,7 +290,7 @@ int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
                if (t->tracking) {
                        ast_mark_lock_acquired(t);
                }
-       } else {
+       } else if (t->tracking) {
 #ifdef HAVE_BKTR
                if (lt->reentrancy) {
                        ast_reentrancy_lock(lt);
@@ -256,14 +299,12 @@ int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
                } else {
                        bt = NULL;
                }
-               if (t->tracking) {
-                       ast_remove_lock_info(t, bt);
-               }
+               ast_remove_lock_info(t, bt);
 #else
-               if (t->tracking) {
-                       ast_remove_lock_info(t);
-               }
+               ast_remove_lock_info(t);
 #endif
+       }
+       if (res) {
                __ast_mutex_logger("%s line %d (%s): Error obtaining mutex: %s\n",
                                   filename, lineno, func, strerror(res));
                DO_THREAD_CRASH;
@@ -274,12 +315,12 @@ int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func,
 }
 
 int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func,
-                                              const char* mutex_name, ast_mutex_t *t)
+                               const char* mutex_name, ast_mutex_t *t)
 {
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt= &t->track;
+       struct ast_lock_track *lt;
        int canlog = strcmp(filename, "logger.c") & t->tracking;
 #ifdef HAVE_BKTR
        struct ast_bt *bt = NULL;
@@ -300,14 +341,27 @@ int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *fu
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
+       if (t->tracking && !t->track) {
+               ast_reentrancy_init(&t->track);
+       }
+       lt = t->track;
+
        if (t->tracking) {
 #ifdef HAVE_BKTR
+               struct ast_bt tmp;
+
+               /* The implementation of backtrace() may have its own locks.
+                * Capture the backtrace outside of the reentrancy lock to
+                * avoid deadlocks. See ASTERISK-22455. */
+               ast_bt_get_addresses(&tmp);
+
                ast_reentrancy_lock(lt);
                if (lt->reentrancy != AST_MAX_REENTRANCY) {
-                       ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+                       lt->backtrace[lt->reentrancy] = tmp;
                        bt = &lt->backtrace[lt->reentrancy];
                }
                ast_reentrancy_unlock(lt);
+
                ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
 #else
                ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
@@ -318,7 +372,7 @@ int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *fu
        res = pthread_mutex_trylock(&t->mutex);
 
 #ifdef DEBUG_THREADS
-       if (!res) {
+       if (t->tracking && !res) {
                ast_reentrancy_lock(lt);
                if (lt->reentrancy < AST_MAX_REENTRANCY) {
                        lt->file[lt->reentrancy] = filename;
@@ -348,7 +402,7 @@ int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *fun
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = &t->track;
+       struct ast_lock_track *lt;
        int canlog = strcmp(filename, "logger.c") & t->tracking;
 #ifdef HAVE_BKTR
        struct ast_bt *bt = NULL;
@@ -367,39 +421,44 @@ int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *fun
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-       ast_reentrancy_lock(lt);
-       if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
-               __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
-                                  filename, lineno, func, mutex_name);
-               __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
-                                  lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
+       if (t->tracking && !t->track) {
+               ast_reentrancy_init(&t->track);
+       }
+       lt = t->track;
+
+       if (t->tracking) {
+               ast_reentrancy_lock(lt);
+               if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
+                       __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
+                                          filename, lineno, func, mutex_name);
+                       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+                                          lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
 #ifdef HAVE_BKTR
-               __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
+                       __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
 #endif
-               DO_THREAD_CRASH;
-       }
+                       DO_THREAD_CRASH;
+               }
 
-       if (--lt->reentrancy < 0) {
-               __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
-                                  filename, lineno, func, mutex_name);
-               lt->reentrancy = 0;
-       }
+               if (--lt->reentrancy < 0) {
+                       __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
+                                          filename, lineno, func, mutex_name);
+                       lt->reentrancy = 0;
+               }
 
-       if (lt->reentrancy < AST_MAX_REENTRANCY) {
-               lt->file[lt->reentrancy] = NULL;
-               lt->lineno[lt->reentrancy] = 0;
-               lt->func[lt->reentrancy] = NULL;
-               lt->thread[lt->reentrancy] = 0;
-       }
+               if (lt->reentrancy < AST_MAX_REENTRANCY) {
+                       lt->file[lt->reentrancy] = NULL;
+                       lt->lineno[lt->reentrancy] = 0;
+                       lt->func[lt->reentrancy] = NULL;
+                       lt->thread[lt->reentrancy] = 0;
+               }
 
 #ifdef HAVE_BKTR
-       if (lt->reentrancy) {
-               bt = &lt->backtrace[lt->reentrancy - 1];
-       }
+               if (lt->reentrancy) {
+                       bt = &lt->backtrace[lt->reentrancy - 1];
+               }
 #endif
-       ast_reentrancy_unlock(lt);
+               ast_reentrancy_unlock(lt);
 
-       if (t->tracking) {
 #ifdef HAVE_BKTR
                ast_remove_lock_info(t, bt);
 #else
@@ -453,11 +512,9 @@ int __ast_cond_wait(const char *filename, int lineno, const char *func,
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt= &t->track;
+       struct ast_lock_track *lt;
+       struct ast_lock_track lt_orig;
        int canlog = strcmp(filename, "logger.c") & t->tracking;
-#ifdef HAVE_BKTR
-       struct ast_bt *bt = NULL;
-#endif
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
        if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
@@ -472,44 +529,36 @@ int __ast_cond_wait(const char *filename, int lineno, const char *func,
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-       ast_reentrancy_lock(lt);
-       if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
-               __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
-                                  filename, lineno, func, mutex_name);
-               __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
-                                  lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
-#ifdef HAVE_BKTR
-               __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
-#endif
-               DO_THREAD_CRASH;
-       }
-
-       if (--lt->reentrancy < 0) {
-               __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
-                                  filename, lineno, func, mutex_name);
-               lt->reentrancy = 0;
-       }
-
-       if (lt->reentrancy < AST_MAX_REENTRANCY) {
-               lt->file[lt->reentrancy] = NULL;
-               lt->lineno[lt->reentrancy] = 0;
-               lt->func[lt->reentrancy] = NULL;
-               lt->thread[lt->reentrancy] = 0;
+       if (t->tracking && !t->track) {
+               ast_reentrancy_init(&t->track);
        }
-
-#ifdef HAVE_BKTR
-       if (lt->reentrancy) {
-               bt = &lt->backtrace[lt->reentrancy - 1];
-       }
-#endif
-       ast_reentrancy_unlock(lt);
+       lt = t->track;
 
        if (t->tracking) {
+               ast_reentrancy_lock(lt);
+               if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
+                       __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
+                                          filename, lineno, func, mutex_name);
+                       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+                                          lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
 #ifdef HAVE_BKTR
-               ast_remove_lock_info(t, bt);
-#else
-               ast_remove_lock_info(t);
+                       __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
 #endif
+                       DO_THREAD_CRASH;
+               } else if (lt->reentrancy <= 0) {
+                       __ast_mutex_logger("%s line %d (%s): attempted to wait on an unlocked mutex '%s'\n",
+                                          filename, lineno, func, mutex_name);
+                       DO_THREAD_CRASH;
+               }
+
+               /* Waiting on a condition completely suspends a recursive mutex,
+                * even if it's been recursively locked multiple times. Make a
+                * copy of the lock tracking, and reset reentrancy to zero */
+               lt_orig = *lt;
+               lt->reentrancy = 0;
+               ast_reentrancy_unlock(lt);
+
+               ast_suspend_lock_info(t);
        }
 #endif /* DEBUG_THREADS */
 
@@ -520,31 +569,17 @@ int __ast_cond_wait(const char *filename, int lineno, const char *func,
                __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
                                   filename, lineno, func, strerror(res));
                DO_THREAD_CRASH;
-       } else {
+       } else if (t->tracking) {
+               pthread_mutex_t reentr_mutex_orig;
                ast_reentrancy_lock(lt);
-               if (lt->reentrancy < AST_MAX_REENTRANCY) {
-                       lt->file[lt->reentrancy] = filename;
-                       lt->lineno[lt->reentrancy] = lineno;
-                       lt->func[lt->reentrancy] = func;
-                       lt->thread[lt->reentrancy] = pthread_self();
-#ifdef HAVE_BKTR
-                       ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
-                       bt = &lt->backtrace[lt->reentrancy];
-#endif
-                       lt->reentrancy++;
-               } else {
-                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-                                                          filename, lineno, func, mutex_name);
-               }
+               /* Restore lock tracking to what it was prior to the wait */
+               reentr_mutex_orig = lt->reentr_mutex;
+               *lt = lt_orig;
+               /* un-trash the mutex we just copied over */
+               lt->reentr_mutex = reentr_mutex_orig;
                ast_reentrancy_unlock(lt);
 
-               if (t->tracking) {
-#ifdef HAVE_BKTR
-                       ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
-#else
-                       ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
-#endif
-               }
+               ast_restore_lock_info(t);
        }
 #endif /* DEBUG_THREADS */
 
@@ -558,11 +593,9 @@ int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = &t->track;
+       struct ast_lock_track *lt;
+       struct ast_lock_track lt_orig;
        int canlog = strcmp(filename, "logger.c") & t->tracking;
-#ifdef HAVE_BKTR
-       struct ast_bt *bt = NULL;
-#endif
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
        if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
@@ -577,43 +610,36 @@ int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-       ast_reentrancy_lock(lt);
-       if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
-               __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
-                                  filename, lineno, func, mutex_name);
-               __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
-                                  lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
-#ifdef HAVE_BKTR
-               __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
-#endif
-               DO_THREAD_CRASH;
-       }
-
-       if (--lt->reentrancy < 0) {
-               __ast_mutex_logger("%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
-                                  filename, lineno, func, mutex_name);
-               lt->reentrancy = 0;
-       }
-
-       if (lt->reentrancy < AST_MAX_REENTRANCY) {
-               lt->file[lt->reentrancy] = NULL;
-               lt->lineno[lt->reentrancy] = 0;
-               lt->func[lt->reentrancy] = NULL;
-               lt->thread[lt->reentrancy] = 0;
+       if (t->tracking && !t->track) {
+               ast_reentrancy_init(&t->track);
        }
-#ifdef HAVE_BKTR
-       if (lt->reentrancy) {
-               bt = &lt->backtrace[lt->reentrancy - 1];
-       }
-#endif
-       ast_reentrancy_unlock(lt);
+       lt = t->track;
 
        if (t->tracking) {
+               ast_reentrancy_lock(lt);
+               if (lt->reentrancy && (lt->thread[ROFFSET] != pthread_self())) {
+                       __ast_mutex_logger("%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
+                                          filename, lineno, func, mutex_name);
+                       __ast_mutex_logger("%s line %d (%s): '%s' was locked here.\n",
+                                          lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
 #ifdef HAVE_BKTR
-               ast_remove_lock_info(t, bt);
-#else
-               ast_remove_lock_info(t);
+                       __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
 #endif
+                       DO_THREAD_CRASH;
+               } else if (lt->reentrancy <= 0) {
+                       __ast_mutex_logger("%s line %d (%s): attempted to wait on an unlocked mutex '%s'\n",
+                                          filename, lineno, func, mutex_name);
+                       DO_THREAD_CRASH;
+               }
+
+               /* Waiting on a condition completely suspends a recursive mutex,
+                * even if it's been recursively locked multiple times. Make a
+                * copy of the lock tracking, and reset reentrancy to zero */
+               lt_orig = *lt;
+               lt->reentrancy = 0;
+               ast_reentrancy_unlock(lt);
+
+               ast_suspend_lock_info(t);
        }
 #endif /* DEBUG_THREADS */
 
@@ -624,31 +650,17 @@ int __ast_cond_timedwait(const char *filename, int lineno, const char *func,
                __ast_mutex_logger("%s line %d (%s): Error waiting on condition mutex '%s'\n",
                                   filename, lineno, func, strerror(res));
                DO_THREAD_CRASH;
-       } else {
+       } else if (t->tracking) {
+               pthread_mutex_t reentr_mutex_orig;
                ast_reentrancy_lock(lt);
-               if (lt->reentrancy < AST_MAX_REENTRANCY) {
-                       lt->file[lt->reentrancy] = filename;
-                       lt->lineno[lt->reentrancy] = lineno;
-                       lt->func[lt->reentrancy] = func;
-                       lt->thread[lt->reentrancy] = pthread_self();
-#ifdef HAVE_BKTR
-                       ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
-                       bt = &lt->backtrace[lt->reentrancy];
-#endif
-                       lt->reentrancy++;
-               } else {
-                       __ast_mutex_logger("%s line %d (%s): '%s' really deep reentrancy!\n",
-                                                          filename, lineno, func, mutex_name);
-               }
+               /* Restore lock tracking to what it was prior to the wait */
+               reentr_mutex_orig = lt->reentr_mutex;
+               *lt = lt_orig;
+               /* un-trash the mutex we just copied over */
+               lt->reentr_mutex = reentr_mutex_orig;
                ast_reentrancy_unlock(lt);
 
-               if (t->tracking) {
-#ifdef HAVE_BKTR
-                       ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
-#else
-                       ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t);
-#endif
-               }
+               ast_suspend_lock_info(t);
        }
 #endif /* DEBUG_THREADS */
 
@@ -661,10 +673,9 @@ int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char
        pthread_rwlockattr_t attr;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt= &t->track;
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
-        int canlog = strcmp(filename, "logger.c") & t->tracking;
+       int canlog = strcmp(filename, "logger.c") & t->tracking;
 
        if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
                __ast_mutex_logger("%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
@@ -673,8 +684,9 @@ int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-       ast_reentrancy_init(lt);
-       t->tracking = tracking;
+       if ((t->tracking = tracking)) {
+               ast_reentrancy_init(&t->track);
+       }
 #endif /* DEBUG_THREADS */
 
        pthread_rwlockattr_init(&attr);
@@ -693,7 +705,7 @@ int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, con
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = &t->track;
+       struct ast_lock_track *lt = t->track;
        int canlog = strcmp(filename, "logger.c") & t->tracking;
 
 #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
@@ -713,29 +725,30 @@ int __ast_rwlock_destroy(const char *filename, int lineno, const char *func, con
                __ast_mutex_logger("%s line %d (%s): Error destroying rwlock %s: %s\n",
                                filename, lineno, func, rwlock_name, strerror(res));
        }
-       ast_reentrancy_lock(lt);
-       lt->file[0] = filename;
-       lt->lineno[0] = lineno;
-       lt->func[0] = func;
-       lt->reentrancy = 0;
-       lt->thread[0] = 0;
+       if (t->tracking && lt) {
+               ast_reentrancy_lock(lt);
+               lt->file[0] = filename;
+               lt->lineno[0] = lineno;
+               lt->func[0] = func;
+               lt->reentrancy = 0;
+               lt->thread[0] = 0;
 #ifdef HAVE_BKTR
-       memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
+               memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
 #endif
-       ast_reentrancy_unlock(lt);
-       delete_reentrancy_cs(lt);
+               ast_reentrancy_unlock(lt);
+               delete_reentrancy_cs(&t->track);
+       }
 #endif /* DEBUG_THREADS */
 
        return res;
 }
 
-int __ast_rwlock_unlock(ast_rwlock_t *t, const char *name,
-       const char *filename, int line, const char *func)
+int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
 {
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = &t->track;
+       struct ast_lock_track *lt;
        int canlog = strcmp(filename, "logger.c") & t->tracking;
 #ifdef HAVE_BKTR
        struct ast_bt *bt = NULL;
@@ -756,40 +769,45 @@ int __ast_rwlock_unlock(ast_rwlock_t *t, const char *name,
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
-       ast_reentrancy_lock(lt);
-       if (lt->reentrancy) {
-               int i;
-               pthread_t self = pthread_self();
-               for (i = lt->reentrancy - 1; i >= 0; --i) {
-                       if (lt->thread[i] == self) {
-                               lock_found = 1;
-                               if (i != lt->reentrancy - 1) {
-                                       lt->file[i] = lt->file[lt->reentrancy - 1];
-                                       lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
-                                       lt->func[i] = lt->func[lt->reentrancy - 1];
-                                       lt->thread[i] = lt->thread[lt->reentrancy - 1];
-                               }
+       if (t->tracking && !t->track) {
+               ast_reentrancy_init(&t->track);
+       }
+       lt = t->track;
+
+       if (t->tracking) {
+               ast_reentrancy_lock(lt);
+               if (lt->reentrancy) {
+                       int i;
+                       pthread_t self = pthread_self();
+                       for (i = lt->reentrancy - 1; i >= 0; --i) {
+                               if (lt->thread[i] == self) {
+                                       lock_found = 1;
+                                       if (i != lt->reentrancy - 1) {
+                                               lt->file[i] = lt->file[lt->reentrancy - 1];
+                                               lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
+                                               lt->func[i] = lt->func[lt->reentrancy - 1];
+                                               lt->thread[i] = lt->thread[lt->reentrancy - 1];
+                                       }
 #ifdef HAVE_BKTR
-                               bt = &lt->backtrace[i];
+                                       bt = &lt->backtrace[i];
 #endif
-                               lt->file[lt->reentrancy - 1] = NULL;
-                               lt->lineno[lt->reentrancy - 1] = 0;
-                               lt->func[lt->reentrancy - 1] = NULL;
-                               lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
-                               break;
+                                       lt->file[lt->reentrancy - 1] = NULL;
+                                       lt->lineno[lt->reentrancy - 1] = 0;
+                                       lt->func[lt->reentrancy - 1] = NULL;
+                                       lt->thread[lt->reentrancy - 1] = AST_PTHREADT_NULL;
+                                       break;
+                               }
                        }
                }
-       }
 
-       if (lock_found && --lt->reentrancy < 0) {
-               __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
-                               filename, line, func, name);
-               lt->reentrancy = 0;
-       }
+               if (lock_found && --lt->reentrancy < 0) {
+                       __ast_mutex_logger("%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
+                                       filename, line, func, name);
+                       lt->reentrancy = 0;
+               }
 
-       ast_reentrancy_unlock(lt);
+               ast_reentrancy_unlock(lt);
 
-       if (t->tracking) {
 #ifdef HAVE_BKTR
                ast_remove_lock_info(t, bt);
 #else
@@ -811,13 +829,12 @@ int __ast_rwlock_unlock(ast_rwlock_t *t, const char *name,
        return res;
 }
 
-int __ast_rwlock_rdlock(ast_rwlock_t *t, const char *name,
-       const char *filename, int line, const char *func)
+int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
 {
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = &t->track;
+       struct ast_lock_track *lt;
        int canlog = strcmp(filename, "logger.c") & t->tracking;
 #ifdef HAVE_BKTR
        struct ast_bt *bt = NULL;
@@ -838,14 +855,27 @@ int __ast_rwlock_rdlock(ast_rwlock_t *t, const char *name,
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
+       if (t->tracking && !t->track) {
+               ast_reentrancy_init(&t->track);
+       }
+       lt = t->track;
+
        if (t->tracking) {
 #ifdef HAVE_BKTR
+               struct ast_bt tmp;
+
+               /* The implementation of backtrace() may have its own locks.
+                * Capture the backtrace outside of the reentrancy lock to
+                * avoid deadlocks. See ASTERISK-22455. */
+               ast_bt_get_addresses(&tmp);
+
                ast_reentrancy_lock(lt);
                if (lt->reentrancy != AST_MAX_REENTRANCY) {
-                       ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+                       lt->backtrace[lt->reentrancy] = tmp;
                        bt = &lt->backtrace[lt->reentrancy];
                }
                ast_reentrancy_unlock(lt);
+
                ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
 #else
                ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
@@ -864,17 +894,19 @@ int __ast_rwlock_rdlock(ast_rwlock_t *t, const char *name,
                                if (wait_time > reported_wait && (wait_time % 5) == 0) {
                                        __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
                                                filename, line, func, (int)wait_time, name);
-                                       ast_reentrancy_lock(lt);
+                                       if (t->tracking) {
+                                               ast_reentrancy_lock(lt);
 #ifdef HAVE_BKTR
-                                       __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
+                                               __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
 #endif
-                                       __ast_mutex_logger("%s line %d (%s): '%s' was locked  here.\n",
-                                                       lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
-                                                       lt->func[lt->reentrancy-1], name);
+                                               __ast_mutex_logger("%s line %d (%s): '%s' was locked  here.\n",
+                                                               lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
+                                                               lt->func[lt->reentrancy-1], name);
 #ifdef HAVE_BKTR
-                                       __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
+                                               __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
 #endif
-                                       ast_reentrancy_unlock(lt);
+                                               ast_reentrancy_unlock(lt);
+                                       }
                                        reported_wait = wait_time;
                                }
                                usleep(200);
@@ -886,7 +918,7 @@ int __ast_rwlock_rdlock(ast_rwlock_t *t, const char *name,
 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
 
 #ifdef DEBUG_THREADS
-       if (!res) {
+       if (!res && t->tracking) {
                ast_reentrancy_lock(lt);
                if (lt->reentrancy < AST_MAX_REENTRANCY) {
                        lt->file[lt->reentrancy] = filename;
@@ -899,7 +931,7 @@ int __ast_rwlock_rdlock(ast_rwlock_t *t, const char *name,
                if (t->tracking) {
                        ast_mark_lock_acquired(t);
                }
-       } else {
+       } else if (t->tracking) {
 #ifdef HAVE_BKTR
                if (lt->reentrancy) {
                        ast_reentrancy_lock(lt);
@@ -908,14 +940,13 @@ int __ast_rwlock_rdlock(ast_rwlock_t *t, const char *name,
                } else {
                        bt = NULL;
                }
-               if (t->tracking) {
-                       ast_remove_lock_info(t, bt);
-               }
+               ast_remove_lock_info(t, bt);
 #else
-               if (t->tracking) {
-                       ast_remove_lock_info(t);
-               }
+               ast_remove_lock_info(t);
 #endif
+       }
+
+       if (res) {
                __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
                                filename, line, func, strerror(res));
                DO_THREAD_CRASH;
@@ -925,13 +956,12 @@ int __ast_rwlock_rdlock(ast_rwlock_t *t, const char *name,
        return res;
 }
 
-int __ast_rwlock_wrlock(ast_rwlock_t *t, const char *name,
-       const char *filename, int line, const char *func)
+int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
 {
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = &t->track;
+       struct ast_lock_track *lt;
        int canlog = strcmp(filename, "logger.c") & t->tracking;
 #ifdef HAVE_BKTR
        struct ast_bt *bt = NULL;
@@ -952,14 +982,27 @@ int __ast_rwlock_wrlock(ast_rwlock_t *t, const char *name,
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
+       if (t->tracking && !t->track) {
+               ast_reentrancy_init(&t->track);
+       }
+       lt = t->track;
+
        if (t->tracking) {
 #ifdef HAVE_BKTR
+               struct ast_bt tmp;
+
+               /* The implementation of backtrace() may have its own locks.
+                * Capture the backtrace outside of the reentrancy lock to
+                * avoid deadlocks. See ASTERISK-22455. */
+               ast_bt_get_addresses(&tmp);
+
                ast_reentrancy_lock(lt);
                if (lt->reentrancy != AST_MAX_REENTRANCY) {
-                       ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+                       lt->backtrace[lt->reentrancy] = tmp;
                        bt = &lt->backtrace[lt->reentrancy];
                }
                ast_reentrancy_unlock(lt);
+
                ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
 #else
                ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
@@ -978,17 +1021,19 @@ int __ast_rwlock_wrlock(ast_rwlock_t *t, const char *name,
                                if (wait_time > reported_wait && (wait_time % 5) == 0) {
                                        __ast_mutex_logger("%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
                                                filename, line, func, (int)wait_time, name);
-                                       ast_reentrancy_lock(lt);
+                                       if (t->tracking) {
+                                               ast_reentrancy_lock(lt);
 #ifdef HAVE_BKTR
-                                       __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
+                                               __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
 #endif
-                                       __ast_mutex_logger("%s line %d (%s): '%s' was locked  here.\n",
-                                                       lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
-                                                       lt->func[lt->reentrancy-1], name);
+                                               __ast_mutex_logger("%s line %d (%s): '%s' was locked  here.\n",
+                                                               lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
+                                                               lt->func[lt->reentrancy-1], name);
 #ifdef HAVE_BKTR
-                                       __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
+                                               __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
 #endif
-                                       ast_reentrancy_unlock(lt);
+                                               ast_reentrancy_unlock(lt);
+                                       }
                                        reported_wait = wait_time;
                                }
                                usleep(200);
@@ -1000,7 +1045,7 @@ int __ast_rwlock_wrlock(ast_rwlock_t *t, const char *name,
 #endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
 
 #ifdef DEBUG_THREADS
-       if (!res) {
+       if (!res && t->tracking) {
                ast_reentrancy_lock(lt);
                if (lt->reentrancy < AST_MAX_REENTRANCY) {
                        lt->file[lt->reentrancy] = filename;
@@ -1013,7 +1058,7 @@ int __ast_rwlock_wrlock(ast_rwlock_t *t, const char *name,
                if (t->tracking) {
                        ast_mark_lock_acquired(t);
                }
-       } else {
+       } else if (t->tracking) {
 #ifdef HAVE_BKTR
                if (lt->reentrancy) {
                        ast_reentrancy_lock(lt);
@@ -1030,6 +1075,8 @@ int __ast_rwlock_wrlock(ast_rwlock_t *t, const char *name,
                        ast_remove_lock_info(t);
                }
 #endif
+       }
+       if (res) {
                __ast_mutex_logger("%s line %d (%s): Error obtaining write lock: %s\n",
                                filename, line, func, strerror(res));
                DO_THREAD_CRASH;
@@ -1039,13 +1086,13 @@ int __ast_rwlock_wrlock(ast_rwlock_t *t, const char *name,
        return res;
 }
 
-int __ast_rwlock_timedrdlock(ast_rwlock_t *t, const char *name,
-       const struct timespec *abs_timeout, const char *filename, int line, const char *func)
+int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
+       const struct timespec *abs_timeout)
 {
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = &t->track;
+       struct ast_lock_track *lt;
        int canlog = strcmp(filename, "logger.c") & t->tracking;
 #ifdef HAVE_BKTR
        struct ast_bt *bt = NULL;
@@ -1066,14 +1113,27 @@ int __ast_rwlock_timedrdlock(ast_rwlock_t *t, const char *name,
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
+       if (t->tracking && !t->track) {
+               ast_reentrancy_init(&t->track);
+       }
+       lt = t->track;
+
        if (t->tracking) {
 #ifdef HAVE_BKTR
+               struct ast_bt tmp;
+
+               /* The implementation of backtrace() may have its own locks.
+                * Capture the backtrace outside of the reentrancy lock to
+                * avoid deadlocks. See ASTERISK-22455. */
+               ast_bt_get_addresses(&tmp);
+
                ast_reentrancy_lock(lt);
                if (lt->reentrancy != AST_MAX_REENTRANCY) {
-                       ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+                       lt->backtrace[lt->reentrancy] = tmp;
                        bt = &lt->backtrace[lt->reentrancy];
                }
                ast_reentrancy_unlock(lt);
+
                ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
 #else
                ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
@@ -1085,13 +1145,13 @@ int __ast_rwlock_timedrdlock(ast_rwlock_t *t, const char *name,
        res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
 #else
        do {
-               struct timeval _start = ast_tvnow(), _diff;
+               struct timeval _now;
                for (;;) {
                        if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
                                break;
                        }
-                       _diff = ast_tvsub(ast_tvnow(), _start);
-                       if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
+                       _now = ast_tvnow();
+                       if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
                                break;
                        }
                        usleep(1);
@@ -1100,7 +1160,7 @@ int __ast_rwlock_timedrdlock(ast_rwlock_t *t, const char *name,
 #endif
 
 #ifdef DEBUG_THREADS
-       if (!res) {
+       if (!res && t->tracking) {
                ast_reentrancy_lock(lt);
                if (lt->reentrancy < AST_MAX_REENTRANCY) {
                        lt->file[lt->reentrancy] = filename;
@@ -1113,7 +1173,7 @@ int __ast_rwlock_timedrdlock(ast_rwlock_t *t, const char *name,
                if (t->tracking) {
                        ast_mark_lock_acquired(t);
                }
-       } else {
+       } else if (t->tracking) {
 #ifdef HAVE_BKTR
                if (lt->reentrancy) {
                        ast_reentrancy_lock(lt);
@@ -1122,14 +1182,12 @@ int __ast_rwlock_timedrdlock(ast_rwlock_t *t, const char *name,
                } else {
                        bt = NULL;
                }
-               if (t->tracking) {
-                       ast_remove_lock_info(t, bt);
-               }
+               ast_remove_lock_info(t, bt);
 #else
-               if (t->tracking) {
-                       ast_remove_lock_info(t);
-               }
+               ast_remove_lock_info(t);
 #endif
+       }
+       if (res) {
                __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
                                filename, line, func, strerror(res));
                DO_THREAD_CRASH;
@@ -1139,13 +1197,13 @@ int __ast_rwlock_timedrdlock(ast_rwlock_t *t, const char *name,
        return res;
 }
 
-int __ast_rwlock_timedwrlock(ast_rwlock_t *t, const char *name,
-       const struct timespec *abs_timeout, const char *filename, int line, const char *func)
+int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name,
+       const struct timespec *abs_timeout)
 {
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = &t->track;
+       struct ast_lock_track *lt;
        int canlog = strcmp(filename, "logger.c") & t->tracking;
 #ifdef HAVE_BKTR
        struct ast_bt *bt = NULL;
@@ -1166,14 +1224,27 @@ int __ast_rwlock_timedwrlock(ast_rwlock_t *t, const char *name,
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
+       if (t->tracking && !t->track) {
+               ast_reentrancy_init(&t->track);
+       }
+       lt = t->track;
+
        if (t->tracking) {
 #ifdef HAVE_BKTR
+               struct ast_bt tmp;
+
+               /* The implementation of backtrace() may have its own locks.
+                * Capture the backtrace outside of the reentrancy lock to
+                * avoid deadlocks. See ASTERISK-22455. */
+               ast_bt_get_addresses(&tmp);
+
                ast_reentrancy_lock(lt);
                if (lt->reentrancy != AST_MAX_REENTRANCY) {
-                       ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+                       lt->backtrace[lt->reentrancy] = tmp;
                        bt = &lt->backtrace[lt->reentrancy];
                }
                ast_reentrancy_unlock(lt);
+
                ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
 #else
                ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
@@ -1185,13 +1256,13 @@ int __ast_rwlock_timedwrlock(ast_rwlock_t *t, const char *name,
        res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
 #else
        do {
-               struct timeval _start = ast_tvnow(), _diff;
+               struct timeval _now;
                for (;;) {
                        if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
                                break;
                        }
-                       _diff = ast_tvsub(ast_tvnow(), _start);
-                       if (_diff.tv_sec > abs_timeout->tv_sec || (_diff.tv_sec == abs_timeout->tv_sec && _diff.tv_usec * 1000 > abs_timeout->tv_nsec)) {
+                       _now = ast_tvnow();
+                       if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
                                break;
                        }
                        usleep(1);
@@ -1200,7 +1271,7 @@ int __ast_rwlock_timedwrlock(ast_rwlock_t *t, const char *name,
 #endif
 
 #ifdef DEBUG_THREADS
-       if (!res) {
+       if (!res && t->tracking) {
                ast_reentrancy_lock(lt);
                if (lt->reentrancy < AST_MAX_REENTRANCY) {
                        lt->file[lt->reentrancy] = filename;
@@ -1213,7 +1284,7 @@ int __ast_rwlock_timedwrlock(ast_rwlock_t *t, const char *name,
                if (t->tracking) {
                        ast_mark_lock_acquired(t);
                }
-       } else {
+       } else if (t->tracking) {
 #ifdef HAVE_BKTR
                if (lt->reentrancy) {
                        ast_reentrancy_lock(lt);
@@ -1230,6 +1301,8 @@ int __ast_rwlock_timedwrlock(ast_rwlock_t *t, const char *name,
                        ast_remove_lock_info(t);
                }
 #endif
+       }
+       if (res) {
                __ast_mutex_logger("%s line %d (%s): Error obtaining read lock: %s\n",
                                filename, line, func, strerror(res));
                DO_THREAD_CRASH;
@@ -1239,13 +1312,12 @@ int __ast_rwlock_timedwrlock(ast_rwlock_t *t, const char *name,
        return res;
 }
 
-int __ast_rwlock_tryrdlock(ast_rwlock_t *t, const char *name,
-       const char *filename, int line, const char *func)
+int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
 {
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt = &t->track;
+       struct ast_lock_track *lt;
 #ifdef HAVE_BKTR
        struct ast_bt *bt = NULL;
 #endif
@@ -1266,14 +1338,27 @@ int __ast_rwlock_tryrdlock(ast_rwlock_t *t, const char *name,
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
+       if (t->tracking && !t->track) {
+               ast_reentrancy_init(&t->track);
+       }
+       lt = t->track;
+
        if (t->tracking) {
 #ifdef HAVE_BKTR
+               struct ast_bt tmp;
+
+               /* The implementation of backtrace() may have its own locks.
+                * Capture the backtrace outside of the reentrancy lock to
+                * avoid deadlocks. See ASTERISK-22455. */
+               ast_bt_get_addresses(&tmp);
+
                ast_reentrancy_lock(lt);
                if (lt->reentrancy != AST_MAX_REENTRANCY) {
-                       ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+                       lt->backtrace[lt->reentrancy] = tmp;
                        bt = &lt->backtrace[lt->reentrancy];
                }
                ast_reentrancy_unlock(lt);
+
                ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
 #else
                ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t);
@@ -1284,7 +1369,7 @@ int __ast_rwlock_tryrdlock(ast_rwlock_t *t, const char *name,
        res = pthread_rwlock_tryrdlock(&t->lock);
 
 #ifdef DEBUG_THREADS
-       if (!res) {
+       if (!res && t->tracking) {
                ast_reentrancy_lock(lt);
                if (lt->reentrancy < AST_MAX_REENTRANCY) {
                        lt->file[lt->reentrancy] = filename;
@@ -1305,13 +1390,12 @@ int __ast_rwlock_tryrdlock(ast_rwlock_t *t, const char *name,
        return res;
 }
 
-int __ast_rwlock_trywrlock(ast_rwlock_t *t, const char *name,
-       const char *filename, int line, const char *func)
+int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast_rwlock_t *t, const char *name)
 {
        int res;
 
 #ifdef DEBUG_THREADS
-       struct ast_lock_track *lt= &t->track;
+       struct ast_lock_track *lt;
 #ifdef HAVE_BKTR
        struct ast_bt *bt = NULL;
 #endif
@@ -1332,14 +1416,27 @@ int __ast_rwlock_trywrlock(ast_rwlock_t *t, const char *name,
        }
 #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
 
+       if (t->tracking && !t->track) {
+               ast_reentrancy_init(&t->track);
+       }
+       lt = t->track;
+
        if (t->tracking) {
 #ifdef HAVE_BKTR
+               struct ast_bt tmp;
+
+               /* The implementation of backtrace() may have its own locks.
+                * Capture the backtrace outside of the reentrancy lock to
+                * avoid deadlocks. See ASTERISK-22455. */
+               ast_bt_get_addresses(&tmp);
+
                ast_reentrancy_lock(lt);
                if (lt->reentrancy != AST_MAX_REENTRANCY) {
-                       ast_bt_get_addresses(&lt->backtrace[lt->reentrancy]);
+                       lt->backtrace[lt->reentrancy] = tmp;
                        bt = &lt->backtrace[lt->reentrancy];
                }
                ast_reentrancy_unlock(lt);
+
                ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
 #else
                ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t);
@@ -1350,7 +1447,7 @@ int __ast_rwlock_trywrlock(ast_rwlock_t *t, const char *name,
        res = pthread_rwlock_trywrlock(&t->lock);
 
 #ifdef DEBUG_THREADS
-       if (!res) {
+       if (!res && t->tracking) {
                ast_reentrancy_lock(lt);
                if (lt->reentrancy < AST_MAX_REENTRANCY) {
                        lt->file[lt->reentrancy] = filename;
@@ -1360,9 +1457,7 @@ int __ast_rwlock_trywrlock(ast_rwlock_t *t, const char *name,
                        lt->reentrancy++;
                }
                ast_reentrancy_unlock(lt);
-               if (t->tracking) {
-                       ast_mark_lock_acquired(t);
-               }
+               ast_mark_lock_acquired(t);
        } else if (t->tracking) {
                ast_mark_lock_failed(t);
        }