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