From 89b9aef8f7286e8078728e83e7a7ec64b1f4baff Mon Sep 17 00:00:00 2001 From: guangli-dai Date: Mon, 27 Jul 2026 17:41:42 -0700 Subject: [PATCH] Move process write part (atfork) to OS layer Migrates pthread_atfork(3) registration onto the existing os/process.h dispatcher. --- include/jemalloc/internal/os/posix/process.h | 27 +++++++++++++++++++ include/jemalloc/internal/os/process.h | 6 +++++ .../jemalloc/internal/os/windows/process.h | 10 +++++++ src/jemalloc_init.c | 19 ++++++++----- 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/include/jemalloc/internal/os/posix/process.h b/include/jemalloc/internal/os/posix/process.h index 63142aed..6f6b6f15 100644 --- a/include/jemalloc/internal/os/posix/process.h +++ b/include/jemalloc/internal/os/posix/process.h @@ -14,4 +14,31 @@ os_process_id(void) { return (int)getpid(); } +/* + * Shared by every POSIX platform: the four predicates below reproduce, in one + * place, exactly which platforms actually get pthread_atfork() registered. + * - JEMALLOC_HAVE_PTHREAD_ATFORK: the function exists. + * - !JEMALLOC_MUTEX_INIT_CB: on FreeBSD-libthr, _pthread_mutex_init_calloc_cb + * makes libthr's own _malloc_prefork/_malloc_postfork drive the fork + * dance instead. Registering here would be redundant. + * - !JEMALLOC_ZONE: on Darwin, malloc-zone fork callbacks subsume + * pthread_atfork. + * - !__native_client__: Native Client's sandbox doesn't support fork() at + * all, and pthread_atfork() risked being an unresolved symbol in some + * NaCl toolchains. Registering it is both pointless and unsafe there. + */ +JEMALLOC_ALWAYS_INLINE bool +os_process_register_atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void)) { +#if defined(JEMALLOC_HAVE_PTHREAD_ATFORK) && !defined(JEMALLOC_MUTEX_INIT_CB) \ + && !defined(JEMALLOC_ZONE) && !defined(__native_client__) + return pthread_atfork(prepare, parent, child) != 0; +#else + (void)prepare; + (void)parent; + (void)child; + return false; +#endif +} + #endif /* JEMALLOC_INTERNAL_OS_POSIX_PROCESS_H */ diff --git a/include/jemalloc/internal/os/process.h b/include/jemalloc/internal/os/process.h index a67e0041..cc824a91 100644 --- a/include/jemalloc/internal/os/process.h +++ b/include/jemalloc/internal/os/process.h @@ -11,6 +11,12 @@ /* Functions required for implementation in each backend. */ JEMALLOC_ALWAYS_INLINE int os_process_id(void); +/* + * Install fork handlers, returning true on failure. A no-op returning false + * where fork handler registration doesn't apply. + */ +JEMALLOC_ALWAYS_INLINE bool os_process_register_atfork( + void (*prepare)(void), void (*parent)(void), void (*child)(void)); #if defined(_WIN32) # include "jemalloc/internal/os/windows/process.h" diff --git a/include/jemalloc/internal/os/windows/process.h b/include/jemalloc/internal/os/windows/process.h index 2c1459ec..5cd1b707 100644 --- a/include/jemalloc/internal/os/windows/process.h +++ b/include/jemalloc/internal/os/windows/process.h @@ -12,4 +12,14 @@ os_process_id(void) { return (int)GetCurrentProcessId(); } +/* Windows has no fork(2)/pthread_atfork; always a no-op. */ +JEMALLOC_ALWAYS_INLINE bool +os_process_register_atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void)) { + (void)prepare; + (void)parent; + (void)child; + return false; +} + #endif /* JEMALLOC_INTERNAL_OS_WINDOWS_PROCESS_H */ diff --git a/src/jemalloc_init.c b/src/jemalloc_init.c index 8f2ff4bc..56be75ca 100644 --- a/src/jemalloc_init.c +++ b/src/jemalloc_init.c @@ -347,13 +347,18 @@ malloc_init_hard_recursible(void) { } } -#if (defined(JEMALLOC_HAVE_PTHREAD_ATFORK) && !defined(JEMALLOC_MUTEX_INIT_CB) \ - && !defined(JEMALLOC_ZONE) && !defined(_WIN32) \ - && !defined(__native_client__)) - /* LinuxThreads' pthread_atfork() allocates. */ - if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent, - jemalloc_postfork_child) - != 0) { +#ifndef JEMALLOC_MUTEX_INIT_CB + /* + * jemalloc_fork.c names these jemalloc_prefork()/jemalloc_postfork_ + * parent() only when !JEMALLOC_MUTEX_INIT_CB; under it they're exported + * as _malloc_prefork()/_malloc_postfork() instead (FreeBSD-libthr calls + * those directly, bypassing pthread_atfork() registration entirely -- + * see os_process_register_atfork()'s own !JEMALLOC_MUTEX_INIT_CB check). + * Referencing the former names here unconditionally would be a link + * error under JEMALLOC_MUTEX_INIT_CB, since they wouldn't exist. + */ + if (os_process_register_atfork(jemalloc_prefork, + jemalloc_postfork_parent, jemalloc_postfork_child)) { malloc_write(": Error in pthread_atfork()\n"); if (opt_abort) { abort();