1*5861f966SKonstantin Belousov
2*5861f966SKonstantin Belousov #include <sys/socket.h>
3*5861f966SKonstantin Belousov #include <sys/select.h>
4*5861f966SKonstantin Belousov #include <sys/stat.h>
5*5861f966SKonstantin Belousov
6*5861f966SKonstantin Belousov #include <err.h>
7*5861f966SKonstantin Belousov #include <fcntl.h>
8*5861f966SKonstantin Belousov #include <signal.h>
9*5861f966SKonstantin Belousov #include <stdio.h>
10*5861f966SKonstantin Belousov #include <stdlib.h>
11*5861f966SKonstantin Belousov #include <unistd.h>
12*5861f966SKonstantin Belousov
13*5861f966SKonstantin Belousov #define FIFONAME "fifo.tmp"
14*5861f966SKonstantin Belousov #define FT_END 3
15*5861f966SKonstantin Belousov #define FT_FIFO 2
16*5861f966SKonstantin Belousov #define FT_PIPE 0
17*5861f966SKonstantin Belousov #define FT_SOCKETPAIR 1
18*5861f966SKonstantin Belousov
19*5861f966SKonstantin Belousov #define SETUP(fd, rfds, tv) do { \
20*5861f966SKonstantin Belousov FD_ZERO(&(rfds)); \
21*5861f966SKonstantin Belousov FD_SET((fd), &(rfds)); \
22*5861f966SKonstantin Belousov (tv).tv_sec = 0; \
23*5861f966SKonstantin Belousov (tv).tv_usec = 0; \
24*5861f966SKonstantin Belousov } while (0)
25*5861f966SKonstantin Belousov
26*5861f966SKonstantin Belousov static int filetype;
27*5861f966SKonstantin Belousov
28*5861f966SKonstantin Belousov static const char *
decode_events(int events)29*5861f966SKonstantin Belousov decode_events(int events)
30*5861f966SKonstantin Belousov {
31*5861f966SKonstantin Belousov return (events ? "set" : "clear");
32*5861f966SKonstantin Belousov }
33*5861f966SKonstantin Belousov
34*5861f966SKonstantin Belousov static void
report(int num,const char * state,int expected,int got)35*5861f966SKonstantin Belousov report(int num, const char *state, int expected, int got)
36*5861f966SKonstantin Belousov {
37*5861f966SKonstantin Belousov if (!expected == !got)
38*5861f966SKonstantin Belousov printf("ok %-2d ", num);
39*5861f966SKonstantin Belousov else
40*5861f966SKonstantin Belousov printf("not ok %-2d", num);
41*5861f966SKonstantin Belousov printf(" %s state %s: expected %s; got %s\n",
42*5861f966SKonstantin Belousov filetype == FT_PIPE ? "Pipe" :
43*5861f966SKonstantin Belousov filetype == FT_SOCKETPAIR ? "Sock" : "FIFO",
44*5861f966SKonstantin Belousov state, decode_events(expected), decode_events(got));
45*5861f966SKonstantin Belousov fflush(stdout);
46*5861f966SKonstantin Belousov }
47*5861f966SKonstantin Belousov
48*5861f966SKonstantin Belousov static pid_t cpid;
49*5861f966SKonstantin Belousov static pid_t ppid;
50*5861f966SKonstantin Belousov static volatile sig_atomic_t state;
51*5861f966SKonstantin Belousov
52*5861f966SKonstantin Belousov static void
catch(int sig)53*5861f966SKonstantin Belousov catch(int sig)
54*5861f966SKonstantin Belousov {
55*5861f966SKonstantin Belousov state++;
56*5861f966SKonstantin Belousov }
57*5861f966SKonstantin Belousov
58*5861f966SKonstantin Belousov static void
child(int fd,int num)59*5861f966SKonstantin Belousov child(int fd, int num)
60*5861f966SKonstantin Belousov {
61*5861f966SKonstantin Belousov fd_set rfds;
62*5861f966SKonstantin Belousov struct timeval tv;
63*5861f966SKonstantin Belousov int fd1, fd2;
64*5861f966SKonstantin Belousov char buf[256];
65*5861f966SKonstantin Belousov
66*5861f966SKonstantin Belousov if (filetype == FT_FIFO) {
67*5861f966SKonstantin Belousov fd = open(FIFONAME, O_RDONLY | O_NONBLOCK);
68*5861f966SKonstantin Belousov if (fd < 0)
69*5861f966SKonstantin Belousov err(1, "open for read");
70*5861f966SKonstantin Belousov }
71*5861f966SKonstantin Belousov if (fd >= FD_SETSIZE)
72*5861f966SKonstantin Belousov errx(1, "fd = %d too large for select()", fd);
73*5861f966SKonstantin Belousov
74*5861f966SKonstantin Belousov if (filetype == FT_FIFO) {
75*5861f966SKonstantin Belousov SETUP(fd, rfds, tv);
76*5861f966SKonstantin Belousov if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
77*5861f966SKonstantin Belousov err(1, "select");
78*5861f966SKonstantin Belousov /*
79*5861f966SKonstantin Belousov * This state (a reader for which there has never been a
80*5861f966SKonstantin Belousov * writer) is reported quite differently for select() than
81*5861f966SKonstantin Belousov * for poll(). select() must see a ready-to-read descriptor
82*5861f966SKonstantin Belousov * since read() will see EOF and not block; it cannot
83*5861f966SKonstantin Belousov * distinguish this state from the one of a reader for which
84*5861f966SKonstantin Belousov * there has been a writer but all writers have gone away
85*5861f966SKonstantin Belousov * and all data has been read. poll() and distinguish these
86*5861f966SKonstantin Belousov * states by returning POLLHUP only for the latter; it does
87*5861f966SKonstantin Belousov * this, although this makes it inconsistent with the
88*5861f966SKonstantin Belousov * blockability of read() in the former.
89*5861f966SKonstantin Belousov */
90*5861f966SKonstantin Belousov report(num++, "0", 1, FD_ISSET(fd, &rfds));
91*5861f966SKonstantin Belousov }
92*5861f966SKonstantin Belousov kill(ppid, SIGUSR1);
93*5861f966SKonstantin Belousov
94*5861f966SKonstantin Belousov usleep(1);
95*5861f966SKonstantin Belousov while (state != 1)
96*5861f966SKonstantin Belousov ;
97*5861f966SKonstantin Belousov if (filetype != FT_FIFO) {
98*5861f966SKonstantin Belousov /*
99*5861f966SKonstantin Belousov * The connection cannot be reestablished. Use the code that
100*5861f966SKonstantin Belousov * delays the read until after the writer disconnects since
101*5861f966SKonstantin Belousov * that case is more interesting.
102*5861f966SKonstantin Belousov */
103*5861f966SKonstantin Belousov state = 4;
104*5861f966SKonstantin Belousov goto state4;
105*5861f966SKonstantin Belousov }
106*5861f966SKonstantin Belousov SETUP(fd, rfds, tv);
107*5861f966SKonstantin Belousov if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
108*5861f966SKonstantin Belousov err(1, "select");
109*5861f966SKonstantin Belousov report(num++, "1", 0, FD_ISSET(fd, &rfds));
110*5861f966SKonstantin Belousov kill(ppid, SIGUSR1);
111*5861f966SKonstantin Belousov
112*5861f966SKonstantin Belousov usleep(1);
113*5861f966SKonstantin Belousov while (state != 2)
114*5861f966SKonstantin Belousov ;
115*5861f966SKonstantin Belousov SETUP(fd, rfds, tv);
116*5861f966SKonstantin Belousov if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
117*5861f966SKonstantin Belousov err(1, "select");
118*5861f966SKonstantin Belousov report(num++, "2", 1, FD_ISSET(fd, &rfds));
119*5861f966SKonstantin Belousov if (read(fd, buf, sizeof buf) != 1)
120*5861f966SKonstantin Belousov err(1, "read");
121*5861f966SKonstantin Belousov SETUP(fd, rfds, tv);
122*5861f966SKonstantin Belousov if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
123*5861f966SKonstantin Belousov err(1, "select");
124*5861f966SKonstantin Belousov report(num++, "2a", 0, FD_ISSET(fd, &rfds));
125*5861f966SKonstantin Belousov kill(ppid, SIGUSR1);
126*5861f966SKonstantin Belousov
127*5861f966SKonstantin Belousov usleep(1);
128*5861f966SKonstantin Belousov while (state != 3)
129*5861f966SKonstantin Belousov ;
130*5861f966SKonstantin Belousov SETUP(fd, rfds, tv);
131*5861f966SKonstantin Belousov if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
132*5861f966SKonstantin Belousov err(1, "select");
133*5861f966SKonstantin Belousov report(num++, "3", 1, FD_ISSET(fd, &rfds));
134*5861f966SKonstantin Belousov kill(ppid, SIGUSR1);
135*5861f966SKonstantin Belousov
136*5861f966SKonstantin Belousov /*
137*5861f966SKonstantin Belousov * Now we expect a new writer, and a new connection too since
138*5861f966SKonstantin Belousov * we read all the data. The only new point is that we didn't
139*5861f966SKonstantin Belousov * start quite from scratch since the read fd is not new. Check
140*5861f966SKonstantin Belousov * startup state as above, but don't do the read as above.
141*5861f966SKonstantin Belousov */
142*5861f966SKonstantin Belousov usleep(1);
143*5861f966SKonstantin Belousov while (state != 4)
144*5861f966SKonstantin Belousov ;
145*5861f966SKonstantin Belousov state4:
146*5861f966SKonstantin Belousov SETUP(fd, rfds, tv);
147*5861f966SKonstantin Belousov if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
148*5861f966SKonstantin Belousov err(1, "select");
149*5861f966SKonstantin Belousov report(num++, "4", 0, FD_ISSET(fd, &rfds));
150*5861f966SKonstantin Belousov kill(ppid, SIGUSR1);
151*5861f966SKonstantin Belousov
152*5861f966SKonstantin Belousov usleep(1);
153*5861f966SKonstantin Belousov while (state != 5)
154*5861f966SKonstantin Belousov ;
155*5861f966SKonstantin Belousov SETUP(fd, rfds, tv);
156*5861f966SKonstantin Belousov if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
157*5861f966SKonstantin Belousov err(1, "select");
158*5861f966SKonstantin Belousov report(num++, "5", 1, FD_ISSET(fd, &rfds));
159*5861f966SKonstantin Belousov kill(ppid, SIGUSR1);
160*5861f966SKonstantin Belousov
161*5861f966SKonstantin Belousov usleep(1);
162*5861f966SKonstantin Belousov while (state != 6)
163*5861f966SKonstantin Belousov ;
164*5861f966SKonstantin Belousov /*
165*5861f966SKonstantin Belousov * Now we have no writer, but should still have data from the old
166*5861f966SKonstantin Belousov * writer. Check that we have a data-readable condition, and that
167*5861f966SKonstantin Belousov * the data can be read in the usual way.
168*5861f966SKonstantin Belousov */
169*5861f966SKonstantin Belousov SETUP(fd, rfds, tv);
170*5861f966SKonstantin Belousov if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
171*5861f966SKonstantin Belousov err(1, "select");
172*5861f966SKonstantin Belousov report(num++, "6", 1, FD_ISSET(fd, &rfds));
173*5861f966SKonstantin Belousov if (read(fd, buf, sizeof buf) != 1)
174*5861f966SKonstantin Belousov err(1, "read");
175*5861f966SKonstantin Belousov SETUP(fd, rfds, tv);
176*5861f966SKonstantin Belousov if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
177*5861f966SKonstantin Belousov err(1, "select");
178*5861f966SKonstantin Belousov report(num++, "6a", 1, FD_ISSET(fd, &rfds));
179*5861f966SKonstantin Belousov if (filetype == FT_FIFO) {
180*5861f966SKonstantin Belousov /*
181*5861f966SKonstantin Belousov * Check that the readable-data condition is sticky for a
182*5861f966SKonstantin Belousov * new reader and for the old reader. We really only have
183*5861f966SKonstantin Belousov * a hangup condition, but select() can only see this as
184*5861f966SKonstantin Belousov * a readable-data condition for null data. select()
185*5861f966SKonstantin Belousov * cannot distinguish this state from the initial state
186*5861f966SKonstantin Belousov * where there is a reader but has never been a writer, so
187*5861f966SKonstantin Belousov * the following tests (to follow the pattern in pipepoll.c)
188*5861f966SKonstantin Belousov * essentially test state 0 again.
189*5861f966SKonstantin Belousov */
190*5861f966SKonstantin Belousov fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK);
191*5861f966SKonstantin Belousov if (fd2 < 0)
192*5861f966SKonstantin Belousov err(1, "open for read");
193*5861f966SKonstantin Belousov fd1 = fd;
194*5861f966SKonstantin Belousov fd = fd2;
195*5861f966SKonstantin Belousov SETUP(fd, rfds, tv);
196*5861f966SKonstantin Belousov if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
197*5861f966SKonstantin Belousov err(1, "select");
198*5861f966SKonstantin Belousov report(num++, "6b", 1, FD_ISSET(fd, &rfds));
199*5861f966SKonstantin Belousov fd = fd1;
200*5861f966SKonstantin Belousov SETUP(fd, rfds, tv);
201*5861f966SKonstantin Belousov if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
202*5861f966SKonstantin Belousov err(1, "select");
203*5861f966SKonstantin Belousov report(num++, "6c", 1, FD_ISSET(fd, &rfds));
204*5861f966SKonstantin Belousov close(fd2);
205*5861f966SKonstantin Belousov SETUP(fd, rfds, tv);
206*5861f966SKonstantin Belousov if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0)
207*5861f966SKonstantin Belousov err(1, "select");
208*5861f966SKonstantin Belousov report(num++, "6d", 1, FD_ISSET(fd, &rfds));
209*5861f966SKonstantin Belousov }
210*5861f966SKonstantin Belousov close(fd);
211*5861f966SKonstantin Belousov kill(ppid, SIGUSR1);
212*5861f966SKonstantin Belousov
213*5861f966SKonstantin Belousov exit(0);
214*5861f966SKonstantin Belousov }
215*5861f966SKonstantin Belousov
216*5861f966SKonstantin Belousov static void
parent(int fd)217*5861f966SKonstantin Belousov parent(int fd)
218*5861f966SKonstantin Belousov {
219*5861f966SKonstantin Belousov usleep(1);
220*5861f966SKonstantin Belousov while (state != 1)
221*5861f966SKonstantin Belousov ;
222*5861f966SKonstantin Belousov if (filetype == FT_FIFO) {
223*5861f966SKonstantin Belousov fd = open(FIFONAME, O_WRONLY | O_NONBLOCK);
224*5861f966SKonstantin Belousov if (fd < 0)
225*5861f966SKonstantin Belousov err(1, "open for write");
226*5861f966SKonstantin Belousov }
227*5861f966SKonstantin Belousov kill(cpid, SIGUSR1);
228*5861f966SKonstantin Belousov
229*5861f966SKonstantin Belousov usleep(1);
230*5861f966SKonstantin Belousov while (state != 2)
231*5861f966SKonstantin Belousov ;
232*5861f966SKonstantin Belousov if (write(fd, "", 1) != 1)
233*5861f966SKonstantin Belousov err(1, "write");
234*5861f966SKonstantin Belousov kill(cpid, SIGUSR1);
235*5861f966SKonstantin Belousov
236*5861f966SKonstantin Belousov usleep(1);
237*5861f966SKonstantin Belousov while (state != 3)
238*5861f966SKonstantin Belousov ;
239*5861f966SKonstantin Belousov if (close(fd) != 0)
240*5861f966SKonstantin Belousov err(1, "close for write");
241*5861f966SKonstantin Belousov kill(cpid, SIGUSR1);
242*5861f966SKonstantin Belousov
243*5861f966SKonstantin Belousov usleep(1);
244*5861f966SKonstantin Belousov while (state != 4)
245*5861f966SKonstantin Belousov ;
246*5861f966SKonstantin Belousov if (filetype != FT_FIFO)
247*5861f966SKonstantin Belousov return;
248*5861f966SKonstantin Belousov fd = open(FIFONAME, O_WRONLY | O_NONBLOCK);
249*5861f966SKonstantin Belousov if (fd < 0)
250*5861f966SKonstantin Belousov err(1, "open for write");
251*5861f966SKonstantin Belousov kill(cpid, SIGUSR1);
252*5861f966SKonstantin Belousov
253*5861f966SKonstantin Belousov usleep(1);
254*5861f966SKonstantin Belousov while (state != 5)
255*5861f966SKonstantin Belousov ;
256*5861f966SKonstantin Belousov if (write(fd, "", 1) != 1)
257*5861f966SKonstantin Belousov err(1, "write");
258*5861f966SKonstantin Belousov kill(cpid, SIGUSR1);
259*5861f966SKonstantin Belousov
260*5861f966SKonstantin Belousov usleep(1);
261*5861f966SKonstantin Belousov while (state != 6)
262*5861f966SKonstantin Belousov ;
263*5861f966SKonstantin Belousov if (close(fd) != 0)
264*5861f966SKonstantin Belousov err(1, "close for write");
265*5861f966SKonstantin Belousov kill(cpid, SIGUSR1);
266*5861f966SKonstantin Belousov
267*5861f966SKonstantin Belousov usleep(1);
268*5861f966SKonstantin Belousov while (state != 7)
269*5861f966SKonstantin Belousov ;
270*5861f966SKonstantin Belousov }
271*5861f966SKonstantin Belousov
272*5861f966SKonstantin Belousov int
main(void)273*5861f966SKonstantin Belousov main(void)
274*5861f966SKonstantin Belousov {
275*5861f966SKonstantin Belousov int fd[2], num;
276*5861f966SKonstantin Belousov
277*5861f966SKonstantin Belousov num = 1;
278*5861f966SKonstantin Belousov printf("1..20\n");
279*5861f966SKonstantin Belousov fflush(stdout);
280*5861f966SKonstantin Belousov signal(SIGUSR1, catch);
281*5861f966SKonstantin Belousov ppid = getpid();
282*5861f966SKonstantin Belousov for (filetype = 0; filetype < FT_END; filetype++) {
283*5861f966SKonstantin Belousov switch (filetype) {
284*5861f966SKonstantin Belousov case FT_FIFO:
285*5861f966SKonstantin Belousov if (mkfifo(FIFONAME, 0666) != 0)
286*5861f966SKonstantin Belousov err(1, "mkfifo");
287*5861f966SKonstantin Belousov fd[0] = -1;
288*5861f966SKonstantin Belousov fd[1] = -1;
289*5861f966SKonstantin Belousov break;
290*5861f966SKonstantin Belousov case FT_SOCKETPAIR:
291*5861f966SKonstantin Belousov if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC,
292*5861f966SKonstantin Belousov fd) != 0)
293*5861f966SKonstantin Belousov err(1, "socketpair");
294*5861f966SKonstantin Belousov break;
295*5861f966SKonstantin Belousov case FT_PIPE:
296*5861f966SKonstantin Belousov if (pipe(fd) != 0)
297*5861f966SKonstantin Belousov err(1, "pipe");
298*5861f966SKonstantin Belousov break;
299*5861f966SKonstantin Belousov }
300*5861f966SKonstantin Belousov state = 0;
301*5861f966SKonstantin Belousov switch (cpid = fork()) {
302*5861f966SKonstantin Belousov case -1:
303*5861f966SKonstantin Belousov err(1, "fork");
304*5861f966SKonstantin Belousov case 0:
305*5861f966SKonstantin Belousov (void)close(fd[1]);
306*5861f966SKonstantin Belousov child(fd[0], num);
307*5861f966SKonstantin Belousov break;
308*5861f966SKonstantin Belousov default:
309*5861f966SKonstantin Belousov (void)close(fd[0]);
310*5861f966SKonstantin Belousov parent(fd[1]);
311*5861f966SKonstantin Belousov break;
312*5861f966SKonstantin Belousov }
313*5861f966SKonstantin Belousov num += filetype == FT_FIFO ? 12 : 4;
314*5861f966SKonstantin Belousov }
315*5861f966SKonstantin Belousov (void)unlink(FIFONAME);
316*5861f966SKonstantin Belousov return (0);
317*5861f966SKonstantin Belousov }
318