• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "test/jemalloc_test.h"
2 
3 #ifndef _WIN32
4 #include <sys/wait.h>
5 #endif
6 
7 #ifndef _WIN32
8 static void
wait_for_child_exit(int pid)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 
TEST_BEGIN(test_fork)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 *
do_fork_thd(void * arg)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
do_test_fork_multithreaded()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 
TEST_BEGIN(test_fork_multithreaded)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
main(void)137 main(void) {
138 	return test_no_reentrancy(
139 	    test_fork,
140 	    test_fork_multithreaded);
141 }
142