[igt-dev] [PATCH i-g-t v3] lib: Kill residual children at the end of a subtest

Chris Wilson chris at chris-wilson.co.uk
Mon Feb 3 13:11:27 UTC 2020


Ensure that we tidy up all the excess children left behind by a failing
subtest, we do not want them loitering into the next!

v2: Behead the undead plague, and throw in a bonus lib/tests

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Petri Latvala <petri.latvala at intel.com>
---
 lib/igt_core.c       |  7 +++++++
 lib/tests/igt_fork.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/lib/igt_core.c b/lib/igt_core.c
index a0bf29408..510417934 100644
--- a/lib/igt_core.c
+++ b/lib/igt_core.c
@@ -1362,6 +1362,13 @@ static void exit_subtest(const char *result)
 
 	igt_terminate_spins();
 
+	/* If the subtest aborted, it may have left children behind */
+	for (int c = 0; c < num_test_children; c++) {
+		kill(test_children[c], SIGKILL);
+		waitpid(test_children[c], NULL, 0); /* don't leave zombies! */
+	}
+	num_test_children = 0;
+
 	if (!in_dynamic_subtest)
 		_igt_dynamic_tests_executed = -1;
 
diff --git a/lib/tests/igt_fork.c b/lib/tests/igt_fork.c
index 7e8b4f9b5..e30584fd2 100644
--- a/lib/tests/igt_fork.c
+++ b/lib/tests/igt_fork.c
@@ -107,6 +107,48 @@ static int do_fork(void (*test_to_run)(void))
 	}
 }
 
+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;
+	}
+}
+
+static void subtest_leak(void)
+{
+	pid_t *children =
+		mmap(0, 4096, PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
+	const int num_children = 4096 / sizeof(*children);
+
+	igt_subtest("fork-leak") {
+		igt_fork(child, num_children)
+			children[child] = getpid();
+
+		/* leak the children */
+		igt_assert(0);
+	}
+
+	/* We expect the exit_subtest to cleanup after the igt_fork */
+	for (int i = 0; i < num_children; i++)
+		assert(kill(children[i], 0) == -1 && errno == ESRCH);
+
+	munmap(children, 4096);
+}
 
 int main(int argc, char **argv)
 {
@@ -131,4 +173,7 @@ int main(int argc, char **argv)
 	/* check that any other process leaks are caught*/
 	ret = do_fork(plain_fork_leak);
 	internal_assert_wsignaled(ret, SIGABRT);
+
+	ret = do_subtest(subtest_leak);
+	internal_assert_wexited(ret, IGT_EXIT_FAILURE); /* not asserted! */
 }
-- 
2.25.0



More information about the igt-dev mailing list