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

Petri Latvala
2020-02-14T11:57:33Z

On Wed, Feb 12, 2020 at 03:21:15PM +0200, Arkadiusz Hiler wrote:
> 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@intel.com>

Reviewed-by: Petri Latvala <petri.latvala@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