Skip to content
Snippets Groups Projects
Commit 308c1b41 authored by Richard Mudgett's avatar Richard Mudgett
Browse files

DEBUG_THREADS: Fix regression and lock tracking initialization problems.

This patch started with David Lee's patch at
https://reviewboard.asterisk.org/r/2826/ and includes a regression fix
introduced by the ASTERISK-22455 patch.

The initialization of a mutex's lock tracking structure was not protected
in a critical section.  This is fine for any mutex that is explicitly
initialized, but a static mutex may have its lock tracking double
initialized if multiple threads attempt the first lock simultaneously.

* Added a global mutex to properly serialize initialization of the lock
tracking structure.  The painful global lock can be mitigated by adding a
double checked lock flag as discussed on the original review request.

* Defer lock tracking initialization until first use.

* Don't be "helpful" and initialize an uninitialized lock when
DEBUG_THREADS is enabled.  Debug code is not supposed to fix or change
normal code behavior.  We don't need a lock initialization race that would
force a re-setup of lock tracking.  Lock tracking already handles
initialization on first use.

* Properly handle allocation failures of the lock tracking structure.

* No need to initialize tracking data in __ast_pthread_mutex_destroy()
just to turn around and destroy it.


The regression introduced by ASTERISK-22455 is the result of manipulating
a pthread_mutex_t struct outside of the pthread library code.  The
pthread_mutex_t struct seems to have a global linked list pointer member
that can get changed by other threads.  Therefore, saving and restoring
the contents of a pthread_mutex_t struct is a bad thing.

Thanks to Thomas Airmont for finding this obscure regression.

* Don't overwrite the struct ast_lock_track.reentr_mutex member to restore
tracking data in __ast_cond_wait() and __ast_cond_timedwait().  The
pthread_mutex_t struct must be treated as a read-only opaque variable.


Miscellaneous other items fixed by this patch:

* Match ast_suspend_lock_info() with ast_restore_lock_info() in
__ast_cond_timedwait().

* Made some uninitialized lock sanity checks return EINVAL and try a
DO_THREAD_CRASH.

* Fix bad canlog initialization expressions.

ASTERISK-24614 #close
Reported by: Thomas Airmont

Review: https://reviewboard.asterisk.org/r/4247/
Review: https://reviewboard.asterisk.org/r/2826/
........

Merged revisions 429539 from http://svn.asterisk.org/svn/asterisk/branches/11


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@429541 65c4cc65-6c06-0410-ace0-fbb531ad65f3
parent 901221ff
No related branches found
No related tags found
No related merge requests found
......@@ -18,7 +18,7 @@
/*! \file
* \brief Asterisk locking-related definitions:
* - ast_mutext_t, ast_rwlock_t and related functions;
* - ast_mutex_t, ast_rwlock_t and related functions;
* - atomic arithmetic instructions;
* - wrappers for channel locking.
*
......@@ -102,6 +102,12 @@
struct ast_channel;
/*!
* \brief Lock tracking information.
*
* \note Any changes to this struct MUST be reflected in the
* lock.c:restore_lock_tracking() function.
*/
struct ast_lock_track {
const char *file[AST_MAX_REENTRANCY];
int lineno[AST_MAX_REENTRANCY];
......@@ -474,45 +480,6 @@ static inline void ast_reentrancy_unlock(struct ast_lock_track *lt)
}
}
static inline void ast_reentrancy_init(struct ast_lock_track **plt)
{
int i;
pthread_mutexattr_t reentr_attr;
struct ast_lock_track *lt = *plt;
if (!lt) {
lt = *plt = (struct ast_lock_track *) calloc(1, sizeof(*lt));
}
for (i = 0; i < AST_MAX_REENTRANCY; i++) {
lt->file[i] = NULL;
lt->lineno[i] = 0;
lt->func[i] = NULL;
lt->thread[i] = 0;
#ifdef HAVE_BKTR
memset(&lt->backtrace[i], 0, sizeof(lt->backtrace[i]));
#endif
}
lt->reentrancy = 0;
pthread_mutexattr_init(&reentr_attr);
pthread_mutexattr_settype(&reentr_attr, AST_MUTEX_KIND);
pthread_mutex_init(&lt->reentr_mutex, &reentr_attr);
pthread_mutexattr_destroy(&reentr_attr);
}
static inline void delete_reentrancy_cs(struct ast_lock_track **plt)
{
struct ast_lock_track *lt;
if (*plt) {
lt = *plt;
pthread_mutex_destroy(&lt->reentr_mutex);
free(lt);
*plt = NULL;
}
}
#else /* !DEBUG_THREADS */
#define AO2_DEADLOCK_AVOIDANCE(obj) \
......
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment