Hi,

I've noticed that kqueue(2) doesn't notify reader about EV_EOF
condition on pipe. Attached simple test program highlights
the problem (confirmed both on 5-CURRENT and 4-STABLE). Also
attached is the simple fix.

-Maxim
Index: sys/kern/sys_pipe.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/sys_pipe.c,v
retrieving revision 1.86
diff -d -u -r1.86 sys_pipe.c
--- sys/kern/sys_pipe.c 2001/09/21 22:46:53     1.86
+++ sys/kern/sys_pipe.c 2001/11/12 13:28:05
@@ -1221,6 +1221,7 @@
 
                        ppipe->pipe_state |= PIPE_EOF;
                        wakeup(ppipe);
+                       KNOTE(&ppipe->pipe_sel.si_note, 0);
                        ppipe->pipe_peer = NULL;
                }
                /*
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <err.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void
testpassed(int sig)
{
        printf("Test passed\n");
        exit(0);
}

int
main(int argc, char **argv)
{
        int kq, pid, ppid, nevents;
        struct kevent changelist[1];
        struct kevent eventlist[1];
        int pp[2];

        pipe(pp);
        ppid = getpid();
        pid = fork();

        switch (pid) {
        case -1:
                /* Error */
                err(1, "can't fork()");
                /* NOTREACHED */

        case 0:
                /* Child */
                close(pp[1]);
                kq = kqueue();
                EV_SET(changelist, pp[0], EVFILT_READ, EV_ADD | EV_ENABLE | EV_EOF, \
                    0, 0, NULL);
                kevent(kq, changelist, 1, NULL, 0, NULL);
                for (;;) {
                        nevents = kevent(kq, NULL, 0, eventlist, 1, NULL);
                        if (nevents > 0 || (eventlist[0].flags & EV_EOF) != 0) {
                                kill(ppid, SIGTERM);
                                exit(0);
                        }
                }
                break;

        default:
                /* Sever */
                close(pp[0]);
                break;
        }
        signal(SIGTERM, testpassed);
        /* Give child some time to initialise kqueue(2) */
        sleep(1);
        close(pp[1]);
        /* Give child some time to receive EV_EOF and kill us */
        sleep(1);
        kill(pid, SIGTERM);
        printf("Test failed\n");
        exit(1);
}

Reply via email to