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