15861f966SKonstantin Belousov /* $FreeBSD$ */ 25861f966SKonstantin Belousov 35861f966SKonstantin Belousov #include <sys/poll.h> 45861f966SKonstantin Belousov #include <sys/socket.h> 55861f966SKonstantin Belousov #include <sys/stat.h> 65861f966SKonstantin Belousov 75861f966SKonstantin Belousov #include <err.h> 85861f966SKonstantin Belousov #include <fcntl.h> 95861f966SKonstantin Belousov #include <signal.h> 105861f966SKonstantin Belousov #include <stdio.h> 115861f966SKonstantin Belousov #include <stdlib.h> 125861f966SKonstantin Belousov #include <unistd.h> 135861f966SKonstantin Belousov 145861f966SKonstantin Belousov #define FIFONAME "fifo.tmp" 155861f966SKonstantin Belousov #define FT_END 3 165861f966SKonstantin Belousov #define FT_FIFO 2 175861f966SKonstantin Belousov #define FT_PIPE 0 185861f966SKonstantin Belousov #define FT_SOCKETPAIR 1 195861f966SKonstantin Belousov 205861f966SKonstantin Belousov static int filetype; 215861f966SKonstantin Belousov 225861f966SKonstantin Belousov static const char * 235861f966SKonstantin Belousov decode_events(int events) 245861f966SKonstantin Belousov { 255861f966SKonstantin Belousov char *ncresult; 265861f966SKonstantin Belousov const char *result; 275861f966SKonstantin Belousov 285861f966SKonstantin Belousov switch (events) { 295861f966SKonstantin Belousov case POLLIN: 305861f966SKonstantin Belousov result = "POLLIN"; 315861f966SKonstantin Belousov break; 325861f966SKonstantin Belousov case POLLHUP: 335861f966SKonstantin Belousov result = "POLLHUP"; 345861f966SKonstantin Belousov break; 355861f966SKonstantin Belousov case POLLIN | POLLHUP: 365861f966SKonstantin Belousov result = "POLLIN | POLLHUP"; 375861f966SKonstantin Belousov break; 385861f966SKonstantin Belousov default: 395861f966SKonstantin Belousov asprintf(&ncresult, "%#x", events); 405861f966SKonstantin Belousov result = ncresult; 415861f966SKonstantin Belousov break; 425861f966SKonstantin Belousov } 435861f966SKonstantin Belousov return (result); 445861f966SKonstantin Belousov } 455861f966SKonstantin Belousov 465861f966SKonstantin Belousov static void 475861f966SKonstantin Belousov report(int num, const char *state, int expected, int got) 485861f966SKonstantin Belousov { 495861f966SKonstantin Belousov if (expected == got) 505861f966SKonstantin Belousov printf("ok %-2d ", num); 515861f966SKonstantin Belousov else 525861f966SKonstantin Belousov printf("not ok %-2d", num); 535861f966SKonstantin Belousov printf(" %s state %s: expected %s; got %s\n", 545861f966SKonstantin Belousov filetype == FT_PIPE ? "Pipe" : 555861f966SKonstantin Belousov filetype == FT_SOCKETPAIR ? "Sock" : "FIFO", 565861f966SKonstantin Belousov state, decode_events(expected), decode_events(got)); 575861f966SKonstantin Belousov fflush(stdout); 585861f966SKonstantin Belousov } 595861f966SKonstantin Belousov 605861f966SKonstantin Belousov static pid_t cpid; 615861f966SKonstantin Belousov static pid_t ppid; 625861f966SKonstantin Belousov static volatile sig_atomic_t state; 635861f966SKonstantin Belousov 645861f966SKonstantin Belousov static void 655861f966SKonstantin Belousov catch(int sig) 665861f966SKonstantin Belousov { 675861f966SKonstantin Belousov state++; 685861f966SKonstantin Belousov } 695861f966SKonstantin Belousov 705861f966SKonstantin Belousov static void 715861f966SKonstantin Belousov child(int fd, int num) 725861f966SKonstantin Belousov { 735861f966SKonstantin Belousov struct pollfd pfd; 745861f966SKonstantin Belousov int fd2; 755861f966SKonstantin Belousov char buf[256]; 765861f966SKonstantin Belousov 775861f966SKonstantin Belousov if (filetype == FT_FIFO) { 785861f966SKonstantin Belousov fd = open(FIFONAME, O_RDONLY | O_NONBLOCK); 795861f966SKonstantin Belousov if (fd < 0) 805861f966SKonstantin Belousov err(1, "open for read"); 815861f966SKonstantin Belousov } 825861f966SKonstantin Belousov pfd.fd = fd; 835861f966SKonstantin Belousov pfd.events = POLLIN; 845861f966SKonstantin Belousov 855861f966SKonstantin Belousov if (filetype == FT_FIFO) { 865861f966SKonstantin Belousov if (poll(&pfd, 1, 0) < 0) 875861f966SKonstantin Belousov err(1, "poll"); 885861f966SKonstantin Belousov report(num++, "0", 0, pfd.revents); 895861f966SKonstantin Belousov } 905861f966SKonstantin Belousov kill(ppid, SIGUSR1); 915861f966SKonstantin Belousov 925861f966SKonstantin Belousov usleep(1); 935861f966SKonstantin Belousov while (state != 1) 945861f966SKonstantin Belousov ; 955861f966SKonstantin Belousov if (filetype != FT_FIFO) { 965861f966SKonstantin Belousov /* 975861f966SKonstantin Belousov * The connection cannot be reestablished. Use the code that 985861f966SKonstantin Belousov * delays the read until after the writer disconnects since 995861f966SKonstantin Belousov * that case is more interesting. 1005861f966SKonstantin Belousov */ 1015861f966SKonstantin Belousov state = 4; 1025861f966SKonstantin Belousov goto state4; 1035861f966SKonstantin Belousov } 1045861f966SKonstantin Belousov if (poll(&pfd, 1, 0) < 0) 1055861f966SKonstantin Belousov err(1, "poll"); 1065861f966SKonstantin Belousov report(num++, "1", 0, pfd.revents); 1075861f966SKonstantin Belousov kill(ppid, SIGUSR1); 1085861f966SKonstantin Belousov 1095861f966SKonstantin Belousov usleep(1); 1105861f966SKonstantin Belousov while (state != 2) 1115861f966SKonstantin Belousov ; 1125861f966SKonstantin Belousov if (poll(&pfd, 1, 0) < 0) 1135861f966SKonstantin Belousov err(1, "poll"); 1145861f966SKonstantin Belousov report(num++, "2", POLLIN, pfd.revents); 1155861f966SKonstantin Belousov if (read(fd, buf, sizeof buf) != 1) 1165861f966SKonstantin Belousov err(1, "read"); 1175861f966SKonstantin Belousov if (poll(&pfd, 1, 0) < 0) 1185861f966SKonstantin Belousov err(1, "poll"); 1195861f966SKonstantin Belousov report(num++, "2a", 0, pfd.revents); 1205861f966SKonstantin Belousov kill(ppid, SIGUSR1); 1215861f966SKonstantin Belousov 1225861f966SKonstantin Belousov usleep(1); 1235861f966SKonstantin Belousov while (state != 3) 1245861f966SKonstantin Belousov ; 1255861f966SKonstantin Belousov if (poll(&pfd, 1, 0) < 0) 1265861f966SKonstantin Belousov err(1, "poll"); 1275861f966SKonstantin Belousov report(num++, "3", POLLHUP, pfd.revents); 1285861f966SKonstantin Belousov kill(ppid, SIGUSR1); 1295861f966SKonstantin Belousov 1305861f966SKonstantin Belousov /* 1315861f966SKonstantin Belousov * Now we expect a new writer, and a new connection too since 1325861f966SKonstantin Belousov * we read all the data. The only new point is that we didn't 1335861f966SKonstantin Belousov * start quite from scratch since the read fd is not new. Check 1345861f966SKonstantin Belousov * startup state as above, but don't do the read as above. 1355861f966SKonstantin Belousov */ 1365861f966SKonstantin Belousov usleep(1); 1375861f966SKonstantin Belousov while (state != 4) 1385861f966SKonstantin Belousov ; 1395861f966SKonstantin Belousov state4: 1405861f966SKonstantin Belousov if (poll(&pfd, 1, 0) < 0) 1415861f966SKonstantin Belousov err(1, "poll"); 1425861f966SKonstantin Belousov report(num++, "4", 0, pfd.revents); 1435861f966SKonstantin Belousov kill(ppid, SIGUSR1); 1445861f966SKonstantin Belousov 1455861f966SKonstantin Belousov usleep(1); 1465861f966SKonstantin Belousov while (state != 5) 1475861f966SKonstantin Belousov ; 1485861f966SKonstantin Belousov if (poll(&pfd, 1, 0) < 0) 1495861f966SKonstantin Belousov err(1, "poll"); 1505861f966SKonstantin Belousov report(num++, "5", POLLIN, pfd.revents); 1515861f966SKonstantin Belousov kill(ppid, SIGUSR1); 1525861f966SKonstantin Belousov 1535861f966SKonstantin Belousov usleep(1); 1545861f966SKonstantin Belousov while (state != 6) 1555861f966SKonstantin Belousov ; 1565861f966SKonstantin Belousov /* 1575861f966SKonstantin Belousov * Now we have no writer, but should still have data from the old 1585861f966SKonstantin Belousov * writer. Check that we have both a data-readable condition and a 1595861f966SKonstantin Belousov * hangup condition, and that the data can be read in the usual way. 1605861f966SKonstantin Belousov * Since Linux does this, programs must not quit reading when they 1615861f966SKonstantin Belousov * see POLLHUP; they must see POLLHUP without POLLIN (or another 1625861f966SKonstantin Belousov * input condition) before they decide that there is EOF. gdb-6.1.1 1635861f966SKonstantin Belousov * is an example of a broken program that quits on POLLHUP only -- 1645861f966SKonstantin Belousov * see its event-loop.c. 1655861f966SKonstantin Belousov */ 1665861f966SKonstantin Belousov if (poll(&pfd, 1, 0) < 0) 1675861f966SKonstantin Belousov err(1, "poll"); 1685861f966SKonstantin Belousov report(num++, "6", POLLIN | POLLHUP, pfd.revents); 1695861f966SKonstantin Belousov if (read(fd, buf, sizeof buf) != 1) 1705861f966SKonstantin Belousov err(1, "read"); 1715861f966SKonstantin Belousov if (poll(&pfd, 1, 0) < 0) 1725861f966SKonstantin Belousov err(1, "poll"); 1735861f966SKonstantin Belousov report(num++, "6a", POLLHUP, pfd.revents); 1745861f966SKonstantin Belousov if (filetype == FT_FIFO) { 1755861f966SKonstantin Belousov /* 1765861f966SKonstantin Belousov * Check that POLLHUP is sticky for a new reader and for 1775861f966SKonstantin Belousov * the old reader. 1785861f966SKonstantin Belousov */ 1795861f966SKonstantin Belousov fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK); 1805861f966SKonstantin Belousov if (fd2 < 0) 1815861f966SKonstantin Belousov err(1, "open for read"); 1825861f966SKonstantin Belousov pfd.fd = fd2; 1835861f966SKonstantin Belousov if (poll(&pfd, 1, 0) < 0) 1845861f966SKonstantin Belousov err(1, "poll"); 1855861f966SKonstantin Belousov report(num++, "6b", POLLHUP, pfd.revents); 1865861f966SKonstantin Belousov pfd.fd = fd; 1875861f966SKonstantin Belousov if (poll(&pfd, 1, 0) < 0) 1885861f966SKonstantin Belousov err(1, "poll"); 1895861f966SKonstantin Belousov report(num++, "6c", POLLHUP, pfd.revents); 1905861f966SKonstantin Belousov close(fd2); 1915861f966SKonstantin Belousov if (poll(&pfd, 1, 0) < 0) 1925861f966SKonstantin Belousov err(1, "poll"); 1935861f966SKonstantin Belousov report(num++, "6d", POLLHUP, pfd.revents); 1945861f966SKonstantin Belousov } 1955861f966SKonstantin Belousov close(fd); 1965861f966SKonstantin Belousov kill(ppid, SIGUSR1); 1975861f966SKonstantin Belousov 1985861f966SKonstantin Belousov exit(0); 1995861f966SKonstantin Belousov } 2005861f966SKonstantin Belousov 2015861f966SKonstantin Belousov static void 2025861f966SKonstantin Belousov parent(int fd) 2035861f966SKonstantin Belousov { 2045861f966SKonstantin Belousov usleep(1); 2055861f966SKonstantin Belousov while (state != 1) 2065861f966SKonstantin Belousov ; 2075861f966SKonstantin Belousov if (filetype == FT_FIFO) { 2085861f966SKonstantin Belousov fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); 2095861f966SKonstantin Belousov if (fd < 0) 2105861f966SKonstantin Belousov err(1, "open for write"); 2115861f966SKonstantin Belousov } 2125861f966SKonstantin Belousov kill(cpid, SIGUSR1); 2135861f966SKonstantin Belousov 2145861f966SKonstantin Belousov usleep(1); 2155861f966SKonstantin Belousov while (state != 2) 2165861f966SKonstantin Belousov ; 2175861f966SKonstantin Belousov if (write(fd, "", 1) != 1) 2185861f966SKonstantin Belousov err(1, "write"); 2195861f966SKonstantin Belousov kill(cpid, SIGUSR1); 2205861f966SKonstantin Belousov 2215861f966SKonstantin Belousov usleep(1); 2225861f966SKonstantin Belousov while (state != 3) 2235861f966SKonstantin Belousov ; 2245861f966SKonstantin Belousov if (close(fd) != 0) 2255861f966SKonstantin Belousov err(1, "close for write"); 2265861f966SKonstantin Belousov kill(cpid, SIGUSR1); 2275861f966SKonstantin Belousov 2285861f966SKonstantin Belousov usleep(1); 2295861f966SKonstantin Belousov while (state != 4) 2305861f966SKonstantin Belousov ; 2315861f966SKonstantin Belousov if (filetype != FT_FIFO) 2325861f966SKonstantin Belousov return; 2335861f966SKonstantin Belousov fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); 2345861f966SKonstantin Belousov if (fd < 0) 2355861f966SKonstantin Belousov err(1, "open for write"); 2365861f966SKonstantin Belousov kill(cpid, SIGUSR1); 2375861f966SKonstantin Belousov 2385861f966SKonstantin Belousov usleep(1); 2395861f966SKonstantin Belousov while (state != 5) 2405861f966SKonstantin Belousov ; 2415861f966SKonstantin Belousov if (write(fd, "", 1) != 1) 2425861f966SKonstantin Belousov err(1, "write"); 2435861f966SKonstantin Belousov kill(cpid, SIGUSR1); 2445861f966SKonstantin Belousov 2455861f966SKonstantin Belousov usleep(1); 2465861f966SKonstantin Belousov while (state != 6) 2475861f966SKonstantin Belousov ; 2485861f966SKonstantin Belousov if (close(fd) != 0) 2495861f966SKonstantin Belousov err(1, "close for write"); 2505861f966SKonstantin Belousov kill(cpid, SIGUSR1); 2515861f966SKonstantin Belousov 2525861f966SKonstantin Belousov usleep(1); 2535861f966SKonstantin Belousov while (state != 7) 2545861f966SKonstantin Belousov ; 2555861f966SKonstantin Belousov } 2565861f966SKonstantin Belousov 2575861f966SKonstantin Belousov int 2585861f966SKonstantin Belousov main(void) 2595861f966SKonstantin Belousov { 2605861f966SKonstantin Belousov int fd[2], num; 2615861f966SKonstantin Belousov 2625861f966SKonstantin Belousov num = 1; 2635861f966SKonstantin Belousov printf("1..20\n"); 2645861f966SKonstantin Belousov fflush(stdout); 2655861f966SKonstantin Belousov signal(SIGUSR1, catch); 2665861f966SKonstantin Belousov ppid = getpid(); 2675861f966SKonstantin Belousov for (filetype = 0; filetype < FT_END; filetype++) { 2685861f966SKonstantin Belousov switch (filetype) { 2695861f966SKonstantin Belousov case FT_FIFO: 2705861f966SKonstantin Belousov if (mkfifo(FIFONAME, 0666) != 0) 2715861f966SKonstantin Belousov err(1, "mkfifo"); 2725861f966SKonstantin Belousov fd[0] = -1; 2735861f966SKonstantin Belousov fd[1] = -1; 2745861f966SKonstantin Belousov break; 2755861f966SKonstantin Belousov case FT_SOCKETPAIR: 2765861f966SKonstantin Belousov if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC, 2775861f966SKonstantin Belousov fd) != 0) 2785861f966SKonstantin Belousov err(1, "socketpair"); 2795861f966SKonstantin Belousov break; 2805861f966SKonstantin Belousov case FT_PIPE: 2815861f966SKonstantin Belousov if (pipe(fd) != 0) 2825861f966SKonstantin Belousov err(1, "pipe"); 2835861f966SKonstantin Belousov break; 2845861f966SKonstantin Belousov } 2855861f966SKonstantin Belousov state = 0; 2865861f966SKonstantin Belousov switch (cpid = fork()) { 2875861f966SKonstantin Belousov case -1: 2885861f966SKonstantin Belousov err(1, "fork"); 2895861f966SKonstantin Belousov case 0: 2905861f966SKonstantin Belousov (void)close(fd[1]); 2915861f966SKonstantin Belousov child(fd[0], num); 2925861f966SKonstantin Belousov break; 2935861f966SKonstantin Belousov default: 2945861f966SKonstantin Belousov (void)close(fd[0]); 2955861f966SKonstantin Belousov parent(fd[1]); 2965861f966SKonstantin Belousov break; 2975861f966SKonstantin Belousov } 2985861f966SKonstantin Belousov num += filetype == FT_FIFO ? 12 : 4; 2995861f966SKonstantin Belousov } 3005861f966SKonstantin Belousov (void)unlink(FIFONAME); 3015861f966SKonstantin Belousov return (0); 3025861f966SKonstantin Belousov } 303