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