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