lib/drmtest: ducttape over fork race
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 13 Sep 2013 14:43:22 +0000 (16:43 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 13 Sep 2013 14:48:08 +0000 (16:48 +0200)
Whatever the reason (and I've thought there isn't one) if we fork and
kill right away the child seems to not reliably die. We can work
around this little race by forcing the default SIGQUIT handler. This
should break anything since we reset our atexit handling anyway, so if
the helper needs any atexit handling the special signal helpers will
be reinstated.

Note that inserting sufficient amounts of printf between the fork and
kill makes this unnecessary.

While add it also add the retry loop for the waitpid call, in case
there's another guy constantly interrupting us.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
lib/drmtest.c

index 1ba8cad..a3ff0d6 100644 (file)
@@ -981,6 +981,7 @@ static void fork_helper_exit_handler(int sig)
 bool __igt_fork_helper(struct igt_helper_process *proc)
 {
        pid_t pid;
+       sighandler_t oldsig;
        int id;
 
        assert(!proc->running);
@@ -991,6 +992,13 @@ bool __igt_fork_helper(struct igt_helper_process *proc)
 
        igt_install_exit_handler(fork_helper_exit_handler);
 
+       /*
+        * XXX: There's a race between fork and the subsequent kill in
+        * igt_stop_signal_helper if we don't ovewrite the SIGQUIT handler. Note
+        * that inserting sufficient amounts of printf or other delays makes
+        * this unnecessary.
+        */
+       oldsig = signal(SIGQUIT, SIG_DFL);
        switch (pid = fork()) {
        case -1:
                igt_assert(0);
@@ -1000,6 +1008,8 @@ bool __igt_fork_helper(struct igt_helper_process *proc)
 
                return true;
        default:
+               signal(SIGQUIT, oldsig);
+
                proc->running = true;
                proc->pid = pid;
                proc->id = id;
@@ -1023,7 +1033,9 @@ void igt_stop_helper(struct igt_helper_process *proc)
        assert(proc->running);
 
        assert(kill(proc->pid, SIGQUIT) == 0);
-       waitpid(proc->pid, &status, 0);
+       while (waitpid(proc->pid, &status, 0) == -1 &&
+              errno == -EINTR)
+               ;
 
        proc->running = false;