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