1 /* $NetBSD: t_poll.c,v 1.8 2021/10/02 17:32:55 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2011 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matthias Scheler.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/stat.h>
33 #include <sys/time.h>
34 #include <sys/wait.h>
35
36 #include <atf-c.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <paths.h>
40 #include <poll.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <signal.h>
44 #include <unistd.h>
45
46 static int desc;
47
48 static void
child1(void)49 child1(void)
50 {
51 struct pollfd pfd;
52
53 pfd.fd = desc;
54 pfd.events = POLLIN | POLLHUP | POLLOUT;
55
56 (void)poll(&pfd, 1, 2000);
57 (void)printf("child1 exit\n");
58 }
59
60 static void
child2(void)61 child2(void)
62 {
63 struct pollfd pfd;
64
65 pfd.fd = desc;
66 pfd.events = POLLIN | POLLHUP | POLLOUT;
67
68 (void)sleep(1);
69 (void)poll(&pfd, 1, INFTIM);
70 (void)printf("child2 exit\n");
71 }
72
73 static void
child3(void)74 child3(void)
75 {
76 struct pollfd pfd;
77
78 (void)sleep(5);
79
80 pfd.fd = desc;
81 pfd.events = POLLIN | POLLHUP | POLLOUT;
82
83 (void)poll(&pfd, 1, INFTIM);
84 (void)printf("child3 exit\n");
85 }
86
87 ATF_TC(3way);
88 ATF_TC_HEAD(3way, tc)
89 {
90 atf_tc_set_md_var(tc, "timeout", "15");
91 atf_tc_set_md_var(tc, "descr",
92 "Check for 3-way collision for descriptor. First child comes "
93 "and polls on descriptor, second child comes and polls, first "
94 "child times out and exits, third child comes and polls. When "
95 "the wakeup event happens, the two remaining children should "
96 "both be awaken. (kern/17517)");
97 }
98
99 ATF_TC_BODY(3way, tc)
100 {
101 int pf[2];
102 int status, i;
103 pid_t pid;
104
105 pipe(pf);
106 desc = pf[0];
107
108 pid = fork();
109 ATF_REQUIRE(pid >= 0);
110
111 if (pid == 0) {
112 (void)close(pf[1]);
113 child1();
114 _exit(0);
115 /* NOTREACHED */
116 }
117
118 pid = fork();
119 ATF_REQUIRE(pid >= 0);
120
121 if (pid == 0) {
122 (void)close(pf[1]);
123 child2();
124 _exit(0);
125 /* NOTREACHED */
126 }
127
128 pid = fork();
129 ATF_REQUIRE( pid >= 0);
130
131 if (pid == 0) {
132 (void)close(pf[1]);
133 child3();
134 _exit(0);
135 /* NOTREACHED */
136 }
137
138 (void)sleep(10);
139
140 (void)printf("parent write\n");
141
142 ATF_REQUIRE(write(pf[1], "konec\n", 6) == 6);
143
144 for(i = 0; i < 3; ++i)
145 (void)wait(&status);
146
147 (void)printf("parent terminated\n");
148 }
149
150 ATF_TC(basic);
ATF_TC_HEAD(basic,tc)151 ATF_TC_HEAD(basic, tc)
152 {
153 atf_tc_set_md_var(tc, "timeout", "10");
154 atf_tc_set_md_var(tc, "descr",
155 "Basis functionality test for poll(2)");
156 }
157
ATF_TC_BODY(basic,tc)158 ATF_TC_BODY(basic, tc)
159 {
160 int fds[2];
161 struct pollfd pfds[2];
162 int ret;
163
164 ATF_REQUIRE_EQ(pipe(fds), 0);
165
166 pfds[0].fd = fds[0];
167 pfds[0].events = POLLIN;
168 pfds[1].fd = fds[1];
169 pfds[1].events = POLLOUT;
170
171 /*
172 * Check that we get a timeout waiting for data on the read end
173 * of our pipe.
174 */
175 pfds[0].revents = -1;
176 pfds[1].revents = -1;
177 ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[0], 1, 1), 0,
178 "got: %d", ret);
179 ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
180 ATF_REQUIRE_EQ_MSG(pfds[1].revents, -1, "got: %d", pfds[1].revents);
181
182 /* Check that the write end of the pipe as reported as ready. */
183 pfds[0].revents = -1;
184 pfds[1].revents = -1;
185 ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[1], 1, 1), 1,
186 "got: %d", ret);
187 ATF_REQUIRE_EQ_MSG(pfds[0].revents, -1, "got: %d", pfds[0].revents);
188 ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",\
189 pfds[1].revents);
190
191 /* Check that only the write end of the pipe as reported as ready. */
192 pfds[0].revents = -1;
193 pfds[1].revents = -1;
194 ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 1,
195 "got: %d", ret);
196 ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
197 ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
198 pfds[1].revents);
199
200 /* Write data to our pipe. */
201 ATF_REQUIRE_EQ(write(fds[1], "", 1), 1);
202
203 /* Check that both ends of our pipe are reported as ready. */
204 pfds[0].revents = -1;
205 pfds[1].revents = -1;
206 ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 2,
207 "got: %d", ret);
208 ATF_REQUIRE_EQ_MSG(pfds[0].revents, POLLIN, "got: %d",
209 pfds[0].revents);
210 ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
211 pfds[1].revents);
212
213 ATF_REQUIRE_EQ(close(fds[0]), 0);
214 ATF_REQUIRE_EQ(close(fds[1]), 0);
215 }
216
217 ATF_TC(err);
ATF_TC_HEAD(err,tc)218 ATF_TC_HEAD(err, tc)
219 {
220 atf_tc_set_md_var(tc, "descr", "Check errors from poll(2)");
221 }
222
ATF_TC_BODY(err,tc)223 ATF_TC_BODY(err, tc)
224 {
225 struct pollfd pfd;
226 int fd = 0;
227
228 pfd.fd = fd;
229 pfd.events = POLLIN;
230
231 errno = 0;
232 ATF_REQUIRE_ERRNO(EFAULT, poll((struct pollfd *)-1, 1, -1) == -1);
233
234 errno = 0;
235 ATF_REQUIRE_ERRNO(EINVAL, poll(&pfd, 1, -2) == -1);
236 }
237
238 static const char fifo_path[] = "pollhup_fifo";
239
240 static void
fifo_support(void)241 fifo_support(void)
242 {
243 errno = 0;
244 if (mkfifo(fifo_path, 0600) == 0) {
245 ATF_REQUIRE(unlink(fifo_path) == 0);
246 return;
247 }
248
249 if (errno == EOPNOTSUPP) {
250 atf_tc_skip("the kernel does not support FIFOs");
251 } else {
252 atf_tc_fail("mkfifo(2) failed");
253 }
254 }
255
256 ATF_TC_WITH_CLEANUP(fifo_inout);
ATF_TC_HEAD(fifo_inout,tc)257 ATF_TC_HEAD(fifo_inout, tc)
258 {
259 atf_tc_set_md_var(tc, "descr",
260 "Check POLLIN/POLLOUT behavior with fifos");
261 }
262
ATF_TC_BODY(fifo_inout,tc)263 ATF_TC_BODY(fifo_inout, tc)
264 {
265 struct pollfd pfd[2];
266 char *buf;
267 int rfd, wfd;
268 long pipe_buf;
269
270 fifo_support();
271
272 ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0);
273 ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0);
274 ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY | O_NONBLOCK)) >= 0);
275
276 /* Get the maximum atomic pipe write size. */
277 pipe_buf = fpathconf(wfd, _PC_PIPE_BUF);
278 ATF_REQUIRE(pipe_buf > 1);
279
280 buf = malloc(pipe_buf);
281 ATF_REQUIRE(buf != NULL);
282
283 memset(&pfd, 0, sizeof(pfd));
284 pfd[0].fd = rfd;
285 pfd[0].events = POLLIN | POLLRDNORM;
286 pfd[1].fd = wfd;
287 pfd[1].events = POLLOUT | POLLWRNORM;
288
289 /* We expect the FIFO to be writable but not readable. */
290 ATF_REQUIRE(poll(pfd, 2, 0) == 1);
291 ATF_REQUIRE(pfd[0].revents == 0);
292 ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM));
293
294 /* Write a single byte of data into the FIFO. */
295 ATF_REQUIRE(write(wfd, buf, 1) == 1);
296
297 /* We expect the FIFO to be readable and writable. */
298 ATF_REQUIRE(poll(pfd, 2, 0) == 2);
299 ATF_REQUIRE(pfd[0].revents == (POLLIN | POLLRDNORM));
300 ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM));
301
302 /* Read that single byte back out. */
303 ATF_REQUIRE(read(rfd, buf, 1) == 1);
304
305 /*
306 * Write data into the FIFO until it is full, which is
307 * defined as insufficient buffer space to hold a the
308 * maximum atomic pipe write size.
309 */
310 while (write(wfd, buf, pipe_buf) != -1) {
311 continue;
312 }
313 ATF_REQUIRE(errno == EAGAIN);
314
315 /* We expect the FIFO to be readble but not writable. */
316 ATF_REQUIRE(poll(pfd, 2, 0) == 1);
317 ATF_REQUIRE(pfd[0].revents == (POLLIN | POLLRDNORM));
318 ATF_REQUIRE(pfd[1].revents == 0);
319
320 /* Read a single byte of data from the FIFO. */
321 ATF_REQUIRE(read(rfd, buf, 1) == 1);
322
323 /*
324 * Because we have read only a single byte out, there will
325 * be insufficient space for a pipe_buf-sized message, so
326 * the FIFO should still not be writable.
327 */
328 ATF_REQUIRE(poll(pfd, 2, 0) == 1);
329 ATF_REQUIRE(pfd[0].revents == (POLLIN | POLLRDNORM));
330 ATF_REQUIRE(pfd[1].revents == 0);
331
332 /*
333 * Now read enough so that exactly pipe_buf space should
334 * be available. The FIFO should be writable after that.
335 * N.B. we don't care if it's readable at this point.
336 */
337 ATF_REQUIRE(read(rfd, buf, pipe_buf - 1) == pipe_buf - 1);
338 ATF_REQUIRE(poll(pfd, 2, 0) >= 1);
339 ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM));
340
341 /*
342 * Now read all of the data out of the FIFO and ensure that
343 * we get back to the initial state.
344 */
345 while (read(rfd, buf, pipe_buf) != -1) {
346 continue;
347 }
348 ATF_REQUIRE(errno == EAGAIN);
349
350 ATF_REQUIRE(poll(pfd, 2, 0) == 1);
351 ATF_REQUIRE(pfd[0].revents == 0);
352 ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM));
353
354 (void)close(wfd);
355 (void)close(rfd);
356 }
357
ATF_TC_CLEANUP(fifo_inout,tc)358 ATF_TC_CLEANUP(fifo_inout, tc)
359 {
360 (void)unlink(fifo_path);
361 }
362
363 ATF_TC_WITH_CLEANUP(fifo_hup1);
ATF_TC_HEAD(fifo_hup1,tc)364 ATF_TC_HEAD(fifo_hup1, tc)
365 {
366 atf_tc_set_md_var(tc, "descr",
367 "Check POLLHUP behavior with fifos [1]");
368 }
369
ATF_TC_BODY(fifo_hup1,tc)370 ATF_TC_BODY(fifo_hup1, tc)
371 {
372 struct pollfd pfd;
373 int rfd, wfd;
374
375 fifo_support();
376
377 ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0);
378 ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0);
379 ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0);
380
381 memset(&pfd, 0, sizeof(pfd));
382 pfd.fd = rfd;
383 pfd.events = POLLIN;
384
385 (void)close(wfd);
386
387 ATF_REQUIRE(poll(&pfd, 1, 0) == 1);
388 ATF_REQUIRE((pfd.revents & POLLHUP) != 0);
389
390 /*
391 * Check that POLLHUP is cleared when a writer re-connects.
392 * Since the writer will not put any data into the FIFO, we
393 * expect no events.
394 */
395 memset(&pfd, 0, sizeof(pfd));
396 pfd.fd = rfd;
397 pfd.events = POLLIN;
398
399 ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0);
400 ATF_REQUIRE(poll(&pfd, 1, 0) == 0);
401 }
402
ATF_TC_CLEANUP(fifo_hup1,tc)403 ATF_TC_CLEANUP(fifo_hup1, tc)
404 {
405 (void)unlink(fifo_path);
406 }
407
408 ATF_TC_WITH_CLEANUP(fifo_hup2);
ATF_TC_HEAD(fifo_hup2,tc)409 ATF_TC_HEAD(fifo_hup2, tc)
410 {
411 atf_tc_set_md_var(tc, "descr",
412 "Check POLLHUP behavior with fifos [2]");
413 }
414
ATF_TC_BODY(fifo_hup2,tc)415 ATF_TC_BODY(fifo_hup2, tc)
416 {
417 struct pollfd pfd;
418 int rfd, wfd;
419 pid_t pid;
420 struct timespec ts1, ts2;
421
422 fifo_support();
423
424 ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0);
425 ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0);
426 ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0);
427
428 memset(&pfd, 0, sizeof(pfd));
429 pfd.fd = rfd;
430 pfd.events = POLLIN;
431
432 pid = fork();
433 ATF_REQUIRE(pid >= 0);
434
435 if (pid == 0) {
436 (void)close(rfd);
437 sleep(5);
438 (void)close(wfd);
439 _exit(0);
440 }
441 (void)close(wfd);
442
443 ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts1) == 0);
444 ATF_REQUIRE(poll(&pfd, 1, INFTIM) == 1);
445 ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts2) == 0);
446
447 /* Make sure at least a couple of seconds have elapsed. */
448 ATF_REQUIRE(ts2.tv_sec - ts1.tv_sec >= 2);
449
450 ATF_REQUIRE((pfd.revents & POLLHUP) != 0);
451 }
452
ATF_TC_CLEANUP(fifo_hup2,tc)453 ATF_TC_CLEANUP(fifo_hup2, tc)
454 {
455 (void)unlink(fifo_path);
456 }
457
ATF_TP_ADD_TCS(tp)458 ATF_TP_ADD_TCS(tp)
459 {
460
461 ATF_TP_ADD_TC(tp, 3way);
462 ATF_TP_ADD_TC(tp, basic);
463 ATF_TP_ADD_TC(tp, err);
464
465 ATF_TP_ADD_TC(tp, fifo_inout);
466 ATF_TP_ADD_TC(tp, fifo_hup1);
467 ATF_TP_ADD_TC(tp, fifo_hup2);
468
469 return atf_no_error();
470 }
471