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