NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/56429: poll(2) should yield POLLHUP when last writer to a fifo close()'s it



>Number:         56429
>Category:       kern
>Synopsis:       poll(2) should yield POLLHUP when last writer to a fifo close()'s it
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Oct 01 11:20:00 +0000 2021
>Originator:     David Mackay
>Release:        9.2
>Organization:
>Environment:
NetBSD netbsd.fritz.box 9.2 NetBSD 9.2 (GENERIC) #0: Wed May 12 13:15:55 UTC 2021  mkrepro%mkrepro.NetBSD.org@localhost:/usr/src/sys/arch/amd64/compile/GENERIC amd64
>Description:
According to the most recent POSIX standard on poll(2):

"POLLHUP
A device has been disconnected, or a pipe or FIFO has been closed by the last process that had it open for writing.
[...]
The POLLHUP event does not occur for FIFOs just because the FIFO is not open for writing. It only occurs when the FIFO is closed by the last writer and persists until some process opens the FIFO for writing or until all read-only file descriptors for the FIFO are closed."

This, however, is not what happens on NetBSD. Attached below is a test case which should print something like:

poll() = 1, revents: POLLIN 0, POLLERR 0, POLLHUP 16, POLLNVAL 0

then exit. This behaviour is observed on GNU/Linux. (On OpenBSD and FreeBSD, POLLIN is also set.) However, on NetBSD, this happens:

poll() = 1, revents: POLLIN 1, POLLERR 0, POLLHUP 0, POLLNVAL 0
read() = 0

and the test case continues waiting.

Note: kevent() with EVFILT_READ *does* return EV_EOF in this case.
>How-To-Repeat:
#include <sys/types.h>
#include <sys/stat.h>

#include <err.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main()
{
	struct pollfd pfd;
	char buf[255];
	int wfd;

	unlink("fifo");

	if (mkfifo("fifo", 0600))
		err(EXIT_FAILURE, "mkfifo");

	pfd.fd = open("fifo", O_RDONLY | O_NONBLOCK);
	if (pfd.fd < 0)
		err(EXIT_FAILURE, "open for read");

	wfd = open("fifo", O_WRONLY);
	if (wfd < 0)
		err(EXIT_FAILURE, "open for write");

	/* close to generate a POLLHUP */
	close(wfd);

	pfd.events = POLLIN;

	do {
		int r = poll(&pfd, 1, -1);

		printf("poll() = %d, revents: POLLIN %d, POLLERR %d, "
		       "POLLHUP %d, POLLNVAL %d\n",
			r, pfd.revents & POLLIN, pfd.revents & POLLERR,
			pfd.revents & POLLHUP, pfd.revents & POLLNVAL);

		if (pfd.revents & POLLIN) {
			r = read(pfd.fd, buf, sizeof buf);
			printf("read() = %d\n", r);
		}
	} while (!(pfd.revents & (POLLERR | POLLHUP | POLLNVAL)));

	return 0;
}

>Fix:
A POLLHUP revent ought to be yielded.



Home | Main Index | Thread Index | Old Index