Pass surviving descriptor through jemalloc_postfork_child orchestrator

The orchestrator looks up the surviving descriptor via
tcache_postfork_arena_descriptor and threads it into
arena_postfork_child, eliminating arena's call into tcache. Also reset
cache_bin_array_descriptor_ql_mtx right before the queue rebuild it
protects.
This commit is contained in:
Slobodan Predolac
2026-05-08 11:36:12 -07:00
parent 3cd9753e23
commit 88745978e9
5 changed files with 28 additions and 23 deletions

View File

@@ -129,6 +129,7 @@ void arena_prefork6(tsdn_t *tsdn, arena_t *arena);
void arena_prefork7(tsdn_t *tsdn, arena_t *arena); void arena_prefork7(tsdn_t *tsdn, arena_t *arena);
void arena_prefork8(tsdn_t *tsdn, arena_t *arena); void arena_prefork8(tsdn_t *tsdn, arena_t *arena);
void arena_postfork_parent(tsdn_t *tsdn, arena_t *arena); void arena_postfork_parent(tsdn_t *tsdn, arena_t *arena);
void arena_postfork_child(tsdn_t *tsdn, arena_t *arena); void arena_postfork_child(tsdn_t *tsdn, arena_t *arena,
cache_bin_array_descriptor_t *surviving_desc);
#endif /* JEMALLOC_INTERNAL_ARENA_EXTERNS_H */ #endif /* JEMALLOC_INTERNAL_ARENA_EXTERNS_H */

View File

@@ -72,7 +72,8 @@ void tcaches_destroy(tsd_t *tsd, unsigned ind);
bool tcache_boot(tsdn_t *tsdn, base_t *base); bool tcache_boot(tsdn_t *tsdn, base_t *base);
void tcache_arena_associate( void tcache_arena_associate(
tsdn_t *tsdn, tcache_slow_t *tcache_slow, arena_t *arena); tsdn_t *tsdn, tcache_slow_t *tcache_slow, arena_t *arena);
void tcache_arena_postfork_child(tsdn_t *tsdn, arena_t *arena); cache_bin_array_descriptor_t *tcache_postfork_arena_descriptor(
tsdn_t *tsdn, arena_t *arena);
void tcache_prefork(tsdn_t *tsdn); void tcache_prefork(tsdn_t *tsdn);
void tcache_postfork_parent(tsdn_t *tsdn); void tcache_postfork_parent(tsdn_t *tsdn);
void tcache_postfork_child(tsdn_t *tsdn); void tcache_postfork_child(tsdn_t *tsdn);

View File

@@ -271,10 +271,9 @@ arena_cache_bin_array_unregister(tsdn_t *tsdn, arena_t *arena,
} }
/* /*
* Postfork-child entry: child is single-threaded and the queue is rebuilt * Postfork-child entry: child is single-threaded, so the queue is rebuilt
* from scratch (descriptors held by other threads at fork time are gone). * from scratch (descriptors held by other threads at fork time are gone)
* The mutex itself is reinitialized later in arena_postfork_child, so we * without locking.
* cannot lock here.
*/ */
void void
arena_cache_bin_array_postfork_child(arena_t *arena, arena_cache_bin_array_postfork_child(arena_t *arena,
@@ -2160,7 +2159,8 @@ arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) {
} }
void void
arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { arena_postfork_child(tsdn_t *tsdn, arena_t *arena,
cache_bin_array_descriptor_t *surviving_desc) {
atomic_store_u(&arena->nthreads[0], 0, ATOMIC_RELAXED); atomic_store_u(&arena->nthreads[0], 0, ATOMIC_RELAXED);
atomic_store_u(&arena->nthreads[1], 0, ATOMIC_RELAXED); atomic_store_u(&arena->nthreads[1], 0, ATOMIC_RELAXED);
if (tsd_arena_get(tsdn_tsd(tsdn)) == arena) { if (tsd_arena_get(tsdn_tsd(tsdn)) == arena) {
@@ -2169,7 +2169,11 @@ arena_postfork_child(tsdn_t *tsdn, arena_t *arena) {
if (tsd_iarena_get(tsdn_tsd(tsdn)) == arena) { if (tsd_iarena_get(tsdn_tsd(tsdn)) == arena) {
arena_nthreads_inc(arena, true); arena_nthreads_inc(arena, true);
} }
tcache_arena_postfork_child(tsdn, arena); if (config_stats) {
malloc_mutex_postfork_child(tsdn,
&arena->cache_bin_array_descriptor_ql_mtx);
arena_cache_bin_array_postfork_child(arena, surviving_desc);
}
for (unsigned i = 0; i < nbins_total; i++) { for (unsigned i = 0; i < nbins_total; i++) {
JEMALLOC_SUPPRESS_WARN_ON_USAGE( JEMALLOC_SUPPRESS_WARN_ON_USAGE(
@@ -2179,7 +2183,4 @@ arena_postfork_child(tsdn_t *tsdn, arena_t *arena) {
malloc_mutex_postfork_child(tsdn, &arena->large_mtx); malloc_mutex_postfork_child(tsdn, &arena->large_mtx);
base_postfork_child(tsdn, arena->base); base_postfork_child(tsdn, arena->base);
pa_shard_postfork_child(tsdn, &arena->pa_shard); pa_shard_postfork_child(tsdn, &arena->pa_shard);
if (config_stats) {
malloc_mutex_postfork_child(tsdn, &arena->cache_bin_array_descriptor_ql_mtx);
}
} }

View File

@@ -150,7 +150,10 @@ jemalloc_postfork_child(void) {
arena_t *arena; arena_t *arena;
if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) { if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) {
arena_postfork_child(tsd_tsdn(tsd), arena); cache_bin_array_descriptor_t *desc =
tcache_postfork_arena_descriptor(
tsd_tsdn(tsd), arena);
arena_postfork_child(tsd_tsdn(tsd), arena, desc);
} }
} }
prof_postfork_child(tsd_tsdn(tsd)); prof_postfork_child(tsd_tsdn(tsd));

View File

@@ -754,21 +754,20 @@ tcache_arena_reassociate(tsdn_t *tsdn, tcache_slow_t *tcache_slow,
tcache_arena_associate(tsdn, tcache_slow, arena); tcache_arena_associate(tsdn, tcache_slow, arena);
} }
void cache_bin_array_descriptor_t *
tcache_arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { tcache_postfork_arena_descriptor(tsdn_t *tsdn, arena_t *arena) {
if (!config_stats) { if (!config_stats) {
return; return NULL;
} }
cache_bin_array_descriptor_t *desc = NULL;
tcache_slow_t *tcache_slow = tcache_slow_get(tsdn_tsd(tsdn)); tcache_slow_t *tcache_slow = tcache_slow_get(tsdn_tsd(tsdn));
if (tcache_slow != NULL && tcache_slow->arena == arena) { if (tcache_slow == NULL || tcache_slow->arena != arena) {
return NULL;
}
assert(tcache_slow->tcache != NULL); assert(tcache_slow->tcache != NULL);
cache_bin_array_descriptor_init( cache_bin_array_descriptor_init(
&tcache_slow->cache_bin_array_descriptor, &tcache_slow->cache_bin_array_descriptor,
tcache_slow->tcache->bins); tcache_slow->tcache->bins);
desc = &tcache_slow->cache_bin_array_descriptor; return &tcache_slow->cache_bin_array_descriptor;
}
arena_cache_bin_array_postfork_child(arena, desc);
} }
static void static void