Module Name: src Committed By: martin Date: Sat Oct 2 11:07:56 UTC 2021
Modified Files: src/sys/kern [netbsd-9]: uipc_socket2.c src/sys/miscfs/fifofs [netbsd-9]: fifo_vnops.c src/tests/lib/libc/sys [netbsd-9]: t_poll.c Log Message: Pull up following revision(s) (requested by thorpej in ticket #1350): sys/kern/uipc_socket2.c: revision 1.140 tests/lib/libc/sys/t_poll.c: revision 1.5 sys/miscfs/fifofs/fifo_vnops.c: revision 1.87 - fifo_poll(): If the last writer has disappeared, detect this and return POLLHUP, per POSIX. - fifo_close(): Use the new fifo_socantrcvmore(), which is like the garden-variety socantrcvmore(), except it specifies POLL_HUP rather than POLL_IN (so the correct code for SIGIO is sent). - sowakeup(): Allow POLL_HUP as a code (notifies poll'ers with POLLHUP). - Add test cases for correct POLLHUP behavior with FIFOs. Fixes PR kern/56429. To generate a diff of this commit: cvs rdiff -u -r1.134.2.1 -r1.134.2.2 src/sys/kern/uipc_socket2.c cvs rdiff -u -r1.79 -r1.79.8.1 src/sys/miscfs/fifofs/fifo_vnops.c cvs rdiff -u -r1.3 -r1.3.34.1 src/tests/lib/libc/sys/t_poll.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/uipc_socket2.c diff -u src/sys/kern/uipc_socket2.c:1.134.2.1 src/sys/kern/uipc_socket2.c:1.134.2.2 --- src/sys/kern/uipc_socket2.c:1.134.2.1 Tue Sep 22 18:39:01 2020 +++ src/sys/kern/uipc_socket2.c Sat Oct 2 11:07:55 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: uipc_socket2.c,v 1.134.2.1 2020/09/22 18:39:01 martin Exp $ */ +/* $NetBSD: uipc_socket2.c,v 1.134.2.2 2021/10/02 11:07:55 martin Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -58,7 +58,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uipc_socket2.c,v 1.134.2.1 2020/09/22 18:39:01 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uipc_socket2.c,v 1.134.2.2 2021/10/02 11:07:55 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_ddb.h" @@ -554,10 +554,27 @@ sowakeup(struct socket *so, struct sockb KASSERT(solocked(so)); KASSERT(sb->sb_so == so); - if (code == POLL_IN) + switch (code) { + case POLL_IN: band = POLLIN|POLLRDNORM; - else + break; + + case POLL_OUT: band = POLLOUT|POLLWRNORM; + break; + + case POLL_HUP: + band = POLLHUP; + break; + + default: + band = 0; +#ifdef DIAGNOSTIC + printf("bad siginfo code %d in socket notification.\n", code); +#endif + break; + } + sb->sb_flags &= ~SB_NOTIFY; selnotify(&sb->sb_sel, band, NOTE_SUBMIT); cv_broadcast(&sb->sb_cv); Index: src/sys/miscfs/fifofs/fifo_vnops.c diff -u src/sys/miscfs/fifofs/fifo_vnops.c:1.79 src/sys/miscfs/fifofs/fifo_vnops.c:1.79.8.1 --- src/sys/miscfs/fifofs/fifo_vnops.c:1.79 Wed Oct 25 08:12:39 2017 +++ src/sys/miscfs/fifofs/fifo_vnops.c Sat Oct 2 11:07:55 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: fifo_vnops.c,v 1.79 2017/10/25 08:12:39 maya Exp $ */ +/* $NetBSD: fifo_vnops.c,v 1.79.8.1 2021/10/02 11:07:55 martin Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -58,7 +58,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: fifo_vnops.c,v 1.79 2017/10/25 08:12:39 maya Exp $"); +__KERNEL_RCSID(0, "$NetBSD: fifo_vnops.c,v 1.79.8.1 2021/10/02 11:07:55 martin Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -337,24 +337,69 @@ fifo_poll(void *v) struct vop_poll_args /* { struct vnode *a_vp; int a_events; - struct lwp *a_l; } */ *ap = v; - struct socket *so; - int revents; + struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock; + struct socket *wso = ap->a_vp->v_fifoinfo->fi_writesock; + struct socket *lso = NULL; + int events; + + /* + * N.B. We're using a slightly different naming convention + * for these variables that most poll handlers. + */ + int revents = 0; + int wevents = 0; + + if (rso != NULL) { + lso = rso; + } else if (wso != NULL) { + lso = wso; + } - revents = 0; - if (ap->a_events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) { - so = ap->a_vp->v_fifoinfo->fi_readsock; - if (so) - revents |= sopoll(so, ap->a_events); + if (lso == NULL) { + /* No associated sockets -> no events to report. */ + return 0; + } + + KASSERT(rso == NULL || lso->so_lock == rso->so_lock); + KASSERT(wso == NULL || lso->so_lock == wso->so_lock); + + solock(lso); + + if (rso != NULL) { + events = ap->a_events & (POLLIN | POLLRDNORM); + if (events != 0 && soreadable(rso)) { + revents |= events; + } + if (rso->so_state & SS_CANTRCVMORE) { + revents |= POLLHUP; + } + /* + * We always selrecord the read side here regardless + * of the caller's read interest because we need to + * action POLLHUP. + */ + if (revents == 0) { + selrecord(curlwp, &rso->so_rcv.sb_sel); + rso->so_rcv.sb_flags |= SB_NOTIFY; + } } - if (ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND)) { - so = ap->a_vp->v_fifoinfo->fi_writesock; - if (so) - revents |= sopoll(so, ap->a_events); + + /* POSIX sez: POLLHUP and POLLOUT are mutually-exclusive. */ + if (wso != NULL && (revents & POLLHUP) == 0) { + events = ap->a_events & (POLLOUT | POLLWRNORM); + if (events != 0 && sowritable(wso)) { + wevents |= events; + } + if (wevents == 0 && events != 0) { + selrecord(curlwp, &wso->so_snd.sb_sel); + wso->so_snd.sb_flags |= SB_NOTIFY; + } } - return (revents); + sounlock(lso); + + return (revents | wevents); } static int @@ -392,6 +437,20 @@ fifo_bmap(void *v) } /* + * This is like socantrcvmore(), but we send the POLL_HUP code. + */ +static void +fifo_socantrcvmore(struct socket *so) +{ + KASSERT(solocked(so)); + + so->so_state |= SS_CANTRCVMORE; + if (sb_notify(&so->so_rcv)) { + sowakeup(so, &so->so_rcv, POLL_HUP); + } +} + +/* * Device close routine */ /* ARGSUSED */ @@ -422,13 +481,13 @@ fifo_close(void *v) } if (fip->fi_writers != 0) { fip->fi_writers = 0; - socantrcvmore(rso); + fifo_socantrcvmore(rso); } } else { if ((ap->a_fflag & FREAD) && --fip->fi_readers == 0) socantsendmore(wso); if ((ap->a_fflag & FWRITE) && --fip->fi_writers == 0) - socantrcvmore(rso); + fifo_socantrcvmore(rso); } if ((fip->fi_readers + fip->fi_writers) == 0) { sounlock(wso); Index: src/tests/lib/libc/sys/t_poll.c diff -u src/tests/lib/libc/sys/t_poll.c:1.3 src/tests/lib/libc/sys/t_poll.c:1.3.34.1 --- src/tests/lib/libc/sys/t_poll.c:1.3 Sun Mar 18 07:00:52 2012 +++ src/tests/lib/libc/sys/t_poll.c Sat Oct 2 11:07:55 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: t_poll.c,v 1.3 2012/03/18 07:00:52 jruoho Exp $ */ +/* $NetBSD: t_poll.c,v 1.3.34.1 2021/10/02 11:07:55 martin Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -29,6 +29,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <sys/stat.h> #include <sys/time.h> #include <sys/wait.h> @@ -378,6 +379,107 @@ ATF_TC_BODY(pollts_sigmask, tc) ATF_REQUIRE_EQ(close(fd), 0); } +static const char fifo_path[] = "pollhup_fifo"; + +static void +fifo_support(void) +{ + errno = 0; + if (mkfifo(fifo_path, 0600) == 0) { + ATF_REQUIRE(unlink(fifo_path) == 0); + return; + } + + if (errno == EOPNOTSUPP) { + atf_tc_skip("the kernel does not support FIFOs"); + } else { + atf_tc_fail("mkfifo(2) failed"); + } +} + +ATF_TC_WITH_CLEANUP(fifo_hup1); +ATF_TC_HEAD(fifo_hup1, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Check POLLHUP behavior with fifos [1]"); +} + +ATF_TC_BODY(fifo_hup1, tc) +{ + struct pollfd pfd; + int rfd, wfd; + + fifo_support(); + + ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0); + ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0); + ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0); + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = rfd; + pfd.events = POLLIN; + + (void)close(wfd); + + ATF_REQUIRE(poll(&pfd, 1, 0) == 1); + ATF_REQUIRE((pfd.revents & POLLHUP) != 0); +} + +ATF_TC_CLEANUP(fifo_hup1, tc) +{ + (void)unlink(fifo_path); +} + +ATF_TC_WITH_CLEANUP(fifo_hup2); +ATF_TC_HEAD(fifo_hup2, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Check POLLHUP behavior with fifos [2]"); +} + +ATF_TC_BODY(fifo_hup2, tc) +{ + struct pollfd pfd; + int rfd, wfd; + pid_t pid; + struct timespec ts1, ts2; + + fifo_support(); + + ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0); + ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0); + ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0); + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = rfd; + pfd.events = POLLIN; + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + (void)close(rfd); + sleep(5); + (void)close(wfd); + _exit(0); + } + (void)close(wfd); + + ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts1) == 0); + ATF_REQUIRE(poll(&pfd, 1, INFTIM) == 1); + ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts2) == 0); + + /* Make sure at least a couple of seconds have elapsed. */ + ATF_REQUIRE(ts2.tv_sec - ts1.tv_sec >= 2); + + ATF_REQUIRE((pfd.revents & POLLHUP) != 0); +} + +ATF_TC_CLEANUP(fifo_hup2, tc) +{ + (void)unlink(fifo_path); +} + ATF_TP_ADD_TCS(tp) { @@ -388,5 +490,8 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, pollts_err); ATF_TP_ADD_TC(tp, pollts_sigmask); + ATF_TP_ADD_TC(tp, fifo_hup1); + ATF_TP_ADD_TC(tp, fifo_hup2); + return atf_no_error(); }