Fix potential deadlokc during arena_reset.

This commit is contained in:
guangli-dai 2026-07-23 15:48:14 -07:00 committed by Guangli Dai
parent 262f08301a
commit 6957341f19
2 changed files with 10 additions and 8 deletions

View file

@ -16,7 +16,7 @@
typedef enum {
background_thread_stopped,
background_thread_started,
/* Thread waits on the global lock when paused (for arena_reset). */
/* Thread waits on its condition variable when paused (arena_reset). */
background_thread_paused,
} background_thread_state_t;

View file

@ -59,8 +59,8 @@ background_thread_arena_reset_begin(tsd_t *tsd, unsigned arena_ind) {
if (background_thread_enabled()) {
background_thread_info_t *info =
background_thread_info_get(arena_ind);
assert(info->state == background_thread_started);
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
assert(info->state == background_thread_started);
info->state = background_thread_paused;
malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
}
@ -73,9 +73,12 @@ background_thread_arena_reset_finish(tsd_t *tsd, unsigned arena_ind) {
if (background_thread_enabled()) {
background_thread_info_t *info =
background_thread_info_get(arena_ind);
assert(info->state == background_thread_paused);
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
assert(info->state == background_thread_paused);
info->state = background_thread_started;
#ifdef JEMALLOC_BACKGROUND_THREAD
pthread_cond_signal(&info->cond);
#endif
malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx);
}
malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
@ -351,11 +354,10 @@ background_thread_sleep(
static bool
background_thread_pause_check(tsdn_t *tsdn, background_thread_info_t *info) {
if (unlikely(info->state == background_thread_paused)) {
malloc_mutex_unlock(tsdn, &info->mtx);
/* Wait on global lock to update status. */
malloc_mutex_lock(tsdn, &background_thread_lock);
malloc_mutex_unlock(tsdn, &background_thread_lock);
malloc_mutex_lock(tsdn, &info->mtx);
while (info->state == background_thread_paused) {
int ret = background_thread_cond_wait(info, NULL);
assert(ret == 0);
}
return true;
}