[igt-dev] [PATCH i-g-t 1/9] lib/tests: Extract fork helpers

Arkadiusz Hiler arkadiusz.hiler at intel.com
Wed Feb 12 13:21:15 UTC 2020


Because of excessive 'copy and paste' we ended up with multiple copies
of almost the same fork helper. This patch extracts the do_fork helper
out and switches all the tests over to it.

Additionally, preemptively I have extracted the more fancy fork helper
that captures stderr/out + related functions out of igt_describe tests.

Signed-off-by: Arkadiusz Hiler <arkadiusz.hiler at intel.com>
---
 lib/tests/igt_assert.c               |  35 +++----
 lib/tests/igt_conflicting_args.c     |  25 ++---
 lib/tests/igt_describe.c             | 135 ++++++---------------------
 lib/tests/igt_dynamic_subtests.c     |  18 ----
 lib/tests/igt_fork.c                 |  71 ++++++--------
 lib/tests/igt_invalid_subtest_name.c |  18 ----
 lib/tests/igt_no_exit.c              |  18 ----
 lib/tests/igt_segfault.c             |  59 +++++-------
 lib/tests/igt_simulation.c           | 101 +++++++++-----------
 lib/tests/igt_tests_common.h         |  91 ++++++++++++++++++
 10 files changed, 232 insertions(+), 339 deletions(-)

diff --git a/lib/tests/igt_assert.c b/lib/tests/igt_assert.c
index 1caf5d88..c94ac698 100644
--- a/lib/tests/igt_assert.c
+++ b/lib/tests/igt_assert.c
@@ -38,8 +38,6 @@
 
 #include "igt_tests_common.h"
 
-char test[] = "test";
-char *argv_run[] = { test };
 void (*test_to_run)(void) = NULL;
 
 /*
@@ -55,26 +53,17 @@ void (*test_to_run)(void) = NULL;
 	exec_total++; \
 }
 
-static int do_fork(void)
+static void fake_test(void)
 {
-	int pid, status;
-	int argc;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		argc = ARRAY_SIZE(argv_run);
-		igt_simple_init(argc, argv_run);
-		test_to_run();
-		igt_exit();
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
-
-		return status;
-	}
+	char test[] = "test";
+	char *argv_run[] = { test };
+	int argc = ARRAY_SIZE(argv_run);
+
+	igt_simple_init(argc, argv_run);
+
+	test_to_run();
+
+	igt_exit();
 }
 
 static void test_cmpint_negative(void)
@@ -150,7 +139,7 @@ igt_main
 	 * we inherit the state from the parent, so ...
 	 */
 	test_to_run = test_cmpint_negative;
-	ret = do_fork();
+	ret = do_fork(fake_test);
 	igt_subtest("igt_cmpint_negative")
 		internal_assert_wexited(ret, IGT_EXIT_FAILURE);
 
@@ -158,7 +147,7 @@ igt_main
 		test_fd();
 
 	test_to_run = test_fd_negative;
-	ret = do_fork();
+	ret = do_fork(fake_test);
 	igt_subtest("igt_assert_fd_negative")
 		internal_assert_wexited(ret, IGT_EXIT_FAILURE);
 }
diff --git a/lib/tests/igt_conflicting_args.c b/lib/tests/igt_conflicting_args.c
index f600abd4..b644fd4b 100644
--- a/lib/tests/igt_conflicting_args.c
+++ b/lib/tests/igt_conflicting_args.c
@@ -43,25 +43,12 @@ static int opt_handler(int option, int option_index, void *input)
 	return 0;
 }
 
