1*8e33eff8Schristos #include "test/jemalloc_test.h" 2*8e33eff8Schristos 3*8e33eff8Schristos #ifndef _WIN32 4*8e33eff8Schristos #include <sys/wait.h> 5*8e33eff8Schristos #endif 6*8e33eff8Schristos 7*8e33eff8Schristos #ifndef _WIN32 8*8e33eff8Schristos static void 9*8e33eff8Schristos wait_for_child_exit(int pid) { 10*8e33eff8Schristos int status; 11*8e33eff8Schristos while (true) { 12*8e33eff8Schristos if (waitpid(pid, &status, 0) == -1) { 13*8e33eff8Schristos test_fail("Unexpected waitpid() failure."); 14*8e33eff8Schristos } 15*8e33eff8Schristos if (WIFSIGNALED(status)) { 16*8e33eff8Schristos test_fail("Unexpected child termination due to " 17*8e33eff8Schristos "signal %d", WTERMSIG(status)); 18*8e33eff8Schristos break; 19*8e33eff8Schristos } 20*8e33eff8Schristos if (WIFEXITED(status)) { 21*8e33eff8Schristos if (WEXITSTATUS(status) != 0) { 22*8e33eff8Schristos test_fail("Unexpected child exit value %d", 23*8e33eff8Schristos WEXITSTATUS(status)); 24*8e33eff8Schristos } 25*8e33eff8Schristos break; 26*8e33eff8Schristos } 27*8e33eff8Schristos } 28*8e33eff8Schristos } 29*8e33eff8Schristos #endif 30*8e33eff8Schristos 31*8e33eff8Schristos TEST_BEGIN(test_fork) { 32*8e33eff8Schristos #ifndef _WIN32 33*8e33eff8Schristos void *p; 34*8e33eff8Schristos pid_t pid; 35*8e33eff8Schristos 36*8e33eff8Schristos /* Set up a manually managed arena for test. */ 37*8e33eff8Schristos unsigned arena_ind; 38*8e33eff8Schristos size_t sz = sizeof(unsigned); 39*8e33eff8Schristos assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), 40*8e33eff8Schristos 0, "Unexpected mallctl() failure"); 41*8e33eff8Schristos 42*8e33eff8Schristos /* Migrate to the new arena. */ 43*8e33eff8Schristos unsigned old_arena_ind; 44*8e33eff8Schristos sz = sizeof(old_arena_ind); 45*8e33eff8Schristos assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz, 46*8e33eff8Schristos (void *)&arena_ind, sizeof(arena_ind)), 0, 47*8e33eff8Schristos "Unexpected mallctl() failure"); 48*8e33eff8Schristos 49*8e33eff8Schristos p = malloc(1); 50*8e33eff8Schristos assert_ptr_not_null(p, "Unexpected malloc() failure"); 51*8e33eff8Schristos 52*8e33eff8Schristos pid = fork(); 53*8e33eff8Schristos 54*8e33eff8Schristos free(p); 55*8e33eff8Schristos 56*8e33eff8Schristos p = malloc(64); 57*8e33eff8Schristos assert_ptr_not_null(p, "Unexpected malloc() failure"); 58*8e33eff8Schristos free(p); 59*8e33eff8Schristos 60*8e33eff8Schristos if (pid == -1) { 61*8e33eff8Schristos /* Error. */ 62*8e33eff8Schristos test_fail("Unexpected fork() failure"); 63*8e33eff8Schristos } else if (pid == 0) { 64*8e33eff8Schristos /* Child. */ 65*8e33eff8Schristos _exit(0); 66*8e33eff8Schristos } else { 67*8e33eff8Schristos wait_for_child_exit(pid); 68*8e33eff8Schristos } 69*8e33eff8Schristos #else 70*8e33eff8Schristos test_skip("fork(2) is irrelevant to Windows"); 71*8e33eff8Schristos #endif 72*8e33eff8Schristos } 73*8e33eff8Schristos TEST_END 74*8e33eff8Schristos 75*8e33eff8Schristos #ifndef _WIN32 76*8e33eff8Schristos static void * 77*8e33eff8Schristos do_fork_thd(void *arg) { 78*8e33eff8Schristos malloc(1); 79*8e33eff8Schristos int pid = fork(); 80*8e33eff8Schristos if (pid == -1) { 81*8e33eff8Schristos /* Error. */ 82*8e33eff8Schristos test_fail("Unexpected fork() failure"); 83*8e33eff8Schristos } else if (pid == 0) { 84*8e33eff8Schristos /* Child. */ 85*8e33eff8Schristos char *args[] = {"true", NULL}; 86*8e33eff8Schristos execvp(args[0], args); 87*8e33eff8Schristos test_fail("Exec failed"); 88*8e33eff8Schristos } else { 89*8e33eff8Schristos /* Parent */ 90*8e33eff8Schristos wait_for_child_exit(pid); 91*8e33eff8Schristos } 92*8e33eff8Schristos return NULL; 93*8e33eff8Schristos } 94*8e33eff8Schristos #endif 95*8e33eff8Schristos 96*8e33eff8Schristos #ifndef _WIN32 97*8e33eff8Schristos static void 98*8e33eff8Schristos do_test_fork_multithreaded() { 99*8e33eff8Schristos thd_t child; 100*8e33eff8Schristos thd_create(&child, do_fork_thd, NULL); 101*8e33eff8Schristos do_fork_thd(NULL); 102*8e33eff8Schristos thd_join(child, NULL); 103*8e33eff8Schristos } 104*8e33eff8Schristos #endif 105*8e33eff8Schristos 106*8e33eff8Schristos TEST_BEGIN(test_fork_multithreaded) { 107*8e33eff8Schristos #ifndef _WIN32 108*8e33eff8Schristos /* 109*8e33eff8Schristos * We've seen bugs involving hanging on arenas_lock (though the same 110*8e33eff8Schristos * class of bugs can happen on any mutex). The bugs are intermittent 111*8e33eff8Schristos * though, so we want to run the test multiple times. Since we hold the 112*8e33eff8Schristos * arenas lock only early in the process lifetime, we can't just run 113*8e33eff8Schristos * this test in a loop (since, after all the arenas are initialized, we 114*8e33eff8Schristos * won't acquire arenas_lock any further). We therefore repeat the test 115*8e33eff8Schristos * with multiple processes. 116*8e33eff8Schristos */ 117*8e33eff8Schristos for (int i = 0; i < 100; i++) { 118*8e33eff8Schristos int pid = fork(); 119*8e33eff8Schristos if (pid == -1) { 120*8e33eff8Schristos /* Error. */ 121*8e33eff8Schristos test_fail("Unexpected fork() failure,"); 122*8e33eff8Schristos } else if (pid == 0) { 123*8e33eff8Schristos /* Child. */ 124*8e33eff8Schristos do_test_fork_multithreaded(); 125*8e33eff8Schristos _exit(0); 126*8e33eff8Schristos } else { 127*8e33eff8Schristos wait_for_child_exit(pid); 128*8e33eff8Schristos } 129*8e33eff8Schristos } 130*8e33eff8Schristos #else 131*8e33eff8Schristos test_skip("fork(2) is irrelevant to Windows"); 132*8e33eff8Schristos #endif 133*8e33eff8Schristos } 134*8e33eff8Schristos TEST_END 135*8e33eff8Schristos 136*8e33eff8Schristos int 137*8e33eff8Schristos main(void) { 138*8e33eff8Schristos return test_no_reentrancy( 139*8e33eff8Schristos test_fork, 140*8e33eff8Schristos test_fork_multithreaded); 141*8e33eff8Schristos } 142