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 *
decode_events(int events)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
report_state(const char * state)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
report(int num,const char * state,int expected,int got,int res,int res_expected)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
catch(int sig __unused)83 catch(int sig __unused)
84 {
85
86 state++;
87 }
88
89 static void
child(int fd,int num)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
parent(int fd)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
main(void)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 }
322