-static int do_fork(void)
+static void fake_test(void)
 {
 	char test_name[] = "test";
-
 	char *argv[] = { test_name };
 	int argc = ARRAY_SIZE(argv);
 
-	pid_t pid = fork();
-	internal_assert(pid != -1);
-
-	if (pid) {
-		int status;
-		while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
-			;
-
-		return status;
-	}
-
-
 	igt_subtest_init_parse_opts(&argc, argv, short_options, long_options,
 				    "", opt_handler, NULL);
 	igt_subtest("dummy") {}
@@ -73,27 +60,27 @@ int main(int argc, char **argv)
 	/* no conflict */
 	long_options[0] = (struct option) { "iterations", required_argument, NULL, 'i'};
 	short_options = "";
-	internal_assert_wexited(do_fork(), 0);
+	internal_assert_wexited(do_fork(fake_test), 0);
 
 	/* conflict on short option */
 	long_options[0] = (struct option) { "iterations", required_argument, NULL, 'i'};
 	short_options = "h";
-	internal_assert_wsignaled(do_fork(), SIGABRT);
+	internal_assert_wsignaled(do_fork(fake_test), SIGABRT);
 
 	/* conflict on long option name */
 	long_options[0] = (struct option) { "help", required_argument, NULL, 'i'};
 	short_options = "";
-	internal_assert_wsignaled(do_fork(), SIGABRT);
+	internal_assert_wsignaled(do_fork(fake_test), SIGABRT);
 
 	/* conflict on long option 'val' representation vs short option */
 	long_options[0] = (struct option) { "iterations", required_argument, NULL, 'h'};
 	short_options = "";
-	internal_assert_wsignaled(do_fork(), SIGABRT);
+	internal_assert_wsignaled(do_fork(fake_test), SIGABRT);
 
 	/* conflict on long option 'val' representations */
 	long_options[0] = (struct option) { "iterations", required_argument, NULL, 500};
 	short_options = "";
-	internal_assert_wsignaled(do_fork(), SIGABRT);
+	internal_assert_wsignaled(do_fork(fake_test), SIGABRT);
 
 	return 0;
 }
diff --git a/lib/tests/igt_describe.c b/lib/tests/igt_describe.c
index 6f3a4319..7b4fa9af 100644
--- a/lib/tests/igt_describe.c
+++ b/lib/tests/igt_describe.c
@@ -28,9 +28,15 @@
 #include "drmtest.h"
 #include "igt_tests_common.h"
 
+char prog[] = "igt_describe";
+char fake_arg[100];
+char *fake_argv[] = {prog, fake_arg};
+int fake_argc = ARRAY_SIZE(fake_argv);
+
 IGT_TEST_DESCRIPTION("the top level description");
-static void fake_main(int argc, char **argv) {
-	igt_subtest_init(argc, argv);
+static void fake_main(void)
+{
+	igt_subtest_init(fake_argc, fake_argv);
 
 	igt_describe("Basic A");
 	igt_subtest("A")
@@ -101,33 +107,33 @@ static void fake_main(int argc, char **argv) {
 static const char DESCRIBE_ALL_OUTPUT[] = \
 	"the top level description\n"
 	"\n"
-	"SUB A ../lib/tests/igt_describe.c:36:\n"
+	"SUB A ../lib/tests/igt_describe.c:42:\n"
 	"  Basic A\n"
 	"\n"
-	"SUB B ../lib/tests/igt_describe.c:45:\n"
+	"SUB B ../lib/tests/igt_describe.c:51:\n"
 	"  Group with B, C & D\n"
 	"\n"
 	"  Basic B\n"
 	"\n"
-	"SUB C ../lib/tests/igt_describe.c:54:\n"
+	"SUB C ../lib/tests/igt_describe.c:60:\n"
 	"  Group with B, C & D\n"
 	"\n"
 	"  Group with C & D\n"
 	"\n"
 	"  Basic C\n"
 	"\n"
-	"SUB D ../lib/tests/igt_describe.c:58:\n"
+	"SUB D ../lib/tests/igt_describe.c:64:\n"
 	"  Group with B, C & D\n"
 	"\n"
 	"  Group with C & D\n"
 	"\n"
-	"SUB E ../lib/tests/igt_describe.c:66:\n"
+	"SUB E ../lib/tests/igt_describe.c:72:\n"
 	"  NO DOCUMENTATION!\n"
 	"\n"
-	"SUB F ../lib/tests/igt_describe.c:71:\n"
+	"SUB F ../lib/tests/igt_describe.c:77:\n"
 	"  NO DOCUMENTATION!\n"
 	"\n"
-	"SUB G ../lib/tests/igt_describe.c:80:\n"
+	"SUB G ../lib/tests/igt_describe.c:86:\n"
 	"  this description should be so long that it wraps itself nicely in the terminal this\n"
 	"  description should be so long that it wraps itself nicely in the terminal this description\n"
 	"  should be so long that it wraps itself nicely in the terminal this description should be so\n"
@@ -135,17 +141,17 @@ static const char DESCRIBE_ALL_OUTPUT[] = \
 	"  wraps itself nicely in the terminal this description should be so long that it wraps itself\n"
 	"  nicely in the terminal\n"
 	"\n"
-	"SUB F ../lib/tests/igt_describe.c:87:\n"
+	"SUB F ../lib/tests/igt_describe.c:93:\n"
 	"  verylongwordthatshoudlbeprintedeventhoughitspastthewrppinglimitverylongwordthatshoudlbeprintedeventhoughitspastthewrappinglimit\n"
 	"  verylongwordthatshoudlbeprintedeventhoughitspastthewrappinglimitverylongwordthatshoudlbeprintedeventhoughitspastthewrappinglimit\n"
 	"\n"
-	"SUB G ../lib/tests/igt_describe.c:91:\n"
+	"SUB G ../lib/tests/igt_describe.c:97:\n"
 	"  Subtest with dynamic subsubtests\n\n";
 
 static const char JUST_C_OUTPUT[] = \
 	"the top level description\n"
 	"\n"
-	"SUB C ../lib/tests/igt_describe.c:54:\n"
+	"SUB C ../lib/tests/igt_describe.c:60:\n"
 	"  Group with B, C & D\n"
 	"\n"
 	"  Group with C & D\n"
@@ -153,95 +159,22 @@ static const char JUST_C_OUTPUT[] = \
 	"  Basic C\n"
 	"\n";
 
-static void assert_pipe_empty(int fd)
-{
-	char buf[5];
-	internal_assert(0 == read(fd, buf, sizeof(buf)));
-}
-
-static void read_whole_pipe(int fd, char *buf, size_t buflen)
-{
-	ssize_t readlen;
-	off_t offset;
-
-	offset = 0;
-	while ((readlen = read(fd, buf+offset, buflen-offset))) {
-		if (readlen == -1) {
-			if (errno == EINTR) {
-				continue;
-			} else {
-				printf("read failed with %s\n", strerror(errno));
-				exit(1);
-			}
-		}
-		internal_assert(readlen != -1);
-		offset += readlen;
-	}
-}
-
-static pid_t do_fork(int argc, char **argv, int *out, int *err)
-{
-	int outfd[2], errfd[2];
-	pid_t pid;
-
-	internal_assert(pipe(outfd) != -1);
-	internal_assert(pipe(errfd) != -1);
-
-	pid = fork();
-	internal_assert(pid != -1);
-
-	if (pid == 0) {
-		while (dup2(outfd[1], STDOUT_FILENO) == -1 && errno == EINTR) {}
-		while (dup2(errfd[1], STDERR_FILENO) == -1 && errno == EINTR) {}
-
-		close(outfd[0]);
-		close(outfd[1]);
-		close(errfd[0]);
-		close(errfd[1]);
-
-		fake_main(argc, argv);
-
-		exit(-1);
-	} else {
-		/* close the writing ends */
-		close(outfd[1]);
-		close(errfd[1]);
-
-		*out = outfd[0];
-		*err = errfd[0];
-
-		return pid;
-	}
-}
-
-static int _wait(pid_t pid, int *status) {
-	int ret;
-
-	do {
-		ret = waitpid(pid, status, 0);
-	} while (ret == -1 && errno == EINTR);
-
-	return ret;
-}
-
 int main(int argc, char **argv)
 {
-	char prog[] = "igt_describe";
 	int status;
 	int outfd, errfd;
+	pid_t pid;
 
 	/* describe all subtest */ {
 		static char out[4096];
-		char arg[] = "--describe";
-		char *fake_argv[] = {prog, arg};
-		int fake_argc = ARRAY_SIZE(fake_argv);
+		strncpy(fake_arg, "--describe", sizeof(fake_arg));
 
-		pid_t pid = do_fork(fake_argc, fake_argv, &outfd, &errfd);
+		pid = do_fork_bg_with_pipes(fake_main, &outfd, &errfd);
 
 		read_whole_pipe(outfd, out, sizeof(out));
 		assert_pipe_empty(errfd);
 
-		internal_assert(_wait(pid, &status) != -1);
+		internal_assert(safe_wait(pid, &status) != -1);
 		internal_assert(WIFEXITED(status));
 		internal_assert(WEXITSTATUS(status) == IGT_EXIT_SUCCESS);
 		internal_assert(0 == strcmp(DESCRIBE_ALL_OUTPUT, out));
@@ -252,16 +185,14 @@ int main(int argc, char **argv)
 
 	/* describe C using a pattern */ {
 		static char out[4096];
-		char arg[] = "--describe=C";
-		char *fake_argv[] = {prog, arg};
-		int fake_argc = ARRAY_SIZE(fake_argv);
+		strncpy(fake_arg, "--describe=C", sizeof(fake_arg));
 
-		pid_t pid = do_fork(fake_argc, fake_argv, &outfd, &errfd);
+		pid = do_fork_bg_with_pipes(fake_main, &outfd, &errfd);
 
 		read_whole_pipe(outfd, out, sizeof(out));
 		assert_pipe_empty(errfd);
 
-		internal_assert(_wait(pid, &status) != -1);
+		internal_assert(safe_wait(pid, &status) != -1);
 		internal_assert(WIFEXITED(status));
 		internal_assert(WEXITSTATUS(status) == IGT_EXIT_SUCCESS);
 		internal_assert(0 == strcmp(JUST_C_OUTPUT, out));
@@ -272,15 +203,13 @@ int main(int argc, char **argv)
 
 	/* fail describing with a bad pattern */ {
 		static char err[4096];
-		char arg[] = "--describe=Z";
-		char *fake_argv[] = {prog, arg};
-		int fake_argc = ARRAY_SIZE(fake_argv);
+		strncpy(fake_arg, "--describe=Z", sizeof(fake_arg));
 
-		pid_t pid = do_fork(fake_argc, fake_argv, &outfd, &errfd);
+		pid = do_fork_bg_with_pipes(fake_main, &outfd, &errfd);
 
 		read_whole_pipe(errfd, err, sizeof(err));
 
-		internal_assert(_wait(pid, &status) != -1);
+		internal_assert(safe_wait(pid, &status) != -1);
 		internal_assert(WIFEXITED(status));
 		internal_assert(WEXITSTATUS(status) == IGT_EXIT_INVALID);
 		internal_assert(strstr(err, "Unknown subtest: Z"));
@@ -291,15 +220,13 @@ int main(int argc, char **argv)
 
 	/* trying to igt_describe a dynamic subsubtest should assert */ {
 		static char err[4096];
-		char arg[] = "--run-subtest=G";
-		char *fake_argv[] = {prog, arg};
-		int fake_argc = ARRAY_SIZE(fake_argv);
+		strncpy(fake_arg, "--run-subtest=G", sizeof(fake_arg));
 
-		pid_t pid = do_fork(fake_argc, fake_argv, &outfd, &errfd);
+		pid = do_fork_bg_with_pipes(fake_main, &outfd, &errfd);
 
 		read_whole_pipe(errfd, err, sizeof(err));
 
-		internal_assert(_wait(pid, &status) != -1);
+		internal_assert(safe_wait(pid, &status) != -1);
 		internal_assert_wsignaled(status, SIGABRT);
 
 		close(outfd);
diff --git a/lib/tests/igt_dynamic_subtests.c b/lib/tests/igt_dynamic_subtests.c
index 606104c5..bd1e1675 100644
--- a/lib/tests/igt_dynamic_subtests.c
+++ b/lib/tests/igt_dynamic_subtests.c
@@ -29,24 +29,6 @@
 
 #include "igt_tests_common.h"
 
-static int do_fork(void (*test_to_run)(void))
-{
-	int pid, status;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		test_to_run();
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
-
-		return status;
-	}
-}
-
 static void dynamic_subtest_in_normal_subtest(void)
 {
 	char prog[] = "igt_no_exit";
diff --git a/lib/tests/igt_fork.c b/lib/tests/igt_fork.c
index e30584fd..4fd0e0c8 100644
--- a/lib/tests/igt_fork.c
+++ b/lib/tests/igt_fork.c
@@ -35,37 +35,52 @@
 #include "igt_tests_common.h"
 
 char test[] = "test";
-char *argv_run[] = { test };
+char *fake_argv[] = { test };
+int fake_argc = ARRAY_SIZE(fake_argv);
 
 static void igt_fork_vs_skip(void)
 {
+	igt_simple_init(fake_argc, fake_argv);
+
 	igt_fork(i, 1) {
 		igt_skip("skipping");
 	}
 
 	igt_waitchildren();
+
+	igt_exit();
 }
 
 static void igt_fork_vs_assert(void)
 {
+	igt_simple_init(fake_argc, fake_argv);
+
 	igt_fork(i, 1) {
 		igt_assert(0);
 	}
 
 	igt_waitchildren();
+
+	igt_exit();
 }
 
 static void igt_fork_leak(void)
 {
+	igt_simple_init(fake_argc, fake_argv);
+
 	igt_fork(i, 1) {
 		sleep(10);
 	}
+
+	igt_exit();
 }
 
 static void plain_fork_leak(void)
 {
 	int pid;
 
+	igt_simple_init(fake_argc, fake_argv);
+
 	switch (pid = fork()) {
 	case -1:
 		internal_assert(0);
@@ -74,59 +89,21 @@ static void plain_fork_leak(void)
 	default:
 		exit(0);
 	}
+
+	igt_exit();
 }
 
 static void igt_fork_timeout_leak(void)
 {
+	igt_simple_init(fake_argc, fake_argv);
+
 	igt_fork(i, 1) {
 		sleep(10);
 	}
 
 	igt_waitchildren_timeout(1, "library test");
-}
-
-static int do_fork(void (*test_to_run)(void))
-{
-	int pid, status;
-	int argc;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		argc = ARRAY_SIZE(argv_run);
-		igt_simple_init(argc, argv_run);
-		test_to_run();
-		igt_exit();
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
-
-		return status;
-	}
-}
-
-static int do_subtest(void (*test_to_run)(void))
-{
-	int pid, status;
-	int argc;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		argc = ARRAY_SIZE(argv_run);
-		igt_subtest_init(argc, argv_run);
-		test_to_run();
-		igt_exit();
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
 
-		return status;
-	}
+	igt_exit();
 }
 
 static void subtest_leak(void)
@@ -135,6 +112,8 @@ static void subtest_leak(void)
 		mmap(0, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
 	const int num_children = 4096 / sizeof(*children);
 
+	igt_subtest_init(fake_argc, fake_argv);
+
 	igt_subtest("fork-leak") {
 		igt_fork(child, num_children)
 			children[child] = getpid();
@@ -148,6 +127,8 @@ static void subtest_leak(void)
 		assert(kill(children[i], 0) == -1 && errno == ESRCH);
 
 	munmap(children, 4096);
+
+	igt_exit();
 }
 
 int main(int argc, char **argv)
@@ -174,6 +155,6 @@ int main(int argc, char **argv)
 	ret = do_fork(plain_fork_leak);
 	internal_assert_wsignaled(ret, SIGABRT);
 
-	ret = do_subtest(subtest_leak);
+	ret = do_fork(subtest_leak);
 	internal_assert_wexited(ret, IGT_EXIT_FAILURE); /* not asserted! */
 }
diff --git a/lib/tests/igt_invalid_subtest_name.c b/lib/tests/igt_invalid_subtest_name.c
index 92e767ab..32c4bcbc 100644
--- a/lib/tests/igt_invalid_subtest_name.c
+++ b/lib/tests/igt_invalid_subtest_name.c
@@ -60,24 +60,6 @@ static void nonexisting_subtest(void)
 	igt_exit();
 }
 
-static int do_fork(void (*test_to_run)(void))
-{
-	int pid, status;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		test_to_run();
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
-
-		return status;
-	}
-}
-
 int main(int argc, char **argv)
 {
 	int ret;
diff --git a/lib/tests/igt_no_exit.c b/lib/tests/igt_no_exit.c
index 82f00b52..d303eba7 100644
--- a/lib/tests/igt_no_exit.c
+++ b/lib/tests/igt_no_exit.c
@@ -56,24 +56,6 @@ static void no_exit(void)
 		;
 }
 
-static int do_fork(void (*test_to_run)(void))
-{
-	int pid, status;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		test_to_run();
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
-
-		return status;
-	}
-}
-
 int main(int argc, char **argv)
 {
 	int ret;
diff --git a/lib/tests/igt_segfault.c b/lib/tests/igt_segfault.c
index 0d872f67..38c040a6 100644
--- a/lib/tests/igt_segfault.c
+++ b/lib/tests/igt_segfault.c
@@ -48,51 +48,38 @@
 bool simple;
 bool runa;
 bool runc;
-char test[] = "test";
-char *argv_run[] = { test };
 
 static void crashme(void)
 {
 	raise(SIGSEGV);
 }
 
-static int do_fork(void)
+static void fake_test(void)
 {
-	int pid, status;
-	int argc;
-
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		argc = ARRAY_SIZE(argv_run);
-		if (simple) {
-			igt_simple_init(argc, argv_run);
-			crashme();
+	char prog[] = "test";
+	char *fake_argv[] = { prog };
+	int fake_argc = ARRAY_SIZE(fake_argv);
 
-			igt_exit();
-		} else {
-			igt_subtest_init(argc, argv_run);
 
-			if(runa)
-				igt_subtest("A")
-					;
+	if (simple) {
+		igt_simple_init(fake_argc, fake_argv);
+		crashme();
 
-			igt_subtest("B")
-				crashme();
+		igt_exit();
+	} else {
+		igt_subtest_init(fake_argc, fake_argv);
+		if(runa)
+			igt_subtest("A")
+				;
 
-			if(runc)
-				igt_subtest("C")
-					;
+		igt_subtest("B")
+			crashme();
 
-			igt_exit();
-		}
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
+		if(runc)
+			igt_subtest("C")
+				;
 
-		return status;
+		igt_exit();
 	}
 }
 
@@ -104,20 +91,20 @@ int main(int argc, char **argv)
 	runc=false;
 	igt_info("Simple test.\n");
 	fflush(stdout);
-	internal_assert_wsignaled(do_fork(), SIGSEGV);
+	internal_assert_wsignaled(do_fork(fake_test), SIGSEGV);
 
 	/* Test crash in a single subtest is reported */
 	simple = false;
 	igt_info("Single subtest.\n");
 	fflush(stdout);
-	internal_assert_wexited(do_fork(), SIGSEGV + 128);
+	internal_assert_wexited(do_fork(fake_test), SIGSEGV + 128);
 
 	/* Test crash in a subtest following a pass is reported */
 	simple = false;
 	runa=true;
 	igt_info("Passing then crashing subtest.\n");
 	fflush(stdout);
-	internal_assert_wexited(do_fork(), SIGSEGV + 128);
+	internal_assert_wexited(do_fork(fake_test), SIGSEGV + 128);
 
 	/* Test crash in a subtest preceeding a pass is reported */
 	simple = false;
@@ -125,7 +112,7 @@ int main(int argc, char **argv)
 	runc=true;
 	igt_info("Crashing then passing subtest.\n");
 	fflush(stdout);
-	internal_assert_wexited(do_fork(), SIGSEGV + 128);
+	internal_assert_wexited(do_fork(fake_test), SIGSEGV + 128);
 
 	return 0;
 }
diff --git a/lib/tests/igt_simulation.c b/lib/tests/igt_simulation.c
index 3f3cd88f..a0ea7000 100644
--- a/lib/tests/igt_simulation.c
+++ b/lib/tests/igt_simulation.c
@@ -40,59 +40,44 @@ bool list_subtests;
 bool in_fixture;
 bool in_subtest;
 
-char test[] = "test";
-char list[] = "--list-subtests";
-char *argv_list[] = { test, list };
-char *argv_run[] = { test };
-
-static int do_fork(void)
+static void fake_test(void)
 {
-	int pid, status;
+	char test[] = "test";
+	char list[] = "--list-subtests";
+	char *argv_list[] = { test, list };
+	char *argv_run[] = { test };
 	int argc;
 
-	switch (pid = fork()) {
-	case -1:
-		internal_assert(0);
-	case 0:
-		if (simple) {
-			argc = 1;
-			igt_simple_init(argc, argv_run);
+	if (simple) {
+		argc = 1;
+		igt_simple_init(argc, argv_run);
 
-			igt_skip_on_simulation();
+		igt_skip_on_simulation();
 
-			igt_exit();
+		igt_exit();
+	} else {
+		if (list_subtests) {
+			argc = 2;
+			igt_subtest_init(argc, argv_list);
 		} else {
-			if (list_subtests) {
-				argc = 2;
-				igt_subtest_init(argc, argv_list);
-			} else {
-				argc = 1;
-				igt_subtest_init(argc, argv_run);
-			}
-
-			if (in_fixture) {
-				igt_fixture
-					igt_skip_on_simulation();
-			} if (in_subtest) {
-				igt_subtest("sim")
-					igt_skip_on_simulation();
-			} else
-				igt_skip_on_simulation();
-
-			if (!in_subtest)
-				igt_subtest("foo")
-					;
-
-			igt_exit();
+			argc = 1;
+			igt_subtest_init(argc, argv_run);
 		}
-	default:
-		while (waitpid(pid, &status, 0) == -1 &&
-		       errno == EINTR)
-			;
 
-		internal_assert(WIFEXITED(status));
+		if (in_fixture) {
+			igt_fixture
+				igt_skip_on_simulation();
+		} if (in_subtest) {
+			igt_subtest("sim")
+				igt_skip_on_simulation();
+		} else
+			igt_skip_on_simulation();
+
+		if (!in_subtest)
+			igt_subtest("foo")
+				;
 
-		return status;
+		igt_exit();
 	}
 }
 
@@ -101,10 +86,10 @@ int main(int argc, char **argv)
 	/* simple tests */
 	simple = true;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SKIP);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SKIP);
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 	/* subtests, list mode */
 	simple = false;
@@ -112,28 +97,28 @@ int main(int argc, char **argv)
 
 	in_fixture = false;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 	in_fixture = true;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	in_fixture = false;
 	in_subtest = true;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	/* subtest, run mode */
@@ -142,29 +127,29 @@ int main(int argc, char **argv)
 
 	in_fixture = false;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SKIP);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SKIP);
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	in_fixture = true;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SKIP);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SKIP);
 
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	in_fixture = false;
 	in_subtest = true;
 	internal_assert(setenv("INTEL_SIMULATION", "1", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SKIP);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SKIP);
 
 
 	internal_assert(setenv("INTEL_SIMULATION", "0", 1) == 0);
-	internal_assert(WEXITSTATUS(do_fork()) == IGT_EXIT_SUCCESS);
+	internal_assert(WEXITSTATUS(do_fork(fake_test)) == IGT_EXIT_SUCCESS);
 
 
 	return 0;
diff --git a/lib/tests/igt_tests_common.h b/lib/tests/igt_tests_common.h
index e66ee37c..b3da3b34 100644
--- a/lib/tests/igt_tests_common.h
+++ b/lib/tests/igt_tests_common.h
@@ -26,6 +26,8 @@
 #define IGT_LIB_TESTS_COMMON_H
 
 #include <assert.h>
+#include <sys/wait.h>
+#include <errno.h>
 
 /*
  * We need to hide assert from the cocci igt test refactor spatch.
@@ -46,4 +48,93 @@ static inline void internal_assert_wsignaled(int wstatus, int signal)
 	internal_assert(WIFSIGNALED(wstatus) &&
 			WTERMSIG(wstatus) == signal);
 }
+
+static inline int do_fork(void (*test_to_run)(void))
+{
+	int pid, status;
+
+	switch (pid = fork()) {
+	case -1:
+		internal_assert(0);
+	case 0:
+		test_to_run();
+	default:
+		while (waitpid(pid, &status, 0) == -1 &&
+		       errno == EINTR)
+			;
+
+		return status;
+	}
+}
+
+static inline pid_t do_fork_bg_with_pipes(void (*test_to_run)(void), int *out, int *err)
+{
+	int outfd[2], errfd[2];
+	pid_t pid;
+
+	internal_assert(pipe(outfd) != -1);
+	internal_assert(pipe(errfd) != -1);
+
+	pid = fork();
+	internal_assert(pid != -1);
+
+	if (pid == 0) {
+		while (dup2(outfd[1], STDOUT_FILENO) == -1 && errno == EINTR) {}
+		while (dup2(errfd[1], STDERR_FILENO) == -1 && errno == EINTR) {}
+
+		close(outfd[0]);
+		close(outfd[1]);
+		close(errfd[0]);
+		close(errfd[1]);
+
+		test_to_run();
+
+		exit(-1);
+	} else {
+		/* close the writing ends */
+		close(outfd[1]);
+		close(errfd[1]);
+
+		*out = outfd[0];
+		*err = errfd[0];
+
+		return pid;
+	}
+}
+
+static inline int safe_wait(pid_t pid, int *status) {
+	int ret;
+
+	do {
+		ret = waitpid(pid, status, 0);
+	} while (ret == -1 && errno == EINTR);
+
+	return ret;
+}
+
+static inline void assert_pipe_empty(int fd)
+{
+	char buf[5];
+	internal_assert(0 == read(fd, buf, sizeof(buf)));
+}
+
+static inline void read_whole_pipe(int fd, char *buf, size_t buflen)
+{
+	ssize_t readlen;
+	off_t offset;
+
+	offset = 0;
+	while ((readlen = read(fd, buf+offset, buflen-offset))) {
+		if (readlen == -1) {
+			if (errno == EINTR) {
+				continue;
+			} else {
+				printf("read failed with %s\n", strerror(errno));
+				exit(1);
+			}
+		}
+		internal_assert(readlen != -1);
+		offset += readlen;
+	}
+}
 #endif
-- 
2.24.1



More information about the igt-dev mailing list