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