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