From 54f22c83d8f649f5c34d1b4d89050e00c631a32e Mon Sep 17 00:00:00 2001 From: Farid Zakaria Date: Mon, 6 Jul 2026 11:03:42 -0700 Subject: [PATCH] Initialize TSD tcache before enabling it --- src/tcache.c | 14 +++++++++----- src/tsd.c | 4 +--- test/unit/tsd.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/tcache.c b/src/tcache.c index 87a44522..9e442cc8 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -1044,24 +1044,28 @@ tcache_create_explicit(tsd_t *tsd) { bool tsd_tcache_enabled_data_init(tsd_t *tsd) { /* Called upon tsd initialization. */ - tsd_tcache_enabled_set(tsd, opt_tcache); /* * tcache is not available yet, but we need to set up its tcache_nbins * in advance. */ tcache_default_settings_init(tsd_tcache_slowp_get(tsd)); - tsd_slow_update(tsd); + +#if defined(JEMALLOC_JET) || defined(JEMALLOC_UNIT_TEST) if (test_hooks_tsd_bootstrap_hook != NULL) { test_hooks_tsd_bootstrap_hook(); } +#endif + bool err = false; if (opt_tcache) { - /* Trigger tcache init. */ - return tsd_tcache_data_init( + /* Initialize the bins before advertising the tcache. */ + err = tsd_tcache_data_init( tsd, NULL, tcache_get_default_ncached_max()); } - return false; + tsd_tcache_enabled_set(tsd, opt_tcache && !err); + tsd_slow_update(tsd); + return err; } void diff --git a/src/tsd.c b/src/tsd.c index ff023a21..9c05e17f 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -182,9 +182,7 @@ tsd_fetch_slow(tsd_t *tsd, bool minimal) { tsd_slow_update(tsd); /* Trigger cleanup handler registration. */ tsd_set(tsd); - tsd_pre_reentrancy_raw(tsd); tsd_data_init(tsd); - tsd_post_reentrancy_raw(tsd); } } else { tsd_state_set(tsd, tsd_state_minimal_initialized); @@ -212,9 +210,9 @@ tsd_fetch_slow(tsd_t *tsd, bool minimal) { /* Switch to fully initialized. */ tsd_state_set(tsd, tsd_state_nominal); assert(*tsd_reentrancy_levelp_get(tsd) >= 1); + (*tsd_reentrancy_levelp_get(tsd))--; tsd_slow_update(tsd); tsd_data_init(tsd); - tsd_post_reentrancy_raw(tsd); } else { assert_tsd_data_cleanup_done(tsd); } diff --git a/test/unit/tsd.c b/test/unit/tsd.c index 7dee910b..1e291133 100644 --- a/test/unit/tsd.c +++ b/test/unit/tsd.c @@ -131,10 +131,12 @@ TEST_BEGIN(test_tsd_reincarnation) { TEST_END static bool tsd_bootstrap_reentrant_hook_ran; +static unsigned tsd_bootstrap_reentrant_hook_runs; static void tsd_bootstrap_reentrant_hook(void) { tsd_bootstrap_reentrant_hook_ran = true; + tsd_bootstrap_reentrant_hook_runs++; test_hooks_tsd_bootstrap_hook = NULL; void *p = malloc(16); @@ -157,12 +159,39 @@ thd_start_reentrant_tsd_bootstrap(void *arg) { return NULL; } +static void * +thd_start_reentrant_tsd_bootstrap_minimal(void *arg) { + (void)arg; + + tsd_t *tsd = tsd_fetch_min(); + expect_u_eq(tsd_state_get(tsd), tsd_state_minimal_initialized, + "TSD should be minimal initialized"); + + test_hooks_tsd_bootstrap_hook = tsd_bootstrap_reentrant_hook; + void *p = malloc(1); + expect_ptr_not_null(p, "Unexpected malloc() failure"); + free(p); + test_hooks_tsd_bootstrap_hook = NULL; + + expect_true(tsd_bootstrap_reentrant_hook_ran, + "TSD bootstrap hook should have executed"); + return NULL; +} + TEST_BEGIN(test_tsd_reentrant_bootstrap) { thd_t thd; tsd_bootstrap_reentrant_hook_ran = false; + tsd_bootstrap_reentrant_hook_runs = 0; thd_create(&thd, thd_start_reentrant_tsd_bootstrap, NULL); thd_join(thd, NULL); + + tsd_bootstrap_reentrant_hook_ran = false; + thd_create(&thd, thd_start_reentrant_tsd_bootstrap_minimal, NULL); + thd_join(thd, NULL); + + expect_u_eq(tsd_bootstrap_reentrant_hook_runs, 2, + "TSD bootstrap hook should have executed once per case"); } TEST_END