mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-04-14 14:41:42 +03:00
Fix arena 0 deferral_allowed flag init
Arena 0 have a dedicated initialization path, which differs from
initialization path of other arenas. The main difference for the purpose
of this change is that we initialize arena 0 before we initialize
background threads. HPA shard options have `deferral_allowed` flag which
should be equal to `background_thread_enabled()` return value, but it
wasn't the case before this change, because for arena 0
`background_thread_enabled()` was initialized correctly after arena 0
initialization phase already ended.
Below is initialization sequence for arena 0 after this commit to
illustrate everything still should be initialized correctly.
* `hpa_central_init` initializes HPA Central, before we initialize every
HPA shard (including arena's 0).
* `background_thread_boot1` initializes `background_thread_enabled()`
return value.
* `pa_shard_enable_hpa` initializes arena 0 HPA shard.
```
malloc_init_hard -------------
/ / \
/ / \
/ / \
malloc_init_hard_a0_locked background_thread_boot1 pa_shard_enable_hpa
/ / \
/ / \
/ / \
arena_boot background_thread_enabled_seta hpa_shard_init
|
|
pa_central_init
|
|
hpa_central_init
```
This commit is contained in:
parent
421b17a622
commit
499f306859
3 changed files with 47 additions and 9 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue