Improve synchronization between the parent and children. This fixes
authorvisa <visa@openbsd.org>
Fri, 3 Aug 2018 15:19:44 +0000 (15:19 +0000)
committervisa <visa@openbsd.org>
Fri, 3 Aug 2018 15:19:44 +0000 (15:19 +0000)
a spurious test failure spotted by anton@ and eliminates sleeping
in the test.

Feedback and OK anton@

regress/sys/kern/kqueue/kqueue-process.c

index dd3ae9b..79fdfad 100644 (file)
@@ -1,15 +1,15 @@
-/*     $OpenBSD: kqueue-process.c,v 1.12 2016/09/20 23:05:27 bluhm Exp $       */
+/*     $OpenBSD: kqueue-process.c,v 1.13 2018/08/03 15:19:44 visa Exp $        */
 /*
  *     Written by Artur Grabowski <art@openbsd.org> 2002 Public Domain
  */
 
 #include <sys/types.h>
 #include <sys/event.h>
+#include <sys/time.h>
 #include <sys/wait.h>
 
 #include <err.h>
 #include <errno.h>
-#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 static int process_child(void);
 
-static void
-usr1handler(int signum)
-{
-       /* nada */
-}
+static int pfd1[2];
+static int pfd2[2];
 
 int
 do_process(void)
 {
        struct kevent ke;
+       struct timespec ts;
        int kq, status;
        pid_t pid, pid2;
        int didfork, didchild;
        int i;
-       struct timespec ts;
+       char ch = 0;
 
        /*
         * Timeout in case something doesn't work.
@@ -43,11 +41,11 @@ do_process(void)
        ASS((kq = kqueue()) >= 0,
            warn("kqueue"));
 
-       /*
-        * Install a signal handler so that we can use pause() to synchronize
-        * with the child with the parent.
-        */
-       signal(SIGUSR1, usr1handler);
+       /* Open pipes for synchronizing the children with the parent. */
+       if (pipe(pfd1) == -1)
+               err(1, "pipe 1");
+       if (pipe(pfd2) == -1)
+               err(1, "pipe 2");
 
        switch ((pid = fork())) {
        case -1:
@@ -56,8 +54,6 @@ do_process(void)
                _exit(process_child());
        }
 
-       sleep(2);       /* wait for child to settle down. */
-
        EV_SET(&ke, pid, EVFILT_PROC, EV_ADD|EV_ENABLE|EV_CLEAR,
            NOTE_EXIT|NOTE_FORK|NOTE_EXEC|NOTE_TRACK, 0, NULL);
        ASS(kevent(kq, &ke, 1, NULL, 0, NULL) == 0,
@@ -71,7 +67,8 @@ do_process(void)
        ASS(errno == ESRCH,
            warn("register bogus pid on kqueue returned wrong error"));
 
-       kill(pid, SIGUSR1);     /* sync 1 */
+       ASS(write(pfd1[1], &ch, 1) == 1,
+           warn("write sync 1"));
 
        didfork = didchild = 0;
 
@@ -107,14 +104,18 @@ do_process(void)
        ASSX(didchild == 1);
        ASSX(didfork == 1);
 
-       kill(pid2, SIGUSR1);    /* sync 2.1 */
-       kill(pid, SIGUSR1);     /* sync 2 */
+       ASS(write(pfd2[1], &ch, 1) == 1,
+           warn("write sync 2.1"));
+       ASS(write(pfd1[1], &ch, 1) == 1,
+           warn("write sync 2"));
 
-       /* Wait for child's exit. */
+       /*
+        * Wait for child's exit. It also implies child-child has exited.
+        * This should ensure that NOTE_EXIT has been posted for both children.
+        * Child-child's events should get aggregated.
+        */
        if (wait(&status) < 0)
                err(1, "wait");
-       /* Wait for child-child's exec/exit to receive two events at once. */
-       sleep(1);
 
        for (i = 0; i < 2; i++) {
                ASS(kevent(kq, NULL, 0, &ke, 1, &ts) == 1,
@@ -145,23 +146,30 @@ do_process(void)
 static int
 process_child(void)
 {
-       signal(SIGCHLD, SIG_IGN);       /* ignore our children. */
+       int status;
+       char ch;
 
-       pause();
+       ASS(read(pfd1[0], &ch, 1) == 1,
+           warn("read sync 1"));
 
        /* fork and see if tracking works. */
        switch (fork()) {
        case -1:
                err(1, "fork");
        case 0:
-               /* sync 2.1 */
-               pause();
+               ASS(read(pfd2[0], &ch, 1) == 1,
+                   warn("read sync 2.1"));
                execl("/usr/bin/true", "true", (char *)NULL);
                err(1, "execl(true)");
        }
 
-       /* sync 2 */
-       pause();
+       ASS(read(pfd1[0], &ch, 1) == 1,
+           warn("read sync 2"));
+
+       if (wait(&status) < 0)
+               err(1, "wait 2");
+       if (!WIFEXITED(status))
+               errx(1, "child-child didn't exit?");
 
        return 0;
 }