Module Name: src Committed By: riastradh Date: Mon Feb 10 02:41:34 UTC 2025
Modified Files: src/tests/lib/libc/sys: t_poll.c Log Message: t_poll: Extend the hangup tests to ptys too. Of course, ptys work slightly differently from pipes and fifos and sockets, presumably for hysterical raisins... While here: add a more detailed comment to each xfail for the reason why I think it is broken. PR kern/59056: poll POLLHUP bugs To generate a diff of this commit: cvs rdiff -u -r1.11 -r1.12 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/tests/lib/libc/sys/t_poll.c diff -u src/tests/lib/libc/sys/t_poll.c:1.11 src/tests/lib/libc/sys/t_poll.c:1.12 --- src/tests/lib/libc/sys/t_poll.c:1.11 Sun Feb 9 17:10:37 2025 +++ src/tests/lib/libc/sys/t_poll.c Mon Feb 10 02:41:34 2025 @@ -1,4 +1,4 @@ -/* $NetBSD: t_poll.c,v 1.11 2025/02/09 17:10:37 riastradh Exp $ */ +/* $NetBSD: t_poll.c,v 1.12 2025/02/10 02:41:34 riastradh Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -29,6 +29,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <sys/ioctl.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/time.h> @@ -43,6 +44,7 @@ #include <stdio.h> #include <stdlib.h> #include <signal.h> +#include <termios.h> #include <unistd.h> #include "h_macros.h" @@ -514,7 +516,7 @@ fillpipebuf(int writefd) } static void -check_write_epipe(int writefd) +check_write_fail(int writefd, int error) { int flags; void (*sighandler)(int); @@ -525,7 +527,7 @@ check_write_epipe(int writefd) RL(fcntl(writefd, F_SETFL, flags|O_NONBLOCK)); REQUIRE_LIBC(sighandler = signal(SIGPIPE, SIG_IGN), SIG_ERR); - ATF_CHECK_ERRNO(EPIPE, (nwrit = write(writefd, &c, 1)) == -1); + ATF_CHECK_ERRNO(error, (nwrit = write(writefd, &c, 1)) == -1); ATF_CHECK_EQ_MSG(nwrit, -1, "nwrit=%zd", nwrit); REQUIRE_LIBC(signal(SIGPIPE, sighandler), SIG_ERR); @@ -549,7 +551,8 @@ check_read_eof(int readfd) } static void -check_pollclosed_delayed_write(int writefd, int readfd) +check_pollclosed_delayed_write(int writefd, int readfd, + int expected, int writeerror) { struct pollfd pfd = { .fd = writefd, .events = POLLOUT }; struct timespec start, end, delta; @@ -577,16 +580,17 @@ check_pollclosed_delayed_write(int write * The reader has been closed, so write will fail immediately * with EPIPE/SIGPIPE, and thus POLLOUT must be set. POLLHUP * is only returned for reads, not for writes (and is mutually - * exclusive with POLLOUT). + * exclusive with POLLOUT). Except we _do_ return POLLHUP + * instead of POLLOUT for terminals. */ RL(nfds = poll(&pfd, 1, 0)); ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds); ATF_CHECK_EQ_MSG(pfd.fd, writefd, "pfd.fd=%d writefd=%d", pfd.fd, writefd); - ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), POLLOUT, - "revents=0x%x expected POLLOUT=0x%x" - " but not POLLHUP=0x%x or POLLIN=0x%x", - pfd.revents, POLLOUT, POLLHUP, POLLIN); + ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), expected, + "revents=0x%x expected=0x%x" + " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x", + pfd.revents, expected, POLLOUT, POLLHUP, POLLIN); /* * We should have slept at least 1sec. @@ -596,11 +600,25 @@ check_pollclosed_delayed_write(int write "slept only %lld.%09ld", (long long)delta.tv_sec, delta.tv_nsec); /* - * Write should fail with EPIPE/SIGPIPE now -- and continue to - * do so. + * Write should fail with EPIPE/SIGPIPE now, or EIO for + * terminals -- and continue to do so. */ - check_write_epipe(writefd); - check_write_epipe(writefd); + check_write_fail(writefd, writeerror); + check_write_fail(writefd, writeerror); +} + +static void +check_pollclosed_delayed_write_fifopipesocket(int writefd, int readfd) +{ + + check_pollclosed_delayed_write(writefd, readfd, POLLOUT, EPIPE); +} + +static void +check_pollclosed_delayed_write_terminal(int writefd, int readfd) +{ + + check_pollclosed_delayed_write(writefd, readfd, POLLHUP, EIO); } static void @@ -675,7 +693,7 @@ check_pollclosed_delayed_read(int readfd } static void -check_pollclosed_delayed_read_pipefifo(int readfd, int writefd) +check_pollclosed_delayed_read_devfifopipe(int readfd, int writefd) { check_pollclosed_delayed_read(readfd, writefd, POLLHUP); @@ -761,7 +779,8 @@ check_pollclosed_delayed_thread(int poll } static void -check_pollclosed_immediate_write(int writefd, int readfd) +check_pollclosed_immediate_write(int writefd, int readfd, int expected, + int writeerror) { struct pollfd pfd = { .fd = writefd, .events = POLLOUT }; int nfds; @@ -776,23 +795,24 @@ check_pollclosed_immediate_write(int wri * The reader has been closed, so write will fail immediately * with EPIPE/SIGPIPE, and thus POLLOUT must be set. POLLHUP * is only returned for reads, not for writes (and is mutually - * exclusive with POLLOUT). + * exclusive with POLLOUT). Except we _do_ return POLLHUP + * instead of POLLOUT for terminals. */ RL(nfds = poll(&pfd, 1, 0)); ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds); ATF_CHECK_EQ_MSG(pfd.fd, writefd, "pfd.fd=%d writefd=%d", pfd.fd, writefd); - ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), POLLOUT, - "revents=0x%x expected POLLOUT=0x%x" - " but not POLLHUP=0x%x or POLLIN=0x%x", - pfd.revents, POLLOUT, POLLHUP, POLLIN); + ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), expected, + "revents=0x%x expected=0x%x" + " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x", + pfd.revents, expected, POLLOUT, POLLHUP, POLLIN); /* * Write should fail with EPIPE/SIGPIPE now -- and continue to * do so. */ - check_write_epipe(writefd); - check_write_epipe(writefd); + check_write_fail(writefd, writeerror); + check_write_fail(writefd, writeerror); } static void @@ -854,10 +874,10 @@ check_pollclosed_immediate_readsome(int RL(nfds = poll(&pfd, 1, 0)); ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds); ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), - POLLIN|pollhup, + pollhup|POLLIN, "revents=0x%x expected=0x%x" " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x", - pfd.revents, POLLIN|pollhup, POLLHUP, POLLIN, POLLOUT); + pfd.revents, pollhup|POLLIN, POLLHUP, POLLIN, POLLOUT); /* * Read all the data. Each read should complete instantly -- @@ -974,6 +994,48 @@ pollclosed_pipe_setup(int *writefdp, int } static void +pollclosed_ptyapp_setup(int *writefdp, int *readfdp) +{ + int hostfd, appfd; + struct termios t; + char *pts; + + RL(hostfd = posix_openpt(O_RDWR|O_NOCTTY)); + RL(grantpt(hostfd)); + RL(unlockpt(hostfd)); + REQUIRE_LIBC(pts = ptsname(hostfd), NULL); + RL(appfd = open(pts, O_RDWR|O_NOCTTY)); + + RL(tcgetattr(appfd, &t)); + t.c_lflag &= ~ICANON; /* block rather than drop input */ + RL(tcsetattr(appfd, TCSANOW, &t)); + + *readfdp = appfd; + *writefdp = hostfd; +} + +static void +pollclosed_ptyhost_setup(int *writefdp, int *readfdp) +{ + int hostfd, appfd; + struct termios t; + char *pts; + + RL(hostfd = posix_openpt(O_RDWR|O_NOCTTY)); + RL(grantpt(hostfd)); + RL(unlockpt(hostfd)); + REQUIRE_LIBC(pts = ptsname(hostfd), NULL); + RL(appfd = open(pts, O_RDWR|O_NOCTTY)); + + RL(tcgetattr(appfd, &t)); + t.c_lflag &= ~ICANON; /* block rather than drop input */ + RL(tcsetattr(appfd, TCSANOW, &t)); + + *writefdp = appfd; + *readfdp = hostfd; +} + +static void pollclosed_socketpair0_setup(int *writefdp, int *readfdp) { int s[2]; @@ -999,8 +1061,10 @@ pollclosed_socketpair1_setup(int *writef * 1. [fifo0] first fifo opener * 2. [fifo1] second fifo opener * 3. [pipe] pipe - * 4. [socketpair0] first side of socket pair - * 5. [socketpair1] second side of socket pair + * 4. [ptyhost] host side of pty + * 5. [ptyapp] application side of pty + * 6. [socketpair0] first side of socket pair + * 7. [socketpair1] second side of socket pair * * with * @@ -1032,7 +1096,7 @@ ATF_TC_BODY(pollclosed_fifo0_immediate_w pollclosed_fifo0_setup(&writefd, &readfd); fillpipebuf(writefd); - check_pollclosed_immediate_write(writefd, readfd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); } ATF_TC(pollclosed_fifo0_immediate_writeempty); @@ -1047,7 +1111,7 @@ ATF_TC_BODY(pollclosed_fifo0_immediate_w pollclosed_fifo0_setup(&writefd, &readfd); /* don't fill the pipe buf */ - check_pollclosed_immediate_write(writefd, readfd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); } ATF_TC(pollclosed_fifo0_immediate_readsome); @@ -1060,9 +1124,13 @@ ATF_TC_BODY(pollclosed_fifo0_immediate_r { int writefd, readfd; + /* + * poll(2) returns nothing, when it is supposed to return + * POLLHUP|POLLIN. + */ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); - pollclosed_fifo1_setup(&writefd, &readfd); + pollclosed_fifo1_setup(&writefd, &readfd); /* reverse r/w */ fillpipebuf(writefd); check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP); } @@ -1077,7 +1145,7 @@ ATF_TC_BODY(pollclosed_fifo0_immediate_r { int writefd, readfd; - pollclosed_fifo1_setup(&writefd, &readfd); + pollclosed_fifo1_setup(&writefd, &readfd); /* reverse r/w */ /* don't fill the pipe buf */ check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP); } @@ -1095,7 +1163,7 @@ ATF_TC_BODY(pollclosed_fifo0_delayed_pro pollclosed_fifo0_setup(&writefd, &readfd); fillpipebuf(writefd); check_pollclosed_delayed_process(writefd, readfd, - &check_pollclosed_delayed_write); + &check_pollclosed_delayed_write_fifopipesocket); } ATF_TC(pollclosed_fifo0_delayed_process_read); @@ -1108,12 +1176,17 @@ ATF_TC_BODY(pollclosed_fifo0_delayed_pro { int writefd, readfd; + /* + * poll(2) wakes up with POLLHUP|POLLIN, but the state isn't + * persistent as it is supposed to be -- it returns nothing + * after that. + */ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); - pollclosed_fifo1_setup(&writefd, &readfd); + pollclosed_fifo1_setup(&writefd, &readfd); /* reverse r/w */ /* don't fill pipe buf */ check_pollclosed_delayed_process(readfd, writefd, - &check_pollclosed_delayed_read_pipefifo); + &check_pollclosed_delayed_read_devfifopipe); } ATF_TC(pollclosed_fifo0_delayed_thread_write); @@ -1129,7 +1202,7 @@ ATF_TC_BODY(pollclosed_fifo0_delayed_thr pollclosed_fifo0_setup(&writefd, &readfd); fillpipebuf(writefd); check_pollclosed_delayed_thread(writefd, readfd, - &check_pollclosed_delayed_write); + &check_pollclosed_delayed_write_fifopipesocket); } ATF_TC(pollclosed_fifo0_delayed_thread_read); @@ -1142,12 +1215,17 @@ ATF_TC_BODY(pollclosed_fifo0_delayed_thr { int writefd, readfd; + /* + * poll(2) wakes up with POLLHUP|POLLIN, but the state isn't + * persistent as it is supposed to be -- it returns nothing + * after that. + */ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); - pollclosed_fifo1_setup(&writefd, &readfd); + pollclosed_fifo1_setup(&writefd, &readfd); /* reverse r/w */ /* don't fill pipe buf */ check_pollclosed_delayed_thread(readfd, writefd, - &check_pollclosed_delayed_read_pipefifo); + &check_pollclosed_delayed_read_devfifopipe); } ATF_TC(pollclosed_fifo1_immediate_writefull); @@ -1162,7 +1240,7 @@ ATF_TC_BODY(pollclosed_fifo1_immediate_w pollclosed_fifo1_setup(&writefd, &readfd); fillpipebuf(writefd); - check_pollclosed_immediate_write(writefd, readfd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); } ATF_TC(pollclosed_fifo1_immediate_writeempty); @@ -1177,7 +1255,7 @@ ATF_TC_BODY(pollclosed_fifo1_immediate_w pollclosed_fifo1_setup(&writefd, &readfd); /* don't fill the pipe buf */ - check_pollclosed_immediate_write(writefd, readfd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); } ATF_TC(pollclosed_fifo1_immediate_readsome); @@ -1190,9 +1268,13 @@ ATF_TC_BODY(pollclosed_fifo1_immediate_r { int writefd, readfd; + /* + * poll(2) returns nothing, when it is supposed to return + * POLLHUP|POLLIN. + */ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); - pollclosed_fifo1_setup(&writefd, &readfd); + pollclosed_fifo0_setup(&writefd, &readfd); /* reverse r/w */ fillpipebuf(writefd); check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP); } @@ -1207,7 +1289,7 @@ ATF_TC_BODY(pollclosed_fifo1_immediate_r { int writefd, readfd; - pollclosed_fifo1_setup(&writefd, &readfd); + pollclosed_fifo0_setup(&writefd, &readfd); /* reverse r/w */ /* don't fill the pipe buf */ check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP); } @@ -1225,7 +1307,7 @@ ATF_TC_BODY(pollclosed_fifo1_delayed_pro pollclosed_fifo1_setup(&writefd, &readfd); fillpipebuf(writefd); check_pollclosed_delayed_process(writefd, readfd, - &check_pollclosed_delayed_write); + &check_pollclosed_delayed_write_fifopipesocket); } ATF_TC(pollclosed_fifo1_delayed_process_read); @@ -1238,12 +1320,17 @@ ATF_TC_BODY(pollclosed_fifo1_delayed_pro { int writefd, readfd; + /* + * poll(2) wakes up with POLLHUP|POLLIN, but the state isn't + * persistent as it is supposed to be -- it returns nothing + * after that. + */ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); - pollclosed_fifo0_setup(&writefd, &readfd); + pollclosed_fifo0_setup(&writefd, &readfd); /* reverse r/w */ /* don't fill pipe buf */ check_pollclosed_delayed_process(readfd, writefd, - &check_pollclosed_delayed_read_pipefifo); + &check_pollclosed_delayed_read_devfifopipe); } ATF_TC(pollclosed_fifo1_delayed_thread_write); @@ -1259,7 +1346,7 @@ ATF_TC_BODY(pollclosed_fifo1_delayed_thr pollclosed_fifo1_setup(&writefd, &readfd); fillpipebuf(writefd); check_pollclosed_delayed_thread(writefd, readfd, - &check_pollclosed_delayed_write); + &check_pollclosed_delayed_write_fifopipesocket); } ATF_TC(pollclosed_fifo1_delayed_thread_read); @@ -1272,12 +1359,17 @@ ATF_TC_BODY(pollclosed_fifo1_delayed_thr { int writefd, readfd; + /* + * poll(2) wakes up with POLLHUP|POLLIN, but the state isn't + * persistent as it is supposed to be -- it returns nothing + * after that. + */ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); - pollclosed_fifo0_setup(&writefd, &readfd); + pollclosed_fifo0_setup(&writefd, &readfd); /* reverse r/w */ /* don't fill pipe buf */ check_pollclosed_delayed_process(readfd, writefd, - &check_pollclosed_delayed_read_pipefifo); + &check_pollclosed_delayed_read_devfifopipe); } ATF_TC(pollclosed_pipe_immediate_writefull); @@ -1290,11 +1382,17 @@ ATF_TC_BODY(pollclosed_pipe_immediate_wr { int writefd, readfd; + /* + * poll(2) returns POLLHUP|POLLOUT, which is forbidden -- + * POLLHUP and POLLOUT are mutually exclusive. And POLLHUP is + * only supposed to be returned by polling for read, not + * polling for write. So it should be POLLOUT. + */ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); pollclosed_pipe_setup(&writefd, &readfd); fillpipebuf(writefd); - check_pollclosed_immediate_write(writefd, readfd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); } ATF_TC(pollclosed_pipe_immediate_writeempty); @@ -1307,11 +1405,17 @@ ATF_TC_BODY(pollclosed_pipe_immediate_wr { int writefd, readfd; + /* + * poll(2) returns POLLHUP|POLLOUT, which is forbidden -- + * POLLHUP and POLLOUT are mutually exclusive. And POLLHUP is + * only supposed to be returned by polling for read, not + * polling for write. So it should be POLLOUT. + */ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); pollclosed_pipe_setup(&writefd, &readfd); /* don't fill pipe buf */ - check_pollclosed_immediate_write(writefd, readfd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); } ATF_TC(pollclosed_pipe_immediate_readsome); @@ -1354,12 +1458,18 @@ ATF_TC_BODY(pollclosed_pipe_delayed_proc { int writefd, readfd; + /* + * poll(2) returns POLLHUP|POLLOUT, which is forbidden -- + * POLLHUP and POLLOUT are mutually exclusive. And POLLHUP is + * only supposed to be returned by polling for read, not + * polling for write. So it should be POLLOUT. + */ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); pollclosed_pipe_setup(&writefd, &readfd); fillpipebuf(writefd); check_pollclosed_delayed_process(writefd, readfd, - &check_pollclosed_delayed_write); + &check_pollclosed_delayed_write_fifopipesocket); } ATF_TC(pollclosed_pipe_delayed_process_read); @@ -1375,7 +1485,7 @@ ATF_TC_BODY(pollclosed_pipe_delayed_proc pollclosed_pipe_setup(&writefd, &readfd); /* don't fill pipe buf */ check_pollclosed_delayed_process(readfd, writefd, - &check_pollclosed_delayed_read_pipefifo); + &check_pollclosed_delayed_read_devfifopipe); } ATF_TC(pollclosed_pipe_delayed_thread_write); @@ -1388,12 +1498,18 @@ ATF_TC_BODY(pollclosed_pipe_delayed_thre { int writefd, readfd; + /* + * poll(2) returns POLLHUP|POLLOUT, which is forbidden -- + * POLLHUP and POLLOUT are mutually exclusive. And POLLHUP is + * only supposed to be returned by polling for read, not + * polling for write. So it should be POLLOUT. + */ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); pollclosed_pipe_setup(&writefd, &readfd); fillpipebuf(writefd); check_pollclosed_delayed_thread(writefd, readfd, - &check_pollclosed_delayed_write); + &check_pollclosed_delayed_write_fifopipesocket); } ATF_TC(pollclosed_pipe_delayed_thread_read); @@ -1409,7 +1525,315 @@ ATF_TC_BODY(pollclosed_pipe_delayed_thre pollclosed_pipe_setup(&writefd, &readfd); /* don't fill pipe buf */ check_pollclosed_delayed_thread(readfd, writefd, - &check_pollclosed_delayed_read_pipefifo); + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_ptyapp_immediate_writefull); +ATF_TC_HEAD(pollclosed_ptyapp_immediate_writefull, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_immediate_writefull, tc) +{ + int writefd, readfd; + + pollclosed_ptyapp_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_immediate_write(writefd, readfd, POLLHUP, EIO); +} + +ATF_TC(pollclosed_ptyapp_immediate_writeempty); +ATF_TC_HEAD(pollclosed_ptyapp_immediate_writeempty, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_immediate_writeempty, tc) +{ + int writefd, readfd; + + pollclosed_ptyapp_setup(&writefd, &readfd); + /* don't fill the pipe buf */ + check_pollclosed_immediate_write(writefd, readfd, POLLHUP, EIO); +} + +ATF_TC(pollclosed_ptyapp_immediate_readsome); +ATF_TC_HEAD(pollclosed_ptyapp_immediate_readsome, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_immediate_readsome, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyhost_setup(&writefd, &readfd); /* reverse r/w */ + fillpipebuf(writefd); + check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_ptyapp_immediate_readnone); +ATF_TC_HEAD(pollclosed_ptyapp_immediate_readnone, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_immediate_readnone, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyhost_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill the pipe buf */ + check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_ptyapp_delayed_process_write); +ATF_TC_HEAD(pollclosed_ptyapp_delayed_process_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_delayed_process_write, tc) +{ + int writefd, readfd; + + /* + * The poll(2) call is not woken by the concurrent close(2) + * call. + */ + atf_tc_expect_signal(SIGALRM, "PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyapp_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_process(writefd, readfd, + &check_pollclosed_delayed_write_terminal); +} + +ATF_TC(pollclosed_ptyapp_delayed_process_read); +ATF_TC_HEAD(pollclosed_ptyapp_delayed_process_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_delayed_process_read, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyhost_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_process(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_ptyapp_delayed_thread_write); +ATF_TC_HEAD(pollclosed_ptyapp_delayed_thread_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_delayed_thread_write, tc) +{ + int writefd, readfd; + + /* + * The poll(2) call is not woken by the concurrent close(2) + * call. + */ + atf_tc_expect_signal(SIGALRM, "PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyapp_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_thread(writefd, readfd, + &check_pollclosed_delayed_write_terminal); +} + +ATF_TC(pollclosed_ptyapp_delayed_thread_read); +ATF_TC_HEAD(pollclosed_ptyapp_delayed_thread_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty application side"); +} +ATF_TC_BODY(pollclosed_ptyapp_delayed_thread_read, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyhost_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_process(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_ptyhost_immediate_writefull); +ATF_TC_HEAD(pollclosed_ptyhost_immediate_writefull, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_immediate_writefull, tc) +{ + int writefd, readfd; + + pollclosed_ptyhost_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_immediate_write(writefd, readfd, POLLHUP, EIO); +} + +ATF_TC(pollclosed_ptyhost_immediate_writeempty); +ATF_TC_HEAD(pollclosed_ptyhost_immediate_writeempty, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_immediate_writeempty, tc) +{ + int writefd, readfd; + + pollclosed_ptyhost_setup(&writefd, &readfd); + /* don't fill the pipe buf */ + check_pollclosed_immediate_write(writefd, readfd, POLLHUP, EIO); +} + +ATF_TC(pollclosed_ptyhost_immediate_readsome); +ATF_TC_HEAD(pollclosed_ptyhost_immediate_readsome, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_immediate_readsome, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyapp_setup(&writefd, &readfd); /* reverse r/w */ + fillpipebuf(writefd); + check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_ptyhost_immediate_readnone); +ATF_TC_HEAD(pollclosed_ptyhost_immediate_readnone, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_immediate_readnone, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyapp_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill the pipe buf */ + check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP); +} + +ATF_TC(pollclosed_ptyhost_delayed_process_write); +ATF_TC_HEAD(pollclosed_ptyhost_delayed_process_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_delayed_process_write, tc) +{ + int writefd, readfd; + + pollclosed_ptyhost_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_process(writefd, readfd, + &check_pollclosed_delayed_write_terminal); +} + +ATF_TC(pollclosed_ptyhost_delayed_process_read); +ATF_TC_HEAD(pollclosed_ptyhost_delayed_process_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_delayed_process_read, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyapp_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_process(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); +} + +ATF_TC(pollclosed_ptyhost_delayed_thread_write); +ATF_TC_HEAD(pollclosed_ptyhost_delayed_thread_write, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_delayed_thread_write, tc) +{ + int writefd, readfd; + + pollclosed_ptyhost_setup(&writefd, &readfd); + fillpipebuf(writefd); + check_pollclosed_delayed_thread(writefd, readfd, + &check_pollclosed_delayed_write_terminal); +} + +ATF_TC(pollclosed_ptyhost_delayed_thread_read); +ATF_TC_HEAD(pollclosed_ptyhost_delayed_thread_read, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks POLLHUP with closing the pty host side"); +} +ATF_TC_BODY(pollclosed_ptyhost_delayed_thread_read, tc) +{ + int writefd, readfd; + + /* + * poll(2) returns POLLHUP but not POLLIN even though read(2) + * would return EOF without blocking. + */ + atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs"); + + pollclosed_ptyapp_setup(&writefd, &readfd); /* reverse r/w */ + /* don't fill pipe buf */ + check_pollclosed_delayed_thread(readfd, writefd, + &check_pollclosed_delayed_read_devfifopipe); } ATF_TC(pollclosed_socketpair0_immediate_writefull); @@ -1424,7 +1848,7 @@ ATF_TC_BODY(pollclosed_socketpair0_immed pollclosed_socketpair0_setup(&writefd, &readfd); fillpipebuf(writefd); - check_pollclosed_immediate_write(writefd, readfd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); } ATF_TC(pollclosed_socketpair0_immediate_writeempty); @@ -1439,7 +1863,7 @@ ATF_TC_BODY(pollclosed_socketpair0_immed pollclosed_socketpair0_setup(&writefd, &readfd); /* don't fill the pipe buf */ - check_pollclosed_immediate_write(writefd, readfd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); } ATF_TC(pollclosed_socketpair0_immediate_readsome); @@ -1452,7 +1876,7 @@ ATF_TC_BODY(pollclosed_socketpair0_immed { int writefd, readfd; - pollclosed_socketpair1_setup(&writefd, &readfd); + pollclosed_socketpair1_setup(&writefd, &readfd); /* reverse r/w */ fillpipebuf(writefd); check_pollclosed_immediate_readsome(readfd, writefd, /*no POLLHUP*/0); } @@ -1467,7 +1891,7 @@ ATF_TC_BODY(pollclosed_socketpair0_immed { int writefd, readfd; - pollclosed_socketpair1_setup(&writefd, &readfd); + pollclosed_socketpair1_setup(&writefd, &readfd); /* reverse r/w */ /* don't fill the pipe buf */ check_pollclosed_immediate_readnone(readfd, writefd, /*no POLLHUP*/0); } @@ -1485,7 +1909,7 @@ ATF_TC_BODY(pollclosed_socketpair0_delay pollclosed_socketpair0_setup(&writefd, &readfd); fillpipebuf(writefd); check_pollclosed_delayed_process(writefd, readfd, - &check_pollclosed_delayed_write); + &check_pollclosed_delayed_write_fifopipesocket); } ATF_TC(pollclosed_socketpair0_delayed_process_read); @@ -1498,7 +1922,7 @@ ATF_TC_BODY(pollclosed_socketpair0_delay { int writefd, readfd; - pollclosed_socketpair1_setup(&writefd, &readfd); + pollclosed_socketpair1_setup(&writefd, &readfd); /* reverse r/w */ /* don't fill pipe buf */ check_pollclosed_delayed_process(readfd, writefd, &check_pollclosed_delayed_read_socket); @@ -1517,7 +1941,7 @@ ATF_TC_BODY(pollclosed_socketpair0_delay pollclosed_socketpair0_setup(&writefd, &readfd); fillpipebuf(writefd); check_pollclosed_delayed_thread(writefd, readfd, - &check_pollclosed_delayed_write); + &check_pollclosed_delayed_write_fifopipesocket); } ATF_TC(pollclosed_socketpair0_delayed_thread_read); @@ -1530,7 +1954,7 @@ ATF_TC_BODY(pollclosed_socketpair0_delay { int writefd, readfd; - pollclosed_socketpair1_setup(&writefd, &readfd); + pollclosed_socketpair1_setup(&writefd, &readfd); /* reverse r/w */ /* don't fill pipe buf */ check_pollclosed_delayed_thread(readfd, writefd, &check_pollclosed_delayed_read_socket); @@ -1548,7 +1972,7 @@ ATF_TC_BODY(pollclosed_socketpair1_immed pollclosed_socketpair1_setup(&writefd, &readfd); fillpipebuf(writefd); - check_pollclosed_immediate_write(writefd, readfd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); } ATF_TC(pollclosed_socketpair1_immediate_writeempty); @@ -1563,7 +1987,7 @@ ATF_TC_BODY(pollclosed_socketpair1_immed pollclosed_socketpair1_setup(&writefd, &readfd); /* don't fill the pipe buf */ - check_pollclosed_immediate_write(writefd, readfd); + check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE); } ATF_TC(pollclosed_socketpair1_immediate_readsome); @@ -1576,7 +2000,7 @@ ATF_TC_BODY(pollclosed_socketpair1_immed { int writefd, readfd; - pollclosed_socketpair0_setup(&writefd, &readfd); + pollclosed_socketpair0_setup(&writefd, &readfd); /* reverse r/w */ fillpipebuf(writefd); check_pollclosed_immediate_readsome(readfd, writefd, /*no POLLHUP*/0); } @@ -1591,7 +2015,7 @@ ATF_TC_BODY(pollclosed_socketpair1_immed { int writefd, readfd; - pollclosed_socketpair0_setup(&writefd, &readfd); + pollclosed_socketpair0_setup(&writefd, &readfd); /* reverse r/w */ /* don't fill the pipe buf */ check_pollclosed_immediate_readnone(readfd, writefd, /*no POLLHUP*/0); } @@ -1609,7 +2033,7 @@ ATF_TC_BODY(pollclosed_socketpair1_delay pollclosed_socketpair1_setup(&writefd, &readfd); fillpipebuf(writefd); check_pollclosed_delayed_process(writefd, readfd, - &check_pollclosed_delayed_write); + &check_pollclosed_delayed_write_fifopipesocket); } ATF_TC(pollclosed_socketpair1_delayed_process_read); @@ -1622,7 +2046,7 @@ ATF_TC_BODY(pollclosed_socketpair1_delay { int writefd, readfd; - pollclosed_socketpair0_setup(&writefd, &readfd); + pollclosed_socketpair0_setup(&writefd, &readfd); /* reverse r/w */ /* don't fill pipe buf */ check_pollclosed_delayed_process(readfd, writefd, &check_pollclosed_delayed_read_socket); @@ -1641,7 +2065,7 @@ ATF_TC_BODY(pollclosed_socketpair1_delay pollclosed_socketpair1_setup(&writefd, &readfd); fillpipebuf(writefd); check_pollclosed_delayed_thread(writefd, readfd, - &check_pollclosed_delayed_write); + &check_pollclosed_delayed_write_fifopipesocket); } ATF_TC(pollclosed_socketpair1_delayed_thread_read); @@ -1654,7 +2078,7 @@ ATF_TC_BODY(pollclosed_socketpair1_delay { int writefd, readfd; - pollclosed_socketpair0_setup(&writefd, &readfd); + pollclosed_socketpair0_setup(&writefd, &readfd); /* reverse r/w */ /* don't fill pipe buf */ check_pollclosed_delayed_process(readfd, writefd, &check_pollclosed_delayed_read_socket); @@ -1674,48 +2098,64 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, pollclosed_fifo0_immediate_writefull); ATF_TP_ADD_TC(tp, pollclosed_fifo1_immediate_writefull); ATF_TP_ADD_TC(tp, pollclosed_pipe_immediate_writefull); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_immediate_writefull); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_immediate_writefull); ATF_TP_ADD_TC(tp, pollclosed_socketpair0_immediate_writefull); ATF_TP_ADD_TC(tp, pollclosed_socketpair1_immediate_writefull); ATF_TP_ADD_TC(tp, pollclosed_fifo0_immediate_writeempty); ATF_TP_ADD_TC(tp, pollclosed_fifo1_immediate_writeempty); ATF_TP_ADD_TC(tp, pollclosed_pipe_immediate_writeempty); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_immediate_writeempty); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_immediate_writeempty); ATF_TP_ADD_TC(tp, pollclosed_socketpair0_immediate_writeempty); ATF_TP_ADD_TC(tp, pollclosed_socketpair1_immediate_writeempty); ATF_TP_ADD_TC(tp, pollclosed_fifo0_immediate_readsome); ATF_TP_ADD_TC(tp, pollclosed_fifo1_immediate_readsome); ATF_TP_ADD_TC(tp, pollclosed_pipe_immediate_readsome); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_immediate_readsome); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_immediate_readsome); ATF_TP_ADD_TC(tp, pollclosed_socketpair0_immediate_readsome); ATF_TP_ADD_TC(tp, pollclosed_socketpair1_immediate_readsome); ATF_TP_ADD_TC(tp, pollclosed_fifo0_immediate_readnone); ATF_TP_ADD_TC(tp, pollclosed_fifo1_immediate_readnone); ATF_TP_ADD_TC(tp, pollclosed_pipe_immediate_readnone); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_immediate_readnone); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_immediate_readnone); ATF_TP_ADD_TC(tp, pollclosed_socketpair0_immediate_readnone); ATF_TP_ADD_TC(tp, pollclosed_socketpair1_immediate_readnone); ATF_TP_ADD_TC(tp, pollclosed_fifo0_delayed_process_write); ATF_TP_ADD_TC(tp, pollclosed_fifo1_delayed_process_write); ATF_TP_ADD_TC(tp, pollclosed_pipe_delayed_process_write); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_delayed_process_write); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_delayed_process_write); ATF_TP_ADD_TC(tp, pollclosed_socketpair0_delayed_process_write); ATF_TP_ADD_TC(tp, pollclosed_socketpair1_delayed_process_write); ATF_TP_ADD_TC(tp, pollclosed_fifo0_delayed_process_read); ATF_TP_ADD_TC(tp, pollclosed_fifo1_delayed_process_read); ATF_TP_ADD_TC(tp, pollclosed_pipe_delayed_process_read); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_delayed_process_read); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_delayed_process_read); ATF_TP_ADD_TC(tp, pollclosed_socketpair0_delayed_process_read); ATF_TP_ADD_TC(tp, pollclosed_socketpair1_delayed_process_read); ATF_TP_ADD_TC(tp, pollclosed_fifo0_delayed_thread_write); ATF_TP_ADD_TC(tp, pollclosed_fifo1_delayed_thread_write); ATF_TP_ADD_TC(tp, pollclosed_pipe_delayed_thread_write); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_delayed_thread_write); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_delayed_thread_write); ATF_TP_ADD_TC(tp, pollclosed_socketpair0_delayed_thread_write); ATF_TP_ADD_TC(tp, pollclosed_socketpair1_delayed_thread_write); ATF_TP_ADD_TC(tp, pollclosed_fifo0_delayed_thread_read); ATF_TP_ADD_TC(tp, pollclosed_fifo1_delayed_thread_read); ATF_TP_ADD_TC(tp, pollclosed_pipe_delayed_thread_read); + ATF_TP_ADD_TC(tp, pollclosed_ptyapp_delayed_thread_read); + ATF_TP_ADD_TC(tp, pollclosed_ptyhost_delayed_thread_read); ATF_TP_ADD_TC(tp, pollclosed_socketpair0_delayed_thread_read); ATF_TP_ADD_TC(tp, pollclosed_socketpair1_delayed_thread_read);