#include "test/jemalloc_test.h" #include "jemalloc/internal/jemalloc_init.h" TEST_BEGIN(test_malloc_init_hard_idempotent) { expect_false(malloc_init_hard(), "malloc_init_hard should return false when already initialized"); expect_true(malloc_initialized(), "malloc_initialized should still be true after re-calling " "malloc_init_hard"); } TEST_END #ifdef JEMALLOC_THREADED_INIT static atomic_b_t initializer_worker_done; static atomic_b_t initializer_worker_result; static void * is_initializer_worker(void *unused) { atomic_store_b(&initializer_worker_result, malloc_is_initializer(), ATOMIC_RELEASE); atomic_store_b(&initializer_worker_done, true, ATOMIC_RELEASE); return NULL; } #endif TEST_BEGIN(test_malloc_is_initializer_false_in_worker) { #ifndef JEMALLOC_THREADED_INIT /* * Without JEMALLOC_THREADED_INIT (e.g. macOS), malloc_initializer * is a process-wide bool and malloc_is_initializer() returns true * for every thread after init. The per-thread distinction this * test exercises only exists in threaded-init builds. */ test_skip_if(true); #else test_skip_if(!malloc_is_initializer()); atomic_store_b(&initializer_worker_done, false, ATOMIC_RELEASE); atomic_store_b(&initializer_worker_result, false, ATOMIC_RELEASE); thd_t thd; thd_create(&thd, is_initializer_worker, NULL); thd_join(thd, NULL); expect_true( atomic_load_b(&initializer_worker_done, ATOMIC_ACQUIRE), "Worker should have completed"); expect_false( atomic_load_b(&initializer_worker_result, ATOMIC_ACQUIRE), "malloc_is_initializer should be false in a non-init thread"); #endif } TEST_END int main(void) { return test(test_malloc_init_hard_idempotent, test_malloc_is_initializer_false_in_worker); }