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 46static int desc; 47 48static void 49child1(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 60static void 61child2(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 73static void 74child3(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 87ATF_TC(3way); 88ATF_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 99ATF_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 150ATF_TC(basic); 151ATF_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 158ATF_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 217ATF_TC(err); 218ATF_TC_HEAD(err, tc) 219{ 220 atf_tc_set_md_var(tc, "descr", "Check errors from poll(2)"); 221} 222 223ATF_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 238static const char fifo_path[] = "pollhup_fifo"; 239 240static void 241fifo_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 256ATF_TC_WITH_CLEANUP(fifo_inout); 257ATF_TC_HEAD(fifo_inout, tc) 258{ 259 atf_tc_set_md_var(tc, "descr", 260 "Check POLLIN/POLLOUT behavior with fifos"); 261} 262 263ATF_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 358ATF_TC_CLEANUP(fifo_inout, tc) 359{ 360 (void)unlink(fifo_path); 361} 362 363ATF_TC_WITH_CLEANUP(fifo_hup1); 364ATF_TC_HEAD(fifo_hup1, tc) 365{ 366 atf_tc_set_md_var(tc, "descr", 367 "Check POLLHUP behavior with fifos [1]"); 368} 369 370ATF_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 403ATF_TC_CLEANUP(fifo_hup1, tc) 404{ 405 (void)unlink(fifo_path); 406} 407 408ATF_TC_WITH_CLEANUP(fifo_hup2); 409ATF_TC_HEAD(fifo_hup2, tc) 410{ 411 atf_tc_set_md_var(tc, "descr", 412 "Check POLLHUP behavior with fifos [2]"); 413} 414 415ATF_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 453ATF_TC_CLEANUP(fifo_hup2, tc) 454{ 455 (void)unlink(fifo_path); 456} 457 458ATF_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