regress/sys/kern/kqueue/kqueue-process (kqueue-test -P) is a test to
receive process-related events (fork/exec/exit). This test forks a
child, then forks a child-child from child. But parent checks only
child's exit. This has worked because scheduler happens to run child-child
much later.
Don't rely on that racy condition but check child-child events too.
Found by Valgrind (by luck).
Index: kqueue-process.c
===================================================================
RCS file: /cvs/src/regress/sys/kern/kqueue/kqueue-process.c,v
retrieving revision 1.6
diff -u -p -r1.6 kqueue-process.c
--- kqueue-process.c 2 Aug 2015 00:47:25 -0000 1.6
+++ kqueue-process.c 2 Aug 2015 01:01:31 -0000
@@ -105,19 +105,24 @@ do_process(void)
kill(pid2, SIGUSR1); /* sync 2.1 */
kill(pid, SIGUSR1); /* sync 2 */
+ /* Wait for child's exit. */
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 < 1; i++) {
- /* make sure we get an exit note */
+ for (i = 0; i < 2; i++) {
ASS(kevent(kq, NULL, 0, &ke, 1, &ts) == 1,
warnx("didn't receive event"));
ASSX(ke.filter == EVFILT_PROC);
switch (ke.fflags) {
case NOTE_EXIT:
- didchild = 1;
ASSX((pid_t)ke.ident == pid);
- fprintf(stderr, "exit %d\n", pid);
+ fprintf(stderr, "child exit %d\n", pid);
+ break;
+ case NOTE_EXEC | NOTE_EXIT:
+ ASSX((pid_t)ke.ident == pid2);
+ fprintf(stderr, "child-child exec/exit %d\n", pid2);
break;
default:
errx(1, "kevent returned weird event 0x%x pid %d",