diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h index 0e442dbe07463491e681ec70a6410a761e8a8361..8e3a105c3c00ddab3d311141ca151dcdf91a948d 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 5b6817f6b5210f881b8f51ce7c8e042ce066bf8a..28091f9c4bc443c7f80b32015eef883a580cd8cb 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 91ebc1e2c9314c9926a0e6639179aa18836e2f85..d9d8a0ca781060a4ff04263f328d21a827d98daf 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 9c1d38383265b6086f3bcd2e18bd8e1690c7c6fc..77ca0eaf1973594bcff42cf3d250e45a60dc4e79 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,16 +245,12 @@ 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"); #ifdef HAVE_BKTR struct ast_bt *bt = NULL; #endif - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -367,16 +365,12 @@ 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"); #ifdef HAVE_BKTR struct ast_bt *bt = NULL; #endif - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -432,7 +426,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"); #ifdef HAVE_BKTR struct ast_bt *bt = NULL; #endif @@ -446,10 +440,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())) { @@ -561,7 +552,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)) { @@ -572,10 +563,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())) { @@ -629,7 +617,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)) { @@ -640,10 +628,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())) { @@ -706,7 +691,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); @@ -724,8 +710,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)) { @@ -772,7 +758,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"); #ifdef HAVE_BKTR struct ast_bt *bt = NULL; #endif @@ -787,10 +773,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) { @@ -851,16 +834,12 @@ 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"); #ifdef HAVE_BKTR struct ast_bt *bt = NULL; #endif - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -960,16 +939,12 @@ 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"); #ifdef HAVE_BKTR struct ast_bt *bt = NULL; #endif - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -1069,16 +1044,12 @@ 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"); #ifdef HAVE_BKTR struct ast_bt *bt = NULL; #endif - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -1162,16 +1133,12 @@ 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"); #ifdef HAVE_BKTR struct ast_bt *bt = NULL; #endif - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -1254,15 +1221,11 @@ 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); #ifdef HAVE_BKTR struct ast_bt *bt = NULL; #endif - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp; @@ -1313,15 +1276,11 @@ 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); #ifdef HAVE_BKTR struct ast_bt *bt = NULL; #endif - if (t->tracking) { - lt = ast_get_reentrancy(&t->track); - } - if (lt) { #ifdef HAVE_BKTR struct ast_bt tmp;