This should fix some issues when using kqueue/poll on FIFOs or pipes.
Related bug reports:
- https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=224615
- https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=203366
In detail this patch makes the following changes:
When new readers/writers connect to a FIFO, pipeselwakeup() is now called so that pollers are woken up and a kqueue event is triggered. I've also added pipeselwakeup() to the error path but I'm not exactly sure how to test the error path.
When reading from a pipe, pipeselwakeup() is now only called if there was actually some data read. This prevents the continuous re-triggering of a EVFILT_READ event on EOF when in edge-triggered mode (using EV_CLEAR).
It is possible to get POLLIN from a O_WRONLY fd on a closed FIFO. There should probably be a check for the FREAD fd flag.
When closing down a pipe, pipeselwakeup() was called before the PIPE_EOF flag is set. This could be moved down a bit so that pipe_poll() and filt_piperead() pick up the PIPE_EOF flag correctly. Similarly, the pipeselwakeup() when disconnecting from the peer can be moved a bit down so calling KNOTE_LOCKED again becomes unnecessary.
The filt_piperead() was modified so it can clear EV_EOF again. This happens when new readers/writers connect to a FIFO. This behavior was present in the old socket based FIFO implementation but lost when FIFOs/pipes where merged some years ago. The man page says that the EV_EOF flag can be cleared by specifying EV_CLEAR, but this seems to be inaccurate. The wording should probably be updated (as DragonFlyBSD did here https://github.com/DragonFlyBSD/DragonFlyBSD/commit/acb71b22f1443bd8a34f6e457cf57c4527d7ab52).
I've also added the check for the current FIFO writer generation to filt_piperead() so that new readers that connect to a previously closed FIFO don't get the "old" EV_EOF flag. This now matches the poll() behavior. I removed the checks on "wpipe": On FIFOs it does not matter because only one pipe of a pipepair is actually used (in this case the "rpipe"). On pipes, "pipeclose" sets both EV_EOF flags shortly after another anyway.
In filt_pipewrite() the EV_EOF flag is now also cleared on new readers. I've moved the assignments to "kn->kn_data" above the EOF checking. This now matches the behavior of the old socket based implementation where kn_data could be non-zero and EV_EOF be set at the same time.
I wrote some ATF tests for most of this (https://github.com/jiixyj/epoll-shim/blob/develop/test/pipe-test.c) and to compare with other OSs. I'd like to clean them up so they could be added as well.