Home | History | Annotate | Line # | Download | only in sys
t_poll.c revision 1.5
      1 /*	$NetBSD: t_poll.c,v 1.5 2021/10/02 02:07:41 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 <signal.h>
     43 #include <unistd.h>
     44 
     45 static int desc;
     46 
     47 static void
     48 child1(void)
     49 {
     50 	struct pollfd pfd;
     51 
     52 	pfd.fd = desc;
     53 	pfd.events = POLLIN | POLLHUP | POLLOUT;
     54 
     55 	(void)poll(&pfd, 1, 2000);
     56 	(void)printf("child1 exit\n");
     57 }
     58 
     59 static void
     60 child2(void)
     61 {
     62 	struct pollfd pfd;
     63 
     64 	pfd.fd = desc;
     65 	pfd.events = POLLIN | POLLHUP | POLLOUT;
     66 
     67 	(void)sleep(1);
     68 	(void)poll(&pfd, 1, INFTIM);
     69 	(void)printf("child2 exit\n");
     70 }
     71 
     72 static void
     73 child3(void)
     74 {
     75 	struct pollfd pfd;
     76 
     77 	(void)sleep(5);
     78 
     79 	pfd.fd = desc;
     80 	pfd.events = POLLIN | POLLHUP | POLLOUT;
     81 
     82 	(void)poll(&pfd, 1, INFTIM);
     83 	(void)printf("child3 exit\n");
     84 }
     85 
     86 ATF_TC(3way);
     87 ATF_TC_HEAD(3way, tc)
     88 {
     89 	atf_tc_set_md_var(tc, "timeout", "15");
     90 	atf_tc_set_md_var(tc, "descr",
     91 	    "Check for 3-way collision for descriptor. First child comes "
     92 	    "and polls on descriptor, second child comes and polls, first "
     93 	    "child times out and exits, third child comes and polls. When "
     94 	    "the wakeup event happens, the two remaining children should "
     95 	    "both be awaken. (kern/17517)");
     96 }
     97 
     98 ATF_TC_BODY(3way, tc)
     99 {
    100 	int pf[2];
    101 	int status, i;
    102 	pid_t pid;
    103 
    104 	pipe(pf);
    105 	desc = pf[0];
    106 
    107 	pid = fork();
    108 	ATF_REQUIRE(pid >= 0);
    109 
    110 	if (pid == 0) {
    111 		(void)close(pf[1]);
    112 		child1();
    113 		_exit(0);
    114 		/* NOTREACHED */
    115 	}
    116 
    117 	pid = fork();
    118 	ATF_REQUIRE(pid >= 0);
    119 
    120 	if (pid == 0) {
    121 		(void)close(pf[1]);
    122 		child2();
    123 		_exit(0);
    124 		/* NOTREACHED */
    125 	}
    126 
    127 	pid = fork();
    128 	ATF_REQUIRE( pid >= 0);
    129 
    130 	if (pid == 0) {
    131 		(void)close(pf[1]);
    132 		child3();
    133 		_exit(0);
    134 		/* NOTREACHED */
    135 	}
    136 
    137 	(void)sleep(10);
    138 
    139 	(void)printf("parent write\n");
    140 
    141 	ATF_REQUIRE(write(pf[1], "konec\n", 6) == 6);
    142 
    143 	for(i = 0; i < 3; ++i)
    144 		(void)wait(&status);
    145 
    146 	(void)printf("parent terminated\n");
    147 }
    148 
    149 ATF_TC(basic);
    150 ATF_TC_HEAD(basic, tc)
    151 {
    152 	atf_tc_set_md_var(tc, "timeout", "10");
    153 	atf_tc_set_md_var(tc, "descr",
    154 	    "Basis functionality test for poll(2)");
    155 }
    156 
    157 ATF_TC_BODY(basic, tc)
    158 {
    159 	int fds[2];
    160 	struct pollfd pfds[2];
    161 	int ret;
    162 
    163 	ATF_REQUIRE_EQ(pipe(fds), 0);
    164 
    165 	pfds[0].fd = fds[0];
    166 	pfds[0].events = POLLIN;
    167 	pfds[1].fd = fds[1];
    168 	pfds[1].events = POLLOUT;
    169 
    170 	/*
    171 	 * Check that we get a timeout waiting for data on the read end
    172 	 * of our pipe.
    173 	 */
    174 	pfds[0].revents = -1;
    175 	pfds[1].revents = -1;
    176 	ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[0], 1, 1), 0,
    177 	    "got: %d", ret);
    178 	ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
    179 	ATF_REQUIRE_EQ_MSG(pfds[1].revents, -1, "got: %d", pfds[1].revents);
    180 
    181 	/* Check that the write end of the pipe as reported as ready. */
    182 	pfds[0].revents = -1;
    183 	pfds[1].revents = -1;
    184 	ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[1], 1, 1), 1,
    185 	    "got: %d", ret);
    186 	ATF_REQUIRE_EQ_MSG(pfds[0].revents, -1, "got: %d", pfds[0].revents);
    187 	ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",\
    188 	    pfds[1].revents);
    189 
    190 	/* Check that only the write end of the pipe as reported as ready. */
    191 	pfds[0].revents = -1;
    192 	pfds[1].revents = -1;
    193 	ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 1,
    194 	    "got: %d", ret);
    195 	ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
    196 	ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
    197 	    pfds[1].revents);
    198 
    199 	/* Write data to our pipe. */
    200 	ATF_REQUIRE_EQ(write(fds[1], "", 1), 1);
    201 
    202 	/* Check that both ends of our pipe are reported as ready. */
    203 	pfds[0].revents = -1;
    204 	pfds[1].revents = -1;
    205 	ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 2,
    206 	    "got: %d", ret);
    207 	ATF_REQUIRE_EQ_MSG(pfds[0].revents, POLLIN, "got: %d",
    208 	    pfds[0].revents);
    209 	ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
    210 	    pfds[1].revents);
    211 
    212 	ATF_REQUIRE_EQ(close(fds[0]), 0);
    213 	ATF_REQUIRE_EQ(close(fds[1]), 0);
    214 }
    215 
    216 ATF_TC(err);
    217 ATF_TC_HEAD(err, tc)
    218 {
    219 	atf_tc_set_md_var(tc, "descr", "Check errors from poll(2)");
    220 }
    221 
    222 ATF_TC_BODY(err, tc)
    223 {
    224 	struct pollfd pfd;
    225 	int fd = 0;
    226 
    227 	pfd.fd = fd;
    228 	pfd.events = POLLIN;
    229 
    230 	errno = 0;
    231 	ATF_REQUIRE_ERRNO(EFAULT, poll((struct pollfd *)-1, 1, -1) == -1);
    232 
    233 	errno = 0;
    234 	ATF_REQUIRE_ERRNO(EINVAL, poll(&pfd, 1, -2) == -1);
    235 }
    236 
    237 static const char	fifo_path[] = "pollhup_fifo";
    238 
    239 static void
    240 fifo_support(void)
    241 {
    242 	errno = 0;
    243 	if (mkfifo(fifo_path, 0600) == 0) {
    244 		ATF_REQUIRE(unlink(fifo_path) == 0);
    245 		return;
    246 	}
    247 
    248 	if (errno == EOPNOTSUPP) {
    249 		atf_tc_skip("the kernel does not support FIFOs");
    250 	} else {
    251 		atf_tc_fail("mkfifo(2) failed");
    252 	}
    253 }
    254 
    255 ATF_TC_WITH_CLEANUP(fifo_hup1);
    256 ATF_TC_HEAD(fifo_hup1, tc)
    257 {
    258 	atf_tc_set_md_var(tc, "descr",
    259 	    "Check POLLHUP behavior with fifos [1]");
    260 }
    261 
    262 ATF_TC_BODY(fifo_hup1, tc)
    263 {
    264 	struct pollfd pfd;
    265 	int rfd, wfd;
    266 
    267 	fifo_support();
    268 
    269 	ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0);
    270 	ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0);
    271 	ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0);
    272 
    273 	memset(&pfd, 0, sizeof(pfd));
    274 	pfd.fd = rfd;
    275 	pfd.events = POLLIN;
    276 
    277 	(void)close(wfd);
    278 
    279 	ATF_REQUIRE(poll(&pfd, 1, 0) == 1);
    280 	ATF_REQUIRE((pfd.revents & POLLHUP) != 0);
    281 }
    282 
    283 ATF_TC_CLEANUP(fifo_hup1, tc)
    284 {
    285 	(void)unlink(fifo_path);
    286 }
    287 
    288 ATF_TC_WITH_CLEANUP(fifo_hup2);
    289 ATF_TC_HEAD(fifo_hup2, tc)
    290 {
    291 	atf_tc_set_md_var(tc, "descr",
    292 	    "Check POLLHUP behavior with fifos [2]");
    293 }
    294 
    295 ATF_TC_BODY(fifo_hup2, tc)
    296 {
    297 	struct pollfd pfd;
    298 	int rfd, wfd;
    299 	pid_t pid;
    300 	struct timespec ts1, ts2;
    301 
    302 	fifo_support();
    303 
    304 	ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0);
    305 	ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0);
    306 	ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0);
    307 
    308 	memset(&pfd, 0, sizeof(pfd));
    309 	pfd.fd = rfd;
    310 	pfd.events = POLLIN;
    311 
    312 	pid = fork();
    313 	ATF_REQUIRE(pid >= 0);
    314 
    315 	if (pid == 0) {
    316 		(void)close(rfd);
    317 		sleep(5);
    318 		(void)close(wfd);
    319 		_exit(0);
    320 	}
    321 	(void)close(wfd);
    322 
    323 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts1) == 0);
    324 	ATF_REQUIRE(poll(&pfd, 1, INFTIM) == 1);
    325 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts2) == 0);
    326 
    327 	/* Make sure at least a couple of seconds have elapsed. */
    328 	ATF_REQUIRE(ts2.tv_sec - ts1.tv_sec >= 2);
    329 
    330 	ATF_REQUIRE((pfd.revents & POLLHUP) != 0);
    331 }
    332 
    333 ATF_TC_CLEANUP(fifo_hup2, tc)
    334 {
    335 	(void)unlink(fifo_path);
    336 }
    337 
    338 ATF_TP_ADD_TCS(tp)
    339 {
    340 
    341 	ATF_TP_ADD_TC(tp, 3way);
    342 	ATF_TP_ADD_TC(tp, basic);
    343 	ATF_TP_ADD_TC(tp, err);
    344 
    345 	ATF_TP_ADD_TC(tp, fifo_hup1);
    346 	ATF_TP_ADD_TC(tp, fifo_hup2);
    347 
    348 	return atf_no_error();
    349 }
    350