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 47*42992a3aSKonstantin Belousov report_state(const char *state) 485861f966SKonstantin Belousov { 49*42992a3aSKonstantin Belousov 50*42992a3aSKonstantin Belousov printf(" %s state %s: ", 51*42992a3aSKonstantin Belousov filetype == FT_PIPE ? "Pipe" : 52*42992a3aSKonstantin Belousov filetype == FT_SOCKETPAIR ? "Sock" : "FIFO", 53*42992a3aSKonstantin Belousov state); 54*42992a3aSKonstantin Belousov } 55*42992a3aSKonstantin Belousov 56*42992a3aSKonstantin Belousov static void 57*42992a3aSKonstantin Belousov report(int num, const char *state, int expected, int got, int res, 58*42992a3aSKonstantin Belousov int res_expected) 59*42992a3aSKonstantin Belousov { 60*42992a3aSKonstantin Belousov 61*42992a3aSKonstantin Belousov if (res != res_expected) { 62*42992a3aSKonstantin Belousov printf("not ok %-2d", num); 63*42992a3aSKonstantin Belousov report_state(state); 64*42992a3aSKonstantin Belousov printf("poll result %d expected %d. ", 65*42992a3aSKonstantin Belousov res, res_expected); 66*42992a3aSKonstantin Belousov } else { 675861f966SKonstantin Belousov if (expected == got) 685861f966SKonstantin Belousov printf("ok %-2d ", num); 695861f966SKonstantin Belousov else 705861f966SKonstantin Belousov printf("not ok %-2d", num); 71*42992a3aSKonstantin Belousov report_state(state); 72*42992a3aSKonstantin Belousov } 73*42992a3aSKonstantin Belousov printf("expected %s; got %s\n", decode_events(expected), 74*42992a3aSKonstantin Belousov decode_events(got)); 755861f966SKonstantin Belousov fflush(stdout); 765861f966SKonstantin Belousov } 775861f966SKonstantin Belousov 785861f966SKonstantin Belousov static pid_t cpid; 795861f966SKonstantin Belousov static pid_t ppid; 805861f966SKonstantin Belousov static volatile sig_atomic_t state; 815861f966SKonstantin Belousov 825861f966SKonstantin Belousov static void 83*42992a3aSKonstantin Belousov catch(int sig __unused) 845861f966SKonstantin Belousov { 85*42992a3aSKonstantin Belousov 865861f966SKonstantin Belousov state++; 875861f966SKonstantin Belousov } 885861f966SKonstantin Belousov 895861f966SKonstantin Belousov static void 905861f966SKonstantin Belousov child(int fd, int num) 915861f966SKonstantin Belousov { 925861f966SKonstantin Belousov struct pollfd pfd; 93*42992a3aSKonstantin Belousov int fd2, res; 945861f966SKonstantin Belousov char buf[256]; 955861f966SKonstantin Belousov 965861f966SKonstantin Belousov if (filetype == FT_FIFO) { 975861f966SKonstantin Belousov fd = open(FIFONAME, O_RDONLY | O_NONBLOCK); 985861f966SKonstantin Belousov if (fd < 0) 995861f966SKonstantin Belousov err(1, "open for read"); 1005861f966SKonstantin Belousov } 1015861f966SKonstantin Belousov pfd.fd = fd; 1025861f966SKonstantin Belousov pfd.events = POLLIN; 1035861f966SKonstantin Belousov 1045861f966SKonstantin Belousov if (filetype == FT_FIFO) { 105*42992a3aSKonstantin Belousov if ((res = poll(&pfd, 1, 0)) < 0) 1065861f966SKonstantin Belousov err(1, "poll"); 107*42992a3aSKonstantin Belousov report(num++, "0", 0, pfd.revents, res, 0); 1085861f966SKonstantin Belousov } 1095861f966SKonstantin Belousov kill(ppid, SIGUSR1); 1105861f966SKonstantin Belousov 1115861f966SKonstantin Belousov usleep(1); 1125861f966SKonstantin Belousov while (state != 1) 1135861f966SKonstantin Belousov ; 1145861f966SKonstantin Belousov if (filetype != FT_FIFO) { 1155861f966SKonstantin Belousov /* 1165861f966SKonstantin Belousov * The connection cannot be reestablished. Use the code that 1175861f966SKonstantin Belousov * delays the read until after the writer disconnects since 1185861f966SKonstantin Belousov * that case is more interesting. 1195861f966SKonstantin Belousov */ 1205861f966SKonstantin Belousov state = 4; 1215861f966SKonstantin Belousov goto state4; 1225861f966SKonstantin Belousov } 123*42992a3aSKonstantin Belousov if ((res = poll(&pfd, 1, 0)) < 0) 1245861f966SKonstantin Belousov err(1, "poll"); 125*42992a3aSKonstantin Belousov report(num++, "1", 0, pfd.revents, res, 0); 1265861f966SKonstantin Belousov kill(ppid, SIGUSR1); 1275861f966SKonstantin Belousov 1285861f966SKonstantin Belousov usleep(1); 1295861f966SKonstantin Belousov while (state != 2) 1305861f966SKonstantin Belousov ; 131*42992a3aSKonstantin Belousov if ((res = poll(&pfd, 1, 0)) < 0) 1325861f966SKonstantin Belousov err(1, "poll"); 133*42992a3aSKonstantin Belousov report(num++, "2", POLLIN, pfd.revents, res, 1); 1345861f966SKonstantin Belousov if (read(fd, buf, sizeof buf) != 1) 1355861f966SKonstantin Belousov err(1, "read"); 136*42992a3aSKonstantin Belousov if ((res = poll(&pfd, 1, 0)) < 0) 1375861f966SKonstantin Belousov err(1, "poll"); 138*42992a3aSKonstantin Belousov report(num++, "2a", 0, pfd.revents, res, 0); 1395861f966SKonstantin Belousov kill(ppid, SIGUSR1); 1405861f966SKonstantin Belousov 1415861f966SKonstantin Belousov usleep(1); 1425861f966SKonstantin Belousov while (state != 3) 1435861f966SKonstantin Belousov ; 144*42992a3aSKonstantin Belousov if ((res = poll(&pfd, 1, 0)) < 0) 1455861f966SKonstantin Belousov err(1, "poll"); 146*42992a3aSKonstantin Belousov report(num++, "3", POLLHUP, pfd.revents, res, 1); 1475861f966SKonstantin Belousov kill(ppid, SIGUSR1); 1485861f966SKonstantin Belousov 1495861f966SKonstantin Belousov /* 1505861f966SKonstantin Belousov * Now we expect a new writer, and a new connection too since 1515861f966SKonstantin Belousov * we read all the data. The only new point is that we didn't 1525861f966SKonstantin Belousov * start quite from scratch since the read fd is not new. Check 1535861f966SKonstantin Belousov * startup state as above, but don't do the read as above. 1545861f966SKonstantin Belousov */ 1555861f966SKonstantin Belousov usleep(1); 1565861f966SKonstantin Belousov while (state != 4) 1575861f966SKonstantin Belousov ; 1585861f966SKonstantin Belousov state4: 159*42992a3aSKonstantin Belousov if ((res = poll(&pfd, 1, 0)) < 0) 1605861f966SKonstantin Belousov err(1, "poll"); 161*42992a3aSKonstantin Belousov report(num++, "4", 0, pfd.revents, res, 0); 1625861f966SKonstantin Belousov kill(ppid, SIGUSR1); 1635861f966SKonstantin Belousov 1645861f966SKonstantin Belousov usleep(1); 1655861f966SKonstantin Belousov while (state != 5) 1665861f966SKonstantin Belousov ; 167*42992a3aSKonstantin Belousov if ((res = poll(&pfd, 1, 0)) < 0) 1685861f966SKonstantin Belousov err(1, "poll"); 169*42992a3aSKonstantin Belousov report(num++, "5", POLLIN, pfd.revents, res, 1); 1705861f966SKonstantin Belousov kill(ppid, SIGUSR1); 1715861f966SKonstantin Belousov 1725861f966SKonstantin Belousov usleep(1); 1735861f966SKonstantin Belousov while (state != 6) 1745861f966SKonstantin Belousov ; 1755861f966SKonstantin Belousov /* 1765861f966SKonstantin Belousov * Now we have no writer, but should still have data from the old 1775861f966SKonstantin Belousov * writer. Check that we have both a data-readable condition and a 1785861f966SKonstantin Belousov * hangup condition, and that the data can be read in the usual way. 1795861f966SKonstantin Belousov * Since Linux does this, programs must not quit reading when they 1805861f966SKonstantin Belousov * see POLLHUP; they must see POLLHUP without POLLIN (or another 1815861f966SKonstantin Belousov * input condition) before they decide that there is EOF. gdb-6.1.1 1825861f966SKonstantin Belousov * is an example of a broken program that quits on POLLHUP only -- 1835861f966SKonstantin Belousov * see its event-loop.c. 1845861f966SKonstantin Belousov */ 185*42992a3aSKonstantin Belousov if ((res = poll(&pfd, 1, 0)) < 0) 1865861f966SKonstantin Belousov err(1, "poll"); 187*42992a3aSKonstantin Belousov report(num++, "6", POLLIN | POLLHUP, pfd.revents, res, 1); 1885861f966SKonstantin Belousov if (read(fd, buf, sizeof buf) != 1) 1895861f966SKonstantin Belousov err(1, "read"); 190*42992a3aSKonstantin Belousov if ((res = poll(&pfd, 1, 0)) < 0) 1915861f966SKonstantin Belousov err(1, "poll"); 192*42992a3aSKonstantin Belousov report(num++, "6a", POLLHUP, pfd.revents, res, 1); 1935861f966SKonstantin Belousov if (filetype == FT_FIFO) { 1945861f966SKonstantin Belousov /* 1955861f966SKonstantin Belousov * Check that POLLHUP is sticky for a new reader and for 1965861f966SKonstantin Belousov * the old reader. 1975861f966SKonstantin Belousov */ 1985861f966SKonstantin Belousov fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK); 1995861f966SKonstantin Belousov if (fd2 < 0) 2005861f966SKonstantin Belousov err(1, "open for read"); 2015861f966SKonstantin Belousov pfd.fd = fd2; 202*42992a3aSKonstantin Belousov if ((res = poll(&pfd, 1, 0)) < 0) 2035861f966SKonstantin Belousov err(1, "poll"); 204*42992a3aSKonstantin Belousov report(num++, "6b", POLLHUP, pfd.revents, res, 1); 2055861f966SKonstantin Belousov pfd.fd = fd; 206*42992a3aSKonstantin Belousov if ((res = poll(&pfd, 1, 0)) < 0) 2075861f966SKonstantin Belousov err(1, "poll"); 208*42992a3aSKonstantin Belousov report(num++, "6c", POLLHUP, pfd.revents, res, 1); 2095861f966SKonstantin Belousov close(fd2); 210*42992a3aSKonstantin Belousov if ((res = poll(&pfd, 1, 0)) < 0) 2115861f966SKonstantin Belousov err(1, "poll"); 212*42992a3aSKonstantin Belousov report(num++, "6d", POLLHUP, pfd.revents, res, 1); 2135861f966SKonstantin Belousov } 2145861f966SKonstantin Belousov close(fd); 2155861f966SKonstantin Belousov kill(ppid, SIGUSR1); 2165861f966SKonstantin Belousov 2175861f966SKonstantin Belousov exit(0); 2185861f966SKonstantin Belousov } 2195861f966SKonstantin Belousov 2205861f966SKonstantin Belousov static void 2215861f966SKonstantin Belousov parent(int fd) 2225861f966SKonstantin Belousov { 2235861f966SKonstantin Belousov usleep(1); 2245861f966SKonstantin Belousov while (state != 1) 2255861f966SKonstantin Belousov ; 2265861f966SKonstantin Belousov if (filetype == FT_FIFO) { 2275861f966SKonstantin Belousov fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); 2285861f966SKonstantin Belousov if (fd < 0) 2295861f966SKonstantin Belousov err(1, "open for write"); 2305861f966SKonstantin Belousov } 2315861f966SKonstantin Belousov kill(cpid, SIGUSR1); 2325861f966SKonstantin Belousov 2335861f966SKonstantin Belousov usleep(1); 2345861f966SKonstantin Belousov while (state != 2) 2355861f966SKonstantin Belousov ; 2365861f966SKonstantin Belousov if (write(fd, "", 1) != 1) 2375861f966SKonstantin Belousov err(1, "write"); 2385861f966SKonstantin Belousov kill(cpid, SIGUSR1); 2395861f966SKonstantin Belousov 2405861f966SKonstantin Belousov usleep(1); 2415861f966SKonstantin Belousov while (state != 3) 2425861f966SKonstantin Belousov ; 2435861f966SKonstantin Belousov if (close(fd) != 0) 2445861f966SKonstantin Belousov err(1, "close for write"); 2455861f966SKonstantin Belousov kill(cpid, SIGUSR1); 2465861f966SKonstantin Belousov 2475861f966SKonstantin Belousov usleep(1); 2485861f966SKonstantin Belousov while (state != 4) 2495861f966SKonstantin Belousov ; 2505861f966SKonstantin Belousov if (filetype != FT_FIFO) 2515861f966SKonstantin Belousov return; 2525861f966SKonstantin Belousov fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); 2535861f966SKonstantin Belousov if (fd < 0) 2545861f966SKonstantin Belousov err(1, "open for write"); 2555861f966SKonstantin Belousov kill(cpid, SIGUSR1); 2565861f966SKonstantin Belousov 2575861f966SKonstantin Belousov usleep(1); 2585861f966SKonstantin Belousov while (state != 5) 2595861f966SKonstantin Belousov ; 2605861f966SKonstantin Belousov if (write(fd, "", 1) != 1) 2615861f966SKonstantin Belousov err(1, "write"); 2625861f966SKonstantin Belousov kill(cpid, SIGUSR1); 2635861f966SKonstantin Belousov 2645861f966SKonstantin Belousov usleep(1); 2655861f966SKonstantin Belousov while (state != 6) 2665861f966SKonstantin Belousov ; 2675861f966SKonstantin Belousov if (close(fd) != 0) 2685861f966SKonstantin Belousov err(1, "close for write"); 2695861f966SKonstantin Belousov kill(cpid, SIGUSR1); 2705861f966SKonstantin Belousov 2715861f966SKonstantin Belousov usleep(1); 2725861f966SKonstantin Belousov while (state != 7) 2735861f966SKonstantin Belousov ; 2745861f966SKonstantin Belousov } 2755861f966SKonstantin Belousov 2765861f966SKonstantin Belousov int 2775861f966SKonstantin Belousov main(void) 2785861f966SKonstantin Belousov { 2795861f966SKonstantin Belousov int fd[2], num; 2805861f966SKonstantin Belousov 2815861f966SKonstantin Belousov num = 1; 2825861f966SKonstantin Belousov printf("1..20\n"); 2835861f966SKonstantin Belousov fflush(stdout); 2845861f966SKonstantin Belousov signal(SIGUSR1, catch); 2855861f966SKonstantin Belousov ppid = getpid(); 2865861f966SKonstantin Belousov for (filetype = 0; filetype < FT_END; filetype++) { 2875861f966SKonstantin Belousov switch (filetype) { 2885861f966SKonstantin Belousov case FT_FIFO: 2895861f966SKonstantin Belousov if (mkfifo(FIFONAME, 0666) != 0) 2905861f966SKonstantin Belousov err(1, "mkfifo"); 2915861f966SKonstantin Belousov fd[0] = -1; 2925861f966SKonstantin Belousov fd[1] = -1; 2935861f966SKonstantin Belousov break; 2945861f966SKonstantin Belousov case FT_SOCKETPAIR: 2955861f966SKonstantin Belousov if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC, 2965861f966SKonstantin Belousov fd) != 0) 2975861f966SKonstantin Belousov err(1, "socketpair"); 2985861f966SKonstantin Belousov break; 2995861f966SKonstantin Belousov case FT_PIPE: 3005861f966SKonstantin Belousov if (pipe(fd) != 0) 3015861f966SKonstantin Belousov err(1, "pipe"); 3025861f966SKonstantin Belousov break; 3035861f966SKonstantin Belousov } 3045861f966SKonstantin Belousov state = 0; 3055861f966SKonstantin Belousov switch (cpid = fork()) { 3065861f966SKonstantin Belousov case -1: 3075861f966SKonstantin Belousov err(1, "fork"); 3085861f966SKonstantin Belousov case 0: 3095861f966SKonstantin Belousov (void)close(fd[1]); 3105861f966SKonstantin Belousov child(fd[0], num); 3115861f966SKonstantin Belousov break; 3125861f966SKonstantin Belousov default: 3135861f966SKonstantin Belousov (void)close(fd[0]); 3145861f966SKonstantin Belousov parent(fd[1]); 3155861f966SKonstantin Belousov break; 3165861f966SKonstantin Belousov } 3175861f966SKonstantin Belousov num += filetype == FT_FIFO ? 12 : 4; 3185861f966SKonstantin Belousov } 3195861f966SKonstantin Belousov (void)unlink(FIFONAME); 3205861f966SKonstantin Belousov return (0); 3215861f966SKonstantin Belousov } 322