Home | History | Annotate | Line # | Download | only in sys
t_poll.c revision 1.8
      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
     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
     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
     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);
    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 
    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);
    218 ATF_TC_HEAD(err, tc)
    219 {
    220 	atf_tc_set_md_var(tc, "descr", "Check errors from poll(2)");
    221 }
    222 
    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
    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);
    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 
    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 
    358 ATF_TC_CLEANUP(fifo_inout, tc)
    359 {
    360 	(void)unlink(fifo_path);
    361 }
    362 
    363 ATF_TC_WITH_CLEANUP(fifo_hup1);
    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 
    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 
    403 ATF_TC_CLEANUP(fifo_hup1, tc)
    404 {
    405 	(void)unlink(fifo_path);
    406 }
    407 
    408 ATF_TC_WITH_CLEANUP(fifo_hup2);
    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 
    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 
    453 ATF_TC_CLEANUP(fifo_hup2, tc)
    454 {
    455 	(void)unlink(fifo_path);
    456 }
    457 
    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