Add follow-up test for postfork multithread

Fix FreeBSD postfork child handler never being called: FreeBSD's libthr
calls _malloc_postfork in both parent and child (see freebsd-src
lib/libthr/thread/thr_fork.c), but jemalloc mapped it to the parent
handler only.  Detect the child via getpid() and route to
jemalloc_postfork_child, which resets nthreads and rebuilds the
descriptor queue.

Remove the child_survivor_bytes vs pre_survivor_bytes comparison: on
macOS where jemalloc registers as the default zone, internal allocations
during the postfork handler (pthread_mutex_init) can inflate the
surviving thread's tcache.

Add double-fork test to verify prefork pid is refreshed correctly when a
child process forks again.
This commit is contained in:
Slobodan Predolac
2026-05-14 11:38:41 -07:00
parent 300b58b49b
commit 00f53eb337
2 changed files with 300 additions and 1 deletions

View File

@@ -12,6 +12,19 @@
* malloc during fork().
*/
#ifdef JEMALLOC_MUTEX_INIT_CB
/*
* When JEMALLOC_MUTEX_INIT_CB is defined, pthread_atfork registration is
* skipped and the platform calls _malloc_prefork/_malloc_postfork directly.
* FreeBSD's libthr calls _malloc_postfork in both parent and child. Detect
* the child by pid change so we route to jemalloc_postfork_child, which resets
* per-arena state the parent handler does not touch (nthreads, descriptor
* queues). The check is harmless on any platform that only calls
* _malloc_postfork in the parent.
*/
static pid_t jemalloc_prefork_pid;
#endif
#ifndef JEMALLOC_MUTEX_INIT_CB
void
jemalloc_prefork(void)
@@ -31,6 +44,10 @@ _malloc_prefork(void)
#endif
assert(malloc_initialized());
#ifdef JEMALLOC_MUTEX_INIT_CB
jemalloc_prefork_pid = getpid();
#endif
tsd = tsd_fetch();
narenas = narenas_total_get();
@@ -105,6 +122,10 @@ _malloc_postfork(void)
if (!malloc_initialized()) {
return;
}
if (getpid() != jemalloc_prefork_pid) {
jemalloc_postfork_child();
return;
}
#endif
assert(malloc_initialized());