diff --git a/src/arena.c b/src/arena.c index 884d1bf9..ab6006d7 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1789,8 +1789,8 @@ arena_new(tsdn_t *tsdn, unsigned ind, const arena_config_t *config) { * We turn on the HPA if set to. There are two exceptions: * - Custom extent hooks (we should only return memory allocated from * them in that case). - * - Arena 0 initialization. In this case, we're mid-bootstrapping, and - * so arena_hpa_global is not yet initialized. + * - Arena 0 initialization. In this case, we're mid-bootstrapping, + * and so background_thread_enabled is not yet initialized. */ if (opt_hpa && ehooks_are_default(base_ehooks_get(base)) && ind != 0) { hpa_shard_opts_t hpa_shard_opts = opt_hpa_opts; diff --git a/src/jemalloc.c b/src/jemalloc.c index 8ae72efb..55e85710 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1964,13 +1964,6 @@ malloc_init_hard_a0_locked(void) { } else { opt_hpa = false; } - } else if (opt_hpa) { - hpa_shard_opts_t hpa_shard_opts = opt_hpa_opts; - hpa_shard_opts.deferral_allowed = background_thread_enabled(); - if (pa_shard_enable_hpa(TSDN_NULL, &a0->pa_shard, - &hpa_shard_opts, &opt_hpa_sec_opts)) { - return true; - } } malloc_init_state = malloc_init_a0_initialized; @@ -2225,6 +2218,20 @@ malloc_init_hard(void) { || background_thread_boot1(tsd_tsdn(tsd), b0get())) { UNLOCK_RETURN(tsd_tsdn(tsd), true, true) } + if (opt_hpa) { + /* + * We didn't initialize arena 0 hpa_shard in arena_new, because + * background_thread_enabled wasn't initialized yet, but we + * need it to set correct value for deferral_allowed. + */ + arena_t *a0 = arena_get(tsd_tsdn(tsd), 0, false); + hpa_shard_opts_t hpa_shard_opts = opt_hpa_opts; + hpa_shard_opts.deferral_allowed = background_thread_enabled(); + if (pa_shard_enable_hpa(tsd_tsdn(tsd), &a0->pa_shard, + &hpa_shard_opts, &opt_hpa_sec_opts)) { + UNLOCK_RETURN(tsd_tsdn(tsd), true, true) + } + } if (config_prof && prof_boot2(tsd, b0get())) { UNLOCK_RETURN(tsd_tsdn(tsd), true, true) } diff --git a/test/unit/hpa_background_thread.c b/test/unit/hpa_background_thread.c index e4abb63b..93f046b5 100644 --- a/test/unit/hpa_background_thread.c +++ b/test/unit/hpa_background_thread.c @@ -1,6 +1,31 @@ #include "test/jemalloc_test.h" #include "test/sleep.h" +TEST_BEGIN(test_hpa_background_thread_a0_initialized) { + /* + * Arena 0 has dedicated initialization path. We'd like to make sure + * deferral_allowed value initialized correctly from the start of the + * application. + */ + test_skip_if(!config_stats); + test_skip_if(!hpa_supported()); + test_skip_if(!have_background_thread); + test_skip_if(san_guard_enabled()); + + bool enabled = false; + size_t sz = sizeof(enabled); + int err = mallctl("background_thread", (void *)&enabled, &sz, NULL, 0); + expect_d_eq(err, 0, "Unexpected mallctl() failure"); + expect_true(enabled, "Background thread should be enabled"); + + arena_t *a0 = arena_get(TSDN_NULL, 0, false); + expect_ptr_ne(a0, NULL, ""); + bool deferral_allowed = a0->pa_shard.hpa_shard.opts.deferral_allowed; + expect_true(deferral_allowed, + "Should have deferral_allowed option enabled for arena #0"); +} +TEST_END + static void sleep_for_background_thread_interval(void) { /* @@ -207,6 +232,12 @@ main(void) { opt_background_thread = true; } return test_no_reentrancy( + /* + * Unfortunately, order of tests is important here. We need to + * make sure arena #0 initialized correctly, before we start + * turning background thread on and off in other tests. + */ + test_hpa_background_thread_a0_initialized, test_hpa_background_thread_purges, test_hpa_background_thread_enable_disable); }