123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- #include "test/jemalloc_test.h"
- #ifndef _WIN32
- #include <sys/wait.h>
- #endif
- #ifndef _WIN32
- static void
- wait_for_child_exit(int pid) {
- int status;
- while (true) {
- if (waitpid(pid, &status, 0) == -1) {
- test_fail("Unexpected waitpid() failure.");
- }
- if (WIFSIGNALED(status)) {
- test_fail("Unexpected child termination due to "
- "signal %d", WTERMSIG(status));
- break;
- }
- if (WIFEXITED(status)) {
- if (WEXITSTATUS(status) != 0) {
- test_fail("Unexpected child exit value %d",
- WEXITSTATUS(status));
- }
- break;
- }
- }
- }
- #endif
- TEST_BEGIN(test_fork) {
- #ifndef _WIN32
- void *p;
- pid_t pid;
- /* Set up a manually managed arena for test. */
- unsigned arena_ind;
- size_t sz = sizeof(unsigned);
- assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0),
- 0, "Unexpected mallctl() failure");
- /* Migrate to the new arena. */
- unsigned old_arena_ind;
- sz = sizeof(old_arena_ind);
- assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz,
- (void *)&arena_ind, sizeof(arena_ind)), 0,
- "Unexpected mallctl() failure");
- p = malloc(1);
- assert_ptr_not_null(p, "Unexpected malloc() failure");
- pid = fork();
- free(p);
- p = malloc(64);
- assert_ptr_not_null(p, "Unexpected malloc() failure");
- free(p);
- if (pid == -1) {
- /* Error. */
- test_fail("Unexpected fork() failure");
- } else if (pid == 0) {
- /* Child. */
- _exit(0);
- } else {
- wait_for_child_exit(pid);
- }
- #else
- test_skip("fork(2) is irrelevant to Windows");
- #endif
- }
- TEST_END
- #ifndef _WIN32
- static void *
- do_fork_thd(void *arg) {
- malloc(1);
- int pid = fork();
- if (pid == -1) {
- /* Error. */
- test_fail("Unexpected fork() failure");
- } else if (pid == 0) {
- /* Child. */
- char *args[] = {"true", NULL};
- execvp(args[0], args);
- test_fail("Exec failed");
- } else {
- /* Parent */
- wait_for_child_exit(pid);
- }
- return NULL;
- }
- #endif
- #ifndef _WIN32
- static void
- do_test_fork_multithreaded() {
- thd_t child;
- thd_create(&child, do_fork_thd, NULL);
- do_fork_thd(NULL);
- thd_join(child, NULL);
- }
- #endif
- TEST_BEGIN(test_fork_multithreaded) {
- #ifndef _WIN32
- /*
- * We've seen bugs involving hanging on arenas_lock (though the same
- * class of bugs can happen on any mutex). The bugs are intermittent
- * though, so we want to run the test multiple times. Since we hold the
- * arenas lock only early in the process lifetime, we can't just run
- * this test in a loop (since, after all the arenas are initialized, we
- * won't acquire arenas_lock any further). We therefore repeat the test
- * with multiple processes.
- */
- for (int i = 0; i < 100; i++) {
- int pid = fork();
- if (pid == -1) {
- /* Error. */
- test_fail("Unexpected fork() failure,");
- } else if (pid == 0) {
- /* Child. */
- do_test_fork_multithreaded();
- _exit(0);
- } else {
- wait_for_child_exit(pid);
- }
- }
- #else
- test_skip("fork(2) is irrelevant to Windows");
- #endif
- }
- TEST_END
- int
- main(void) {
- return test_no_reentrancy(
- test_fork,
- test_fork_multithreaded);
- }
|