1195636Skib/* $FreeBSD$ */ 2195636Skib 3195636Skib#include <sys/socket.h> 4195636Skib#include <sys/select.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 20195636Skib#define SETUP(fd, rfds, tv) do { \ 21195636Skib FD_ZERO(&(rfds)); \ 22195636Skib FD_SET((fd), &(rfds)); \ 23195636Skib (tv).tv_sec = 0; \ 24195636Skib (tv).tv_usec = 0; \ 25195636Skib} while (0) 26195636Skib 27195636Skibstatic int filetype; 28195636Skib 29195636Skibstatic const char * 30195636Skibdecode_events(int events) 31195636Skib{ 32195636Skib return (events ? "set" : "clear"); 33195636Skib} 34195636Skib 35195636Skibstatic void 36195636Skibreport(int num, const char *state, int expected, int got) 37195636Skib{ 38195636Skib if (!expected == !got) 39195636Skib printf("ok %-2d ", num); 40195636Skib else 41195636Skib printf("not ok %-2d", num); 42195636Skib printf(" %s state %s: expected %s; got %s\n", 43195636Skib filetype == FT_PIPE ? "Pipe" : 44195636Skib filetype == FT_SOCKETPAIR ? "Sock" : "FIFO", 45195636Skib state, decode_events(expected), decode_events(got)); 46195636Skib fflush(stdout); 47195636Skib} 48195636Skib 49195636Skibstatic pid_t cpid; 50195636Skibstatic pid_t ppid; 51195636Skibstatic volatile sig_atomic_t state; 52195636Skib 53195636Skibstatic void 54195636Skibcatch(int sig) 55195636Skib{ 56195636Skib state++; 57195636Skib} 58195636Skib 59195636Skibstatic void 60195636Skibchild(int fd, int num) 61195636Skib{ 62195636Skib fd_set rfds; 63195636Skib struct timeval tv; 64195636Skib int fd1, fd2; 65195636Skib char buf[256]; 66195636Skib 67195636Skib if (filetype == FT_FIFO) { 68195636Skib fd = open(FIFONAME, O_RDONLY | O_NONBLOCK); 69195636Skib if (fd < 0) 70195636Skib err(1, "open for read"); 71195636Skib } 72195636Skib if (fd >= FD_SETSIZE) 73195636Skib errx(1, "fd = %d too large for select()", fd); 74195636Skib 75195636Skib if (filetype == FT_FIFO) { 76195636Skib SETUP(fd, rfds, tv); 77195636Skib if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 78195636Skib err(1, "select"); 79195636Skib /* 80195636Skib * This state (a reader for which there has never been a 81195636Skib * writer) is reported quite differently for select() than 82195636Skib * for poll(). select() must see a ready-to-read descriptor 83195636Skib * since read() will see EOF and not block; it cannot 84195636Skib * distinguish this state from the one of a reader for which 85195636Skib * there has been a writer but all writers have gone away 86195636Skib * and all data has been read. poll() and distinguish these 87195636Skib * states by returning POLLHUP only for the latter; it does 88195636Skib * this, although this makes it inconsistent with the 89195636Skib * blockability of read() in the former. 90195636Skib */ 91195636Skib report(num++, "0", 1, FD_ISSET(fd, &rfds)); 92195636Skib } 93195636Skib kill(ppid, SIGUSR1); 94195636Skib 95195636Skib usleep(1); 96195636Skib while (state != 1) 97195636Skib ; 98195636Skib if (filetype != FT_FIFO) { 99195636Skib /* 100195636Skib * The connection cannot be reestablished. Use the code that 101195636Skib * delays the read until after the writer disconnects since 102195636Skib * that case is more interesting. 103195636Skib */ 104195636Skib state = 4; 105195636Skib goto state4; 106195636Skib } 107195636Skib SETUP(fd, rfds, tv); 108195636Skib if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 109195636Skib err(1, "select"); 110195636Skib report(num++, "1", 0, FD_ISSET(fd, &rfds)); 111195636Skib kill(ppid, SIGUSR1); 112195636Skib 113195636Skib usleep(1); 114195636Skib while (state != 2) 115195636Skib ; 116195636Skib SETUP(fd, rfds, tv); 117195636Skib if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 118195636Skib err(1, "select"); 119195636Skib report(num++, "2", 1, FD_ISSET(fd, &rfds)); 120195636Skib if (read(fd, buf, sizeof buf) != 1) 121195636Skib err(1, "read"); 122195636Skib SETUP(fd, rfds, tv); 123195636Skib if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 124195636Skib err(1, "select"); 125195636Skib report(num++, "2a", 0, FD_ISSET(fd, &rfds)); 126195636Skib kill(ppid, SIGUSR1); 127195636Skib 128195636Skib usleep(1); 129195636Skib while (state != 3) 130195636Skib ; 131195636Skib SETUP(fd, rfds, tv); 132195636Skib if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 133195636Skib err(1, "select"); 134195636Skib report(num++, "3", 1, FD_ISSET(fd, &rfds)); 135195636Skib kill(ppid, SIGUSR1); 136195636Skib 137195636Skib /* 138195636Skib * Now we expect a new writer, and a new connection too since 139195636Skib * we read all the data. The only new point is that we didn't 140195636Skib * start quite from scratch since the read fd is not new. Check 141195636Skib * startup state as above, but don't do the read as above. 142195636Skib */ 143195636Skib usleep(1); 144195636Skib while (state != 4) 145195636Skib ; 146195636Skibstate4: 147195636Skib SETUP(fd, rfds, tv); 148195636Skib if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 149195636Skib err(1, "select"); 150195636Skib report(num++, "4", 0, FD_ISSET(fd, &rfds)); 151195636Skib kill(ppid, SIGUSR1); 152195636Skib 153195636Skib usleep(1); 154195636Skib while (state != 5) 155195636Skib ; 156195636Skib SETUP(fd, rfds, tv); 157195636Skib if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 158195636Skib err(1, "select"); 159195636Skib report(num++, "5", 1, FD_ISSET(fd, &rfds)); 160195636Skib kill(ppid, SIGUSR1); 161195636Skib 162195636Skib usleep(1); 163195636Skib while (state != 6) 164195636Skib ; 165195636Skib /* 166195636Skib * Now we have no writer, but should still have data from the old 167195636Skib * writer. Check that we have a data-readable condition, and that 168195636Skib * the data can be read in the usual way. 169195636Skib */ 170195636Skib SETUP(fd, rfds, tv); 171195636Skib if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 172195636Skib err(1, "select"); 173195636Skib report(num++, "6", 1, FD_ISSET(fd, &rfds)); 174195636Skib if (read(fd, buf, sizeof buf) != 1) 175195636Skib err(1, "read"); 176195636Skib SETUP(fd, rfds, tv); 177195636Skib if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 178195636Skib err(1, "select"); 179195636Skib report(num++, "6a", 1, FD_ISSET(fd, &rfds)); 180195636Skib if (filetype == FT_FIFO) { 181195636Skib /* 182195636Skib * Check that the readable-data condition is sticky for a 183195636Skib * new reader and for the old reader. We really only have 184195636Skib * a hangup condition, but select() can only see this as 185195636Skib * a readable-data condition for null data. select() 186195636Skib * cannot distinguish this state from the initial state 187195636Skib * where there is a reader but has never been a writer, so 188195636Skib * the following tests (to follow the pattern in pipepoll.c) 189195636Skib * essentially test state 0 again. 190195636Skib */ 191195636Skib fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK); 192195636Skib if (fd2 < 0) 193195636Skib err(1, "open for read"); 194195636Skib fd1 = fd; 195195636Skib fd = fd2; 196195636Skib SETUP(fd, rfds, tv); 197195636Skib if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 198195636Skib err(1, "select"); 199195636Skib report(num++, "6b", 1, FD_ISSET(fd, &rfds)); 200195636Skib fd = fd1; 201195636Skib SETUP(fd, rfds, tv); 202195636Skib if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 203195636Skib err(1, "select"); 204195636Skib report(num++, "6c", 1, FD_ISSET(fd, &rfds)); 205195636Skib close(fd2); 206195636Skib SETUP(fd, rfds, tv); 207195636Skib if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 208195636Skib err(1, "select"); 209195636Skib report(num++, "6d", 1, FD_ISSET(fd, &rfds)); 210195636Skib } 211195636Skib close(fd); 212195636Skib kill(ppid, SIGUSR1); 213195636Skib 214195636Skib exit(0); 215195636Skib} 216195636Skib 217195636Skibstatic void 218195636Skibparent(int fd) 219195636Skib{ 220195636Skib usleep(1); 221195636Skib while (state != 1) 222195636Skib ; 223195636Skib if (filetype == FT_FIFO) { 224195636Skib fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); 225195636Skib if (fd < 0) 226195636Skib err(1, "open for write"); 227195636Skib } 228195636Skib kill(cpid, SIGUSR1); 229195636Skib 230195636Skib usleep(1); 231195636Skib while (state != 2) 232195636Skib ; 233195636Skib if (write(fd, "", 1) != 1) 234195636Skib err(1, "write"); 235195636Skib kill(cpid, SIGUSR1); 236195636Skib 237195636Skib usleep(1); 238195636Skib while (state != 3) 239195636Skib ; 240195636Skib if (close(fd) != 0) 241195636Skib err(1, "close for write"); 242195636Skib kill(cpid, SIGUSR1); 243195636Skib 244195636Skib usleep(1); 245195636Skib while (state != 4) 246195636Skib ; 247195636Skib if (filetype != FT_FIFO) 248195636Skib return; 249195636Skib fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); 250195636Skib if (fd < 0) 251195636Skib err(1, "open for write"); 252195636Skib kill(cpid, SIGUSR1); 253195636Skib 254195636Skib usleep(1); 255195636Skib while (state != 5) 256195636Skib ; 257195636Skib if (write(fd, "", 1) != 1) 258195636Skib err(1, "write"); 259195636Skib kill(cpid, SIGUSR1); 260195636Skib 261195636Skib usleep(1); 262195636Skib while (state != 6) 263195636Skib ; 264195636Skib if (close(fd) != 0) 265195636Skib err(1, "close for write"); 266195636Skib kill(cpid, SIGUSR1); 267195636Skib 268195636Skib usleep(1); 269195636Skib while (state != 7) 270195636Skib ; 271195636Skib} 272195636Skib 273195636Skibint 274195636Skibmain(void) 275195636Skib{ 276195636Skib int fd[2], num; 277195636Skib 278195636Skib num = 1; 279195636Skib printf("1..20\n"); 280195636Skib fflush(stdout); 281195636Skib signal(SIGUSR1, catch); 282195636Skib ppid = getpid(); 283195636Skib for (filetype = 0; filetype < FT_END; filetype++) { 284195636Skib switch (filetype) { 285195636Skib case FT_FIFO: 286195636Skib if (mkfifo(FIFONAME, 0666) != 0) 287195636Skib err(1, "mkfifo"); 288195636Skib fd[0] = -1; 289195636Skib fd[1] = -1; 290195636Skib break; 291195636Skib case FT_SOCKETPAIR: 292195636Skib if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC, 293195636Skib fd) != 0) 294195636Skib err(1, "socketpair"); 295195636Skib break; 296195636Skib case FT_PIPE: 297195636Skib if (pipe(fd) != 0) 298195636Skib err(1, "pipe"); 299195636Skib break; 300195636Skib } 301195636Skib state = 0; 302195636Skib switch (cpid = fork()) { 303195636Skib case -1: 304195636Skib err(1, "fork"); 305195636Skib case 0: 306195636Skib (void)close(fd[1]); 307195636Skib child(fd[0], num); 308195636Skib break; 309195636Skib default: 310195636Skib (void)close(fd[0]); 311195636Skib parent(fd[1]); 312195636Skib break; 313195636Skib } 314195636Skib num += filetype == FT_FIFO ? 12 : 4; 315195636Skib } 316195636Skib (void)unlink(FIFONAME); 317195636Skib return (0); 318195636Skib} 319