Home | History | Annotate | Line # | Download | only in unit
      1 #include "test/jemalloc_test.h"
      2 
      3 #ifndef _WIN32
      4 #include <sys/wait.h>
      5 #endif
      6 
      7 #ifndef _WIN32
      8 static void
      9 wait_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 
     31 TEST_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 }
     73 TEST_END
     74 
     75 #ifndef _WIN32
     76 static void *
     77 do_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
     97 static void
     98 do_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 
    106 TEST_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 }
    134 TEST_END
    135 
    136 int
    137 main(void) {
    138 	return test_no_reentrancy(
    139 	    test_fork,
    140 	    test_fork_multithreaded);
    141 }
    142