From 205c6be8955f5c90c5b3d2d47e302630337a966d Mon Sep 17 00:00:00 2001 From: Corey Farrell <git@cfware.com> Date: Thu, 27 Sep 2018 20:32:21 -0400 Subject: [PATCH] lock: Improve performance of DEBUG_THREADS. Add a volatile flag to lock tracking structures so we only need to use the global lock when first initializing tracking. Additionally add support for DEBUG_THREADS_LOOSE_ABI. This is used by astobj2.c to eliminate storage for tracking fields when DEBUG_THREADS is not defined. Change-Id: Iabd650908901843e9fff47ef1c539f0e1b8cb13b --- include/asterisk/astobj2.h | 3 + include/asterisk/lock.h | 39 +++++++++--- main/astobj2.c | 4 ++ main/lock.c | 125 +++++++++++++------------------------ 4 files changed, 81 insertions(+), 90 deletions(-) diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h index 0e442dbe07..8e3a105c3c 100644 --- a/include/asterisk/astobj2.h +++ b/include/asterisk/astobj2.h @@ -752,6 +752,9 @@ int __ao2_trylock(void *a, enum ao2_lock_req lock_how, const char *file, const c * lock address, this allows you to correlate against * object address, to match objects to reported locks. * + * \warning AO2 lock objects do not include tracking fields when + * DEBUG_THREADS is not enabled. + * * \since 1.6.1 */ void *ao2_object_get_lockaddr(void *obj); diff --git a/include/asterisk/lock.h b/include/asterisk/lock.h index a46d04799e..b409a27a1b 100644 --- a/include/asterisk/lock.h +++ b/include/asterisk/lock.h @@ -92,11 +92,11 @@ #define AST_LOCK_TRACK_INIT_VALUE { { NULL }, { 0 }, 0, { NULL }, { 0 }, PTHREAD_MUTEX_INIT_VALUE } #endif -#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, NULL, 1 } -#define AST_MUTEX_INIT_VALUE_NOTRACKING { PTHREAD_MUTEX_INIT_VALUE, NULL, 0 } +#define AST_MUTEX_INIT_VALUE { PTHREAD_MUTEX_INIT_VALUE, NULL, {1, 0} } +#define AST_MUTEX_INIT_VALUE_NOTRACKING { PTHREAD_MUTEX_INIT_VALUE, NULL, {0, 0} } -#define AST_RWLOCK_INIT_VALUE { __AST_RWLOCK_INIT_VALUE, NULL, 1 } -#define AST_RWLOCK_INIT_VALUE_NOTRACKING { __AST_RWLOCK_INIT_VALUE, NULL, 0 } +#define AST_RWLOCK_INIT_VALUE { __AST_RWLOCK_INIT_VALUE, NULL, {1, 0} } +#define AST_RWLOCK_INIT_VALUE_NOTRACKING { __AST_RWLOCK_INIT_VALUE, NULL, {0, 0} } #define AST_MAX_REENTRANCY 10 @@ -120,6 +120,13 @@ struct ast_lock_track { pthread_mutex_t reentr_mutex; }; +struct ast_lock_track_flags { + /*! non-zero if lock tracking is enabled */ + unsigned int tracking:1; + /*! non-zero if track is setup */ + volatile unsigned int setup:1; +}; + /*! \brief Structure for mutex and tracking information. * * We have tracking information in this structure regardless of DEBUG_THREADS being enabled. @@ -127,9 +134,18 @@ struct ast_lock_track { */ struct ast_mutex_info { pthread_mutex_t mutex; - /*! Track which thread holds this mutex */ +#if !defined(DEBUG_THREADS) && !defined(DEBUG_THREADS_LOOSE_ABI) + /*! + * These fields are renamed to ensure they are never used when + * DEBUG_THREADS is not defined. + */ + struct ast_lock_track *_track; + struct ast_lock_track_flags _flags; +#elif defined(DEBUG_THREADS) + /*! Track which thread holds this mutex. */ struct ast_lock_track *track; - unsigned int tracking:1; + struct ast_lock_track_flags flags; +#endif }; /*! \brief Structure for rwlock and tracking information. @@ -139,9 +155,18 @@ struct ast_mutex_info { */ struct ast_rwlock_info { pthread_rwlock_t lock; +#if !defined(DEBUG_THREADS) && !defined(DEBUG_THREADS_LOOSE_ABI) + /*! + * These fields are renamed to ensure they are never used when + * DEBUG_THREADS is not defined. + */ + struct ast_lock_track *_track; + struct ast_lock_track_flags _flags; +#elif defined(DEBUG_THREADS) /*! Track which thread holds this lock */ struct ast_lock_track *track; - unsigned int tracking:1; + struct ast_lock_track_flags flags; +#endif }; typedef struct ast_mutex_info ast_mutex_t; diff --git a/main/astobj2.c b/main/astobj2.c index 91ebc1e2c9..d9d8a0ca78 100644 --- a/main/astobj2.c +++ b/main/astobj2.c @@ -25,6 +25,10 @@ <support_level>core</support_level> ***/ +/* This reduces the size of lock structures within astobj2 objects when + * DEBUG_THREADS is not defined. */ +#define DEBUG_THREADS_LOOSE_ABI + #include "asterisk.h" #include "asterisk/_private.h" diff --git a/main/lock.c b/main/lock.c index dec814fb14..5ad9e134b7 100644 --- a/main/lock.c +++ b/main/lock.c @@ -72,21 +72,16 @@ static void __dump_backtrace(struct ast_bt *bt, int canlog) #ifdef DEBUG_THREADS AST_MUTEX_DEFINE_STATIC(reentrancy_lock); -static inline struct ast_lock_track *ast_get_reentrancy(struct ast_lock_track **plt) +static inline struct ast_lock_track *ast_get_reentrancy(struct ast_lock_track **plt, + struct ast_lock_track_flags *flags, int no_setup) { pthread_mutexattr_t reentr_attr; struct ast_lock_track *lt; - /* It's a bit painful to lock a global mutex for every access to the - * reentrancy structure, but it's necessary to ensure that we don't - * double-allocate the structure or double-initialize the reentr_mutex. - * - * If you'd like to replace this with a double-checked lock, be sure to - * properly volatile-ize everything to avoid optimizer bugs. - * - * We also have to use the underlying pthread calls for manipulating - * the mutex, because this is called from the Asterisk mutex code. - */ + if (!flags->tracking || flags->setup) { + return *plt; + } + pthread_mutex_lock(&reentrancy_lock.mutex); if (*plt) { @@ -94,6 +89,11 @@ static inline struct ast_lock_track *ast_get_reentrancy(struct ast_lock_track ** return *plt; } + if (no_setup) { + pthread_mutex_unlock(&reentrancy_lock.mutex); + return NULL; + } + lt = *plt = ast_std_calloc(1, sizeof(*lt)); if (!lt) { fprintf(stderr, "%s: Failed to allocate lock tracking\n", __func__); @@ -110,6 +110,7 @@ static inline struct ast_lock_track *ast_get_reentrancy(struct ast_lock_track ** pthread_mutex_init(<->reentr_mutex, &reentr_attr); pthread_mutexattr_destroy(&reentr_attr); + flags->setup = 1; pthread_mutex_unlock(&reentrancy_lock.mutex); return lt; } @@ -148,7 +149,8 @@ int __ast_pthread_mutex_init(int tracking, const char *filename, int lineno, con #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ t->track = NULL; - t->tracking = tracking; + t->flags.tracking = tracking; + t->flags.setup = 0; #endif /* DEBUG_THREADS */ pthread_mutexattr_init(&attr); @@ -165,8 +167,8 @@ int __ast_pthread_mutex_destroy(const char *filename, int lineno, const char *fu int res; #ifdef DEBUG_THREADS - struct ast_lock_track *lt = t->track; - int canlog = t->tracking && strcmp(filename, "logger.c"); + struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1); + int canlog = t->flags.tracking && strcmp(filename, "logger.c"); #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE) if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { @@ -243,14 +245,10 @@ int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, int res; #ifdef DEBUG_THREADS - struct ast_lock_track *lt = NULL; - int canlog = t->tracking && strcmp(filename, "logger.c"); + struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0); + int canlog = t->flags.tracking && strcmp(filename, "logger.c"); struct ast_bt *bt = NULL; - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -360,14 +358,10 @@ int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *fu int res; #ifdef DEBUG_THREADS - struct ast_lock_track *lt = NULL; - int canlog = t->tracking && strcmp(filename, "logger.c"); + struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0); + int canlog = t->flags.tracking && strcmp(filename, "logger.c"); struct ast_bt *bt = NULL; - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -420,7 +414,7 @@ int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *fun #ifdef DEBUG_THREADS struct ast_lock_track *lt = NULL; - int canlog = t->tracking && strcmp(filename, "logger.c"); + int canlog = t->flags.tracking && strcmp(filename, "logger.c"); struct ast_bt *bt = NULL; #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE) @@ -432,10 +426,7 @@ int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *fun } #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - + lt = ast_get_reentrancy(&t->track, &t->flags, 0); if (lt) { ast_reentrancy_lock(lt); if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) { @@ -543,7 +534,7 @@ int __ast_cond_wait(const char *filename, int lineno, const char *func, #ifdef DEBUG_THREADS struct ast_lock_track *lt = NULL; struct ast_lock_track lt_orig; - int canlog = t->tracking && strcmp(filename, "logger.c"); + int canlog = t->flags.tracking && strcmp(filename, "logger.c"); #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE) if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { @@ -554,10 +545,7 @@ int __ast_cond_wait(const char *filename, int lineno, const char *func, } #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - + lt = ast_get_reentrancy(&t->track, &t->flags, 0); if (lt) { ast_reentrancy_lock(lt); if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) { @@ -611,7 +599,7 @@ int __ast_cond_timedwait(const char *filename, int lineno, const char *func, #ifdef DEBUG_THREADS struct ast_lock_track *lt = NULL; struct ast_lock_track lt_orig; - int canlog = t->tracking && strcmp(filename, "logger.c"); + int canlog = t->flags.tracking && strcmp(filename, "logger.c"); #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE) if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) { @@ -622,10 +610,7 @@ int __ast_cond_timedwait(const char *filename, int lineno, const char *func, } #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - + lt = ast_get_reentrancy(&t->track, &t->flags, 0); if (lt) { ast_reentrancy_lock(lt); if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) { @@ -688,7 +673,8 @@ int __ast_rwlock_init(int tracking, const char *filename, int lineno, const char #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ t->track = NULL; - t->tracking = tracking; + t->flags.tracking = tracking; + t->flags.setup = 0; #endif /* DEBUG_THREADS */ pthread_rwlockattr_init(&attr); @@ -706,8 +692,8 @@ 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; - int canlog = t->tracking && strcmp(filename, "logger.c"); + struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1); + int canlog = t->flags.tracking && strcmp(filename, "logger.c"); #if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE) if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) { @@ -754,7 +740,7 @@ int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rw #ifdef DEBUG_THREADS struct ast_lock_track *lt = NULL; - int canlog = t->tracking && strcmp(filename, "logger.c"); + int canlog = t->flags.tracking && strcmp(filename, "logger.c"); struct ast_bt *bt = NULL; int lock_found = 0; @@ -767,10 +753,7 @@ int __ast_rwlock_unlock(const char *filename, int line, const char *func, ast_rw } #endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */ - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - + lt = ast_get_reentrancy(&t->track, &t->flags, 0); if (lt) { ast_reentrancy_lock(lt); if (lt->reentrancy) { @@ -827,14 +810,10 @@ int __ast_rwlock_rdlock(const char *filename, int line, const char *func, ast_rw int res; #ifdef DEBUG_THREADS - struct ast_lock_track *lt = NULL; - int canlog = t->tracking && strcmp(filename, "logger.c"); + struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0); + int canlog = t->flags.tracking && strcmp(filename, "logger.c"); struct ast_bt *bt = NULL; - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -929,14 +908,10 @@ int __ast_rwlock_wrlock(const char *filename, int line, const char *func, ast_rw int res; #ifdef DEBUG_THREADS - struct ast_lock_track *lt = NULL; - int canlog = t->tracking && strcmp(filename, "logger.c"); + struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0); + int canlog = t->flags.tracking && strcmp(filename, "logger.c"); struct ast_bt *bt = NULL; - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -1031,14 +1006,10 @@ int __ast_rwlock_timedrdlock(const char *filename, int line, const char *func, a int res; #ifdef DEBUG_THREADS - struct ast_lock_track *lt = NULL; - int canlog = t->tracking && strcmp(filename, "logger.c"); + struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0); + int canlog = t->flags.tracking && strcmp(filename, "logger.c"); struct ast_bt *bt = NULL; - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -1117,14 +1088,10 @@ int __ast_rwlock_timedwrlock(const char *filename, int line, const char *func, a int res; #ifdef DEBUG_THREADS - struct ast_lock_track *lt = NULL; - int canlog = t->tracking && strcmp(filename, "logger.c"); + struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0); + int canlog = t->flags.tracking && strcmp(filename, "logger.c"); struct ast_bt *bt = NULL; - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -1202,13 +1169,9 @@ int __ast_rwlock_tryrdlock(const char *filename, int line, const char *func, ast int res; #ifdef DEBUG_THREADS - struct ast_lock_track *lt = NULL; + struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0); struct ast_bt *bt = NULL; - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -1256,13 +1219,9 @@ int __ast_rwlock_trywrlock(const char *filename, int line, const char *func, ast int res; #ifdef DEBUG_THREADS - struct ast_lock_track *lt = NULL; + struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0); struct ast_bt *bt = NULL; - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; -- GitLab