Blame jemalloc/test/unit/fork.c

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