diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2019-02-13 11:35:46 +0100 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2019-02-15 10:36:40 +0100 |
commit | 89932c1500f927165c243015d70318f5cf3082da (patch) | |
tree | cb18a7d48c9175448de90c1fcdfb85dff5e6190c /lib/igt_core.c | |
parent | ecdf823b965f93269ccfc4ed89c4a06e13d3ff2c (diff) |
lib: Don't leak children in igt_waitchildren_timeout
Instead of cleaning up the mess in igt_exit make sure we don't even
let it out of the container. See also
commit 754876378d6c9b2775e8c07b4d16f9878c55949f
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date: Fri Feb 26 22:11:10 2016 +0000
igt/gem_sync: Enforce a timeout of 20s
which added this helper.
To make sure that everyone follows the rules, add an assert.
We're keeping the cleanup code as a failsafe, and because it speeds
up the testcase I'm following up with.
v2: Chris pointed out that my original patch did nothing. Which I
didn't catch because my testcase was also broken. Unfortunately this
means we need to open code part of the waiting.
v3: The 2nd __igt_waitchildren() isn't necessary, __igt_waitchildren
recovers from EINTR already and keeps waiting (Chris Wilson).
v4: Change the timeout signal vs waitchildren logic to be race-free
(Chris). This changes the exit code for a timeout from
IGT_EXIT_FAILURE to SIGKILL + 128.
v5: Clarify the docs (Chris).
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Diffstat (limited to 'lib/igt_core.c')
-rw-r--r-- | lib/igt_core.c | 31 |
1 files changed, 26 insertions, 5 deletions
diff --git a/lib/igt_core.c b/lib/igt_core.c index cbbe79f8..607b34cd 100644 --- a/lib/igt_core.c +++ b/lib/igt_core.c @@ -1525,6 +1525,7 @@ void igt_exit(void) for (int c = 0; c < num_test_children; c++) kill(test_children[c], SIGKILL); + assert(!num_test_children); if (!test_with_subtests) { struct timespec now; @@ -1832,20 +1833,40 @@ void igt_waitchildren(void) igt_fail(err); } +static void igt_alarm_killchildren(int signal) +{ + igt_info("Timed out waiting for children\n"); + + for (int c = 0; c < num_test_children; c++) + kill(test_children[c], SIGKILL); +} + /** * igt_waitchildren_timeout: * @seconds: timeout in seconds to wait * @reason: debug string explaining what timedout * - * Wait for all children forked with igt_fork, for a maximum of @seconds. - * - * Wraps igt_waitchildren() and igt_set_timeout() + * Wait for all children forked with igt_fork, for a maximum of @seconds. If the + * timeout expires, kills all children, cleans them up, and then fails by + * calling igt_fail(). */ void igt_waitchildren_timeout(int seconds, const char *reason) { - igt_set_timeout(seconds, reason); - igt_waitchildren(); + struct sigaction sa; + int ret; + + sa.sa_handler = igt_alarm_killchildren; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + + sigaction(SIGALRM, &sa, NULL); + + alarm(seconds); + + ret = __igt_waitchildren(); igt_reset_timeout(); + if (ret) + igt_fail(ret); } /* exit handler code */ |