mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +00:00 
			
		
		
		
	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
This commit is contained in:
		| @@ -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); | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
							
								
								
									
										125
									
								
								main/lock.c
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user