1195636Skib/* $FreeBSD$ */ 2195636Skib 3195636Skib#include <sys/poll.h> 4195636Skib#include <sys/socket.h> 5195636Skib#include <sys/stat.h> 6195636Skib 7195636Skib#include <err.h> 8195636Skib#include <fcntl.h> 9195636Skib#include <signal.h> 10195636Skib#include <stdio.h> 11195636Skib#include <stdlib.h> 12195636Skib#include <unistd.h> 13195636Skib 14195636Skib#define FIFONAME "fifo.tmp" 15195636Skib#define FT_END 3 16195636Skib#define FT_FIFO 2 17195636Skib#define FT_PIPE 0 18195636Skib#define FT_SOCKETPAIR 1 19195636Skib 20195636Skibstatic int filetype; 21195636Skib 22195636Skibstatic const char * 23195636Skibdecode_events(int events) 24195636Skib{ 25195636Skib char *ncresult; 26195636Skib const char *result; 27195636Skib 28195636Skib switch (events) { 29195636Skib case POLLIN: 30195636Skib result = "POLLIN"; 31195636Skib break; 32195636Skib case POLLHUP: 33195636Skib result = "POLLHUP"; 34195636Skib break; 35195636Skib case POLLIN | POLLHUP: 36195636Skib result = "POLLIN | POLLHUP"; 37195636Skib break; 38195636Skib default: 39195636Skib asprintf(&ncresult, "%#x", events); 40195636Skib result = ncresult; 41195636Skib break; 42195636Skib } 43195636Skib return (result); 44195636Skib} 45195636Skib 46195636Skibstatic void 47211940Skibreport_state(const char *state) 48195636Skib{ 49211940Skib 50211940Skib printf(" %s state %s: ", 51195636Skib filetype == FT_PIPE ? "Pipe" : 52195636Skib filetype == FT_SOCKETPAIR ? "Sock" : "FIFO", 53211940Skib state); 54211940Skib} 55211940Skib 56211940Skibstatic void 57211940Skibreport(int num, const char *state, int expected, int got, int res, 58211940Skib int res_expected) 59211940Skib{ 60211940Skib 61211940Skib if (res != res_expected) { 62211940Skib printf("not ok %-2d", num); 63211940Skib report_state(state); 64211940Skib printf("poll result %d expected %d. ", 65211940Skib res, res_expected); 66211940Skib } else { 67211940Skib if (expected == got) 68211940Skib printf("ok %-2d ", num); 69211940Skib else 70211940Skib printf("not ok %-2d", num); 71211940Skib report_state(state); 72211940Skib } 73211940Skib printf("expected %s; got %s\n", decode_events(expected), 74211940Skib decode_events(got)); 75195636Skib fflush(stdout); 76195636Skib} 77195636Skib 78195636Skibstatic pid_t cpid; 79195636Skibstatic pid_t ppid; 80195636Skibstatic volatile sig_atomic_t state; 81195636Skib 82195636Skibstatic void 83211940Skibcatch(int sig __unused) 84195636Skib{ 85211940Skib 86195636Skib state++; 87195636Skib} 88195636Skib 89195636Skibstatic void 90195636Skibchild(int fd, int num) 91195636Skib{ 92195636Skib struct pollfd pfd; 93211940Skib int fd2, res; 94195636Skib char buf[256]; 95195636Skib 96195636Skib if (filetype == FT_FIFO) { 97195636Skib fd = open(FIFONAME, O_RDONLY | O_NONBLOCK); 98195636Skib if (fd < 0) 99195636Skib err(1, "open for read"); 100195636Skib } 101195636Skib pfd.fd = fd; 102195636Skib pfd.events = POLLIN; 103195636Skib 104195636Skib if (filetype == FT_FIFO) { 105211940Skib if ((res = poll(&pfd, 1, 0)) < 0) 106195636Skib err(1, "poll"); 107211940Skib report(num++, "0", 0, pfd.revents, res, 0); 108195636Skib } 109195636Skib kill(ppid, SIGUSR1); 110195636Skib 111195636Skib usleep(1); 112195636Skib while (state != 1) 113195636Skib ; 114195636Skib if (filetype != FT_FIFO) { 115195636Skib /* 116195636Skib * The connection cannot be reestablished. Use the code that 117195636Skib * delays the read until after the writer disconnects since 118195636Skib * that case is more interesting. 119195636Skib */ 120195636Skib state = 4; 121195636Skib goto state4; 122195636Skib } 123211940Skib if ((res = poll(&pfd, 1, 0)) < 0) 124195636Skib err(1, "poll"); 125211940Skib report(num++, "1", 0, pfd.revents, res, 0); 126195636Skib kill(ppid, SIGUSR1); 127195636Skib 128195636Skib usleep(1); 129195636Skib while (state != 2) 130195636Skib ; 131211940Skib if ((res = poll(&pfd, 1, 0)) < 0) 132195636Skib err(1, "poll"); 133211940Skib report(num++, "2", POLLIN, pfd.revents, res, 1); 134195636Skib if (read(fd, buf, sizeof buf) != 1) 135195636Skib err(1, "read"); 136211940Skib if ((res = poll(&pfd, 1, 0)) < 0) 137195636Skib err(1, "poll"); 138211940Skib report(num++, "2a", 0, pfd.revents, res, 0); 139195636Skib kill(ppid, SIGUSR1); 140195636Skib 141195636Skib usleep(1); 142195636Skib while (state != 3) 143195636Skib ; 144211940Skib if ((res = poll(&pfd, 1, 0)) < 0) 145195636Skib err(1, "poll"); 146211940Skib report(num++, "3", POLLHUP, pfd.revents, res, 1); 147195636Skib kill(ppid, SIGUSR1); 148195636Skib 149195636Skib /* 150195636Skib * Now we expect a new writer, and a new connection too since 151195636Skib * we read all the data. The only new point is that we didn't 152195636Skib * start quite from scratch since the read fd is not new. Check 153195636Skib * startup state as above, but don't do the read as above. 154195636Skib */ 155195636Skib usleep(1); 156195636Skib while (state != 4) 157195636Skib ; 158195636Skibstate4: 159211940Skib if ((res = poll(&pfd, 1, 0)) < 0) 160195636Skib err(1, "poll"); 161211940Skib report(num++, "4", 0, pfd.revents, res, 0); 162195636Skib kill(ppid, SIGUSR1); 163195636Skib 164195636Skib usleep(1); 165195636Skib while (state != 5) 166195636Skib ; 167211940Skib if ((res = poll(&pfd, 1, 0)) < 0) 168195636Skib err(1, "poll"); 169211940Skib report(num++, "5", POLLIN, pfd.revents, res, 1); 170195636Skib kill(ppid, SIGUSR1); 171195636Skib 172195636Skib usleep(1); 173195636Skib while (state != 6) 174195636Skib ; 175195636Skib /* 176195636Skib * Now we have no writer, but should still have data from the old 177195636Skib * writer. Check that we have both a data-readable condition and a 178195636Skib * hangup condition, and that the data can be read in the usual way. 179195636Skib * Since Linux does this, programs must not quit reading when they 180195636Skib * see POLLHUP; they must see POLLHUP without POLLIN (or another 181195636Skib * input condition) before they decide that there is EOF. gdb-6.1.1 182195636Skib * is an example of a broken program that quits on POLLHUP only -- 183195636Skib * see its event-loop.c. 184195636Skib */ 185211940Skib if ((res = poll(&pfd, 1, 0)) < 0) 186195636Skib err(1, "poll"); 187211940Skib report(num++, "6", POLLIN | POLLHUP, pfd.revents, res, 1); 188195636Skib if (read(fd, buf, sizeof buf) != 1) 189195636Skib err(1, "read"); 190211940Skib if ((res = poll(&pfd, 1, 0)) < 0) 191195636Skib err(1, "poll"); 192211940Skib report(num++, "6a", POLLHUP, pfd.revents, res, 1); 193195636Skib if (filetype == FT_FIFO) { 194195636Skib /* 195195636Skib * Check that POLLHUP is sticky for a new reader and for 196195636Skib * the old reader. 197195636Skib */ 198195636Skib fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK); 199195636Skib if (fd2 < 0) 200195636Skib err(1, "open for read"); 201195636Skib pfd.fd = fd2; 202211940Skib if ((res = poll(&pfd, 1, 0)) < 0) 203195636Skib err(1, "poll"); 204211940Skib report(num++, "6b", POLLHUP, pfd.revents, res, 1); 205195636Skib pfd.fd = fd; 206211940Skib if ((res = poll(&pfd, 1, 0)) < 0) 207195636Skib err(1, "poll"); 208211940Skib report(num++, "6c", POLLHUP, pfd.revents, res, 1); 209195636Skib close(fd2); 210211940Skib if ((res = poll(&pfd, 1, 0)) < 0) 211195636Skib err(1, "poll"); 212211940Skib report(num++, "6d", POLLHUP, pfd.revents, res, 1); 213195636Skib } 214195636Skib close(fd); 215195636Skib kill(ppid, SIGUSR1); 216195636Skib 217195636Skib exit(0); 218195636Skib} 219195636Skib 220195636Skibstatic void 221195636Skibparent(int fd) 222195636Skib{ 223195636Skib usleep(1); 224195636Skib while (state != 1) 225195636Skib ; 226195636Skib if (filetype == FT_FIFO) { 227195636Skib fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); 228195636Skib if (fd < 0) 229195636Skib err(1, "open for write"); 230195636Skib } 231195636Skib kill(cpid, SIGUSR1); 232195636Skib 233195636Skib usleep(1); 234195636Skib while (state != 2) 235195636Skib ; 236195636Skib if (write(fd, "", 1) != 1) 237195636Skib err(1, "write"); 238195636Skib kill(cpid, SIGUSR1); 239195636Skib 240195636Skib usleep(1); 241195636Skib while (state != 3) 242195636Skib ; 243195636Skib if (close(fd) != 0) 244195636Skib err(1, "close for write"); 245195636Skib kill(cpid, SIGUSR1); 246195636Skib 247195636Skib usleep(1); 248195636Skib while (state != 4) 249195636Skib ; 250195636Skib if (filetype != FT_FIFO) 251195636Skib return; 252195636Skib fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); 253195636Skib if (fd < 0) 254195636Skib err(1, "open for write"); 255195636Skib kill(cpid, SIGUSR1); 256195636Skib 257195636Skib usleep(1); 258195636Skib while (state != 5) 259195636Skib ; 260195636Skib if (write(fd, "", 1) != 1) 261195636Skib err(1, "write"); 262195636Skib kill(cpid, SIGUSR1); 263195636Skib 264195636Skib usleep(1); 265195636Skib while (state != 6) 266195636Skib ; 267195636Skib if (close(fd) != 0) 268195636Skib err(1, "close for write"); 269195636Skib kill(cpid, SIGUSR1); 270195636Skib 271195636Skib usleep(1); 272195636Skib while (state != 7) 273195636Skib ; 274195636Skib} 275195636Skib 276195636Skibint 277195636Skibmain(void) 278195636Skib{ 279195636Skib int fd[2], num; 280195636Skib 281195636Skib num = 1; 282195636Skib printf("1..20\n"); 283195636Skib fflush(stdout); 284195636Skib signal(SIGUSR1, catch); 285195636Skib ppid = getpid(); 286195636Skib for (filetype = 0; filetype < FT_END; filetype++) { 287195636Skib switch (filetype) { 288195636Skib case FT_FIFO: 289195636Skib if (mkfifo(FIFONAME, 0666) != 0) 290195636Skib err(1, "mkfifo"); 291195636Skib fd[0] = -1; 292195636Skib fd[1] = -1; 293195636Skib break; 294195636Skib case FT_SOCKETPAIR: 295195636Skib if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC, 296195636Skib fd) != 0) 297195636Skib err(1, "socketpair"); 298195636Skib break; 299195636Skib case FT_PIPE: 300195636Skib if (pipe(fd) != 0) 301195636Skib err(1, "pipe"); 302195636Skib break; 303195636Skib } 304195636Skib state = 0; 305195636Skib switch (cpid = fork()) { 306195636Skib case -1: 307195636Skib err(1, "fork"); 308195636Skib case 0: 309195636Skib (void)close(fd[1]); 310195636Skib child(fd[0], num); 311195636Skib break; 312195636Skib default: 313195636Skib (void)close(fd[0]); 314195636Skib parent(fd[1]); 315195636Skib break; 316195636Skib } 317195636Skib num += filetype == FT_FIFO ? 12 : 4; 318195636Skib } 319195636Skib (void)unlink(FIFONAME); 320195636Skib return (0); 321195636Skib} 322