Home | History | Annotate | Line # | Download | only in sys
t_timerfd.c revision 1.3
      1 /* $NetBSD: t_timerfd.c,v 1.3 2021/11/01 14:33:41 hannken Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2020 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __COPYRIGHT("@(#) Copyright (c) 2020\
     31  The NetBSD Foundation, inc. All rights reserved.");
     32 __RCSID("$NetBSD: t_timerfd.c,v 1.3 2021/11/01 14:33:41 hannken Exp $");
     33 
     34 #include <sys/types.h>
     35 #include <sys/event.h>
     36 #include <sys/select.h>
     37 #include <sys/stat.h>
     38 #include <sys/syscall.h>
     39 #include <sys/timerfd.h>
     40 #include <errno.h>
     41 #include <poll.h>
     42 #include <pthread.h>
     43 #include <stdlib.h>
     44 #include <stdio.h>
     45 #include <time.h>
     46 #include <unistd.h>
     47 
     48 #include <atf-c.h>
     49 
     50 #include "isqemu.h"
     51 
     52 struct helper_context {
     53 	int	fd;
     54 
     55 	pthread_barrier_t barrier;
     56 };
     57 
     58 static void
     59 init_helper_context(struct helper_context * const ctx)
     60 {
     61 
     62 	memset(ctx, 0, sizeof(*ctx));
     63 
     64 	ATF_REQUIRE(pthread_barrier_init(&ctx->barrier, NULL, 2) == 0);
     65 }
     66 
     67 static bool
     68 wait_barrier(struct helper_context * const ctx)
     69 {
     70 	int rv = pthread_barrier_wait(&ctx->barrier);
     71 
     72 	return rv == 0 || rv == PTHREAD_BARRIER_SERIAL_THREAD;
     73 }
     74 
     75 static bool
     76 check_value_against_bounds(uint64_t value, uint64_t lower, uint64_t upper)
     77 {
     78 
     79 	/*
     80 	 * If running under QEMU make sure the upper bound is large
     81 	 * enough for the effect of kern/43997
     82 	 */
     83 	if (isQEMU()) {
     84 		upper *= 4;
     85 	}
     86 
     87 	if (value < lower || value > upper) {
     88 		printf("val %" PRIu64 " not in [ %" PRIu64 ", %" PRIu64 " ]\n",
     89 		    value, lower, upper);
     90 	}
     91 
     92 	return value >= lower && value <= upper;
     93 }
     94 
     95 /*****************************************************************************/
     96 
     97 static int
     98 timerfd_read(int fd, uint64_t *valp)
     99 {
    100 	uint64_t val;
    101 
    102 	switch (read(fd, &val, sizeof(val))) {
    103 	case -1:
    104 		return -1;
    105 
    106 	case sizeof(val):
    107 		*valp = val;
    108 		return 0;
    109 
    110 	default:
    111 		/* ?? Should never happen. */
    112 		errno = EIO;
    113 		return -1;
    114 	}
    115 }
    116 
    117 /*****************************************************************************/
    118 
    119 ATF_TC(timerfd_create);
    120 ATF_TC_HEAD(timerfd_create, tc)
    121 {
    122 	atf_tc_set_md_var(tc, "descr", "validates timerfd_create()");
    123 }
    124 ATF_TC_BODY(timerfd_create, tc)
    125 {
    126 	int fd;
    127 
    128 	ATF_REQUIRE((fd = timerfd_create(CLOCK_REALTIME, 0)) >= 0);
    129 	(void) close(fd);
    130 
    131 	ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0);
    132 	(void) close(fd);
    133 
    134 	ATF_REQUIRE_ERRNO(EINVAL,
    135 	    (fd = timerfd_create(CLOCK_VIRTUAL, 0)) == -1);
    136 
    137 	ATF_REQUIRE_ERRNO(EINVAL,
    138 	    (fd = timerfd_create(CLOCK_PROF, 0)) == -1);
    139 
    140 	ATF_REQUIRE_ERRNO(EINVAL,
    141 	    (fd = timerfd_create(CLOCK_REALTIME,
    142 	    			    ~(TFD_CLOEXEC | TFD_NONBLOCK))) == -1);
    143 }
    144 
    145 /*****************************************************************************/
    146 
    147 ATF_TC(timerfd_bogusfd);
    148 ATF_TC_HEAD(timerfd_bogusfd, tc)
    149 {
    150 	atf_tc_set_md_var(tc, "descr",
    151 	    "validates rejection of bogus fds by timerfd_{get,set}time()");
    152 }
    153 ATF_TC_BODY(timerfd_bogusfd, tc)
    154 {
    155 	struct itimerspec its = { 0 };
    156 	int fd;
    157 
    158 	ATF_REQUIRE((fd = kqueue()) >= 0);	/* arbitrary fd type */
    159 
    160 	ATF_REQUIRE_ERRNO(EINVAL,
    161 	    timerfd_gettime(fd, &its) == -1);
    162 
    163 	its.it_value.tv_sec = 5;
    164 	ATF_REQUIRE_ERRNO(EINVAL,
    165 	    timerfd_settime(fd, 0, &its, NULL) == -1);
    166 
    167 	(void) close(fd);
    168 }
    169 
    170 /*****************************************************************************/
    171 
    172 ATF_TC(timerfd_block);
    173 ATF_TC_HEAD(timerfd_block, tc)
    174 {
    175 	atf_tc_set_md_var(tc, "descr", "validates blocking behavior");
    176 }
    177 ATF_TC_BODY(timerfd_block, tc)
    178 {
    179 	struct timespec then, now, delta;
    180 	uint64_t val;
    181 	int fd;
    182 
    183 	ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0);
    184 
    185 	const struct itimerspec its = {
    186 		.it_value = { .tv_sec = 1, .tv_nsec = 0 },
    187 		.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
    188 	};
    189 
    190 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
    191 	ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0);
    192 	ATF_REQUIRE(timerfd_read(fd, &val) == 0);
    193 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
    194 	ATF_REQUIRE(check_value_against_bounds(val, 1, 1));
    195 
    196 	timespecsub(&now, &then, &delta);
    197 	ATF_REQUIRE(check_value_against_bounds(delta.tv_sec, 1, 1));
    198 
    199 	(void) close(fd);
    200 }
    201 
    202 /*****************************************************************************/
    203 
    204 ATF_TC(timerfd_repeating);
    205 ATF_TC_HEAD(timerfd_repeating, tc)
    206 {
    207 	atf_tc_set_md_var(tc, "descr", "validates repeating timer behavior");
    208 }
    209 ATF_TC_BODY(timerfd_repeating, tc)
    210 {
    211 	struct timespec then, now, delta;
    212 	uint64_t val;
    213 	int fd;
    214 
    215 	ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC,
    216 					    TFD_NONBLOCK)) >= 0);
    217 
    218 	const struct itimerspec its = {
    219 		.it_value = { .tv_sec = 0, .tv_nsec = 200000000 },
    220 		.it_interval = { .tv_sec = 0, .tv_nsec = 200000000 },
    221 	};
    222 
    223 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
    224 	ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0);
    225 	ATF_REQUIRE(sleep(1) == 0);
    226 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
    227 	ATF_REQUIRE(timerfd_read(fd, &val) == 0);
    228 	/* allow some slop */
    229 	ATF_REQUIRE(check_value_against_bounds(val, 3, 5));
    230 
    231 	timespecsub(&now, &then, &delta);
    232 	ATF_REQUIRE(check_value_against_bounds(delta.tv_sec, 1, 1));
    233 
    234 	(void) close(fd);
    235 }
    236 
    237 /*****************************************************************************/
    238 
    239 ATF_TC(timerfd_abstime);
    240 ATF_TC_HEAD(timerfd_abstime, tc)
    241 {
    242 	atf_tc_set_md_var(tc, "descr", "validates specifying abstime");
    243 }
    244 ATF_TC_BODY(timerfd_abstime, tc)
    245 {
    246 	struct timespec then, now, delta;
    247 	uint64_t val;
    248 	int fd;
    249 
    250 	ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0);
    251 
    252 	struct itimerspec its = {
    253 		.it_value = { .tv_sec = 0, .tv_nsec = 0 },
    254 		.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
    255 	};
    256 
    257 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
    258 	its.it_value = then;
    259 	its.it_value.tv_sec += 1;
    260 	ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL) == 0);
    261 	ATF_REQUIRE(timerfd_read(fd, &val) == 0);
    262 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
    263 	ATF_REQUIRE(check_value_against_bounds(val, 1, 1));
    264 
    265 	timespecsub(&now, &then, &delta);
    266 	ATF_REQUIRE(check_value_against_bounds(delta.tv_sec, 1, 1));
    267 
    268 	(void) close(fd);
    269 }
    270 
    271 /*****************************************************************************/
    272 
    273 ATF_TC(timerfd_cancel_on_set_immed);
    274 ATF_TC_HEAD(timerfd_cancel_on_set_immed, tc)
    275 {
    276 	atf_tc_set_md_var(tc, "descr", "validates cancel-on-set - immediate");
    277 	atf_tc_set_md_var(tc, "require.user", "root");
    278 }
    279 ATF_TC_BODY(timerfd_cancel_on_set_immed, tc)
    280 {
    281 	struct timespec now;
    282 	uint64_t val;
    283 	int fd;
    284 
    285 	ATF_REQUIRE((fd = timerfd_create(CLOCK_REALTIME, 0)) >= 0);
    286 
    287 	const struct itimerspec its = {
    288 		.it_value = { .tv_sec = 60 * 60, .tv_nsec = 0 },
    289 		.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
    290 	};
    291 
    292 	ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &now) == 0);
    293 	ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_CANCEL_ON_SET,
    294 				    &its, NULL) == 0);
    295 	ATF_REQUIRE(clock_settime(CLOCK_REALTIME, &now) == 0);
    296 	ATF_REQUIRE_ERRNO(ECANCELED, timerfd_read(fd, &val) == -1);
    297 
    298 	(void) close(fd);
    299 }
    300 
    301 /*****************************************************************************/
    302 
    303 static void *
    304 timerfd_cancel_on_set_block_helper(void * const v)
    305 {
    306 	struct helper_context * const ctx = v;
    307 	struct timespec now;
    308 
    309 	ATF_REQUIRE(wait_barrier(ctx));
    310 
    311 	ATF_REQUIRE(sleep(2) == 0);
    312 	ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &now) == 0);
    313 	ATF_REQUIRE(clock_settime(CLOCK_REALTIME, &now) == 0);
    314 
    315 	return NULL;
    316 }
    317 
    318 ATF_TC(timerfd_cancel_on_set_block);
    319 ATF_TC_HEAD(timerfd_cancel_on_set_block, tc)
    320 {
    321 	atf_tc_set_md_var(tc, "descr", "validates cancel-on-set - blocking");
    322 	atf_tc_set_md_var(tc, "require.user", "root");
    323 }
    324 ATF_TC_BODY(timerfd_cancel_on_set_block, tc)
    325 {
    326 	struct helper_context ctx;
    327 	pthread_t helper;
    328 	void *join_val;
    329 	uint64_t val;
    330 	int fd;
    331 
    332 	ATF_REQUIRE((fd = timerfd_create(CLOCK_REALTIME, 0)) >= 0);
    333 
    334 	const struct itimerspec its = {
    335 		.it_value = { .tv_sec = 60 * 60, .tv_nsec = 0 },
    336 		.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
    337 	};
    338 
    339 	init_helper_context(&ctx);
    340 
    341 	ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_CANCEL_ON_SET,
    342 				    &its, NULL) == 0);
    343 	ATF_REQUIRE(pthread_create(&helper, NULL,
    344 				timerfd_cancel_on_set_block_helper, &ctx) == 0);
    345 	ATF_REQUIRE(wait_barrier(&ctx));
    346 	ATF_REQUIRE_ERRNO(ECANCELED, timerfd_read(fd, &val) == -1);
    347 
    348 	ATF_REQUIRE(pthread_join(helper, &join_val) == 0);
    349 
    350 	(void) close(fd);
    351 }
    352 
    353 /*****************************************************************************/
    354 
    355 ATF_TC(timerfd_select_poll_kevent_immed);
    356 ATF_TC_HEAD(timerfd_select_poll_kevent_immed, tc)
    357 {
    358 	atf_tc_set_md_var(tc, "descr",
    359 	    "validates select/poll/kevent behavior - immediate return");
    360 }
    361 ATF_TC_BODY(timerfd_select_poll_kevent_immed, tc)
    362 {
    363 	const struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
    364 	struct itimerspec its;
    365 	struct timeval tv;
    366 	struct stat st;
    367 	struct pollfd fds[1];
    368 	uint64_t val;
    369 	fd_set readfds, writefds, exceptfds;
    370 	int fd;
    371 	int kq;
    372 	struct kevent kev[1];
    373 
    374 	ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) >= 0);
    375 
    376 	ATF_REQUIRE((kq = kqueue()) >= 0);
    377 	EV_SET(&kev[0], fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
    378 	ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, &ts) == 0);
    379 
    380 	/*
    381 	 * fd should be writable but not readable.  Pass all of the
    382 	 * event bits; we should only get back POLLOUT | POLLWRNORM.
    383 	 * (It's writable only in so far as we'll get an error if we try.)
    384 	 */
    385 	fds[0].fd = fd;
    386 	fds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI |
    387 	    POLLOUT | POLLWRNORM | POLLWRBAND | POLLHUP;
    388 	fds[0].revents = 0;
    389 	ATF_REQUIRE(poll(fds, 1, 0) == 1);
    390 	ATF_REQUIRE(fds[0].revents == (POLLOUT | POLLWRNORM));
    391 
    392 	/*
    393 	 * As above; fd should only be set in writefds upon return
    394 	 * from the select() call.
    395 	 */
    396 	FD_ZERO(&readfds);
    397 	FD_ZERO(&writefds);
    398 	FD_ZERO(&exceptfds);
    399 	tv.tv_sec = 0;
    400 	tv.tv_usec = 0;
    401 	FD_SET(fd, &readfds);
    402 	FD_SET(fd, &writefds);
    403 	FD_SET(fd, &exceptfds);
    404 	ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 1);
    405 	ATF_REQUIRE(!FD_ISSET(fd, &readfds));
    406 	ATF_REQUIRE(FD_ISSET(fd, &writefds));
    407 	ATF_REQUIRE(!FD_ISSET(fd, &exceptfds));
    408 
    409 	/*
    410 	 * Now set a one-shot half-second timer, wait for it to expire, and
    411 	 * then check again.
    412 	 */
    413 	memset(&its, 0, sizeof(its));
    414 	its.it_value.tv_sec = 0;
    415 	its.it_value.tv_nsec = 500000000;
    416 	ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0);
    417 	ATF_REQUIRE(sleep(2) == 0);
    418 
    419 	/* Verify it actually fired via the stat() back-channel. */
    420 	ATF_REQUIRE(fstat(fd, &st) == 0);
    421 	ATF_REQUIRE(st.st_size == 1);
    422 
    423 	fds[0].fd = fd;
    424 	fds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI |
    425 	    POLLOUT | POLLWRNORM | POLLWRBAND | POLLHUP;
    426 	fds[0].revents = 0;
    427 	ATF_REQUIRE(poll(fds, 1, 0) == 1);
    428 	ATF_REQUIRE(fds[0].revents == (POLLIN | POLLRDNORM |
    429 				       POLLOUT | POLLWRNORM));
    430 
    431 	FD_ZERO(&readfds);
    432 	FD_ZERO(&writefds);
    433 	FD_ZERO(&exceptfds);
    434 	tv.tv_sec = 0;
    435 	tv.tv_usec = 0;
    436 	FD_SET(fd, &readfds);
    437 	FD_SET(fd, &writefds);
    438 	FD_SET(fd, &exceptfds);
    439 	ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 2);
    440 	ATF_REQUIRE(FD_ISSET(fd, &readfds));
    441 	ATF_REQUIRE(FD_ISSET(fd, &writefds));
    442 	ATF_REQUIRE(!FD_ISSET(fd, &exceptfds));
    443 
    444 	/*
    445 	 * Check that we get an EVFILT_READ event on fd.
    446 	 */
    447 	memset(kev, 0, sizeof(kev));
    448 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, 1, &ts) == 1);
    449 	ATF_REQUIRE(kev[0].ident == (uintptr_t)fd);
    450 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
    451 	ATF_REQUIRE((kev[0].flags & (EV_EOF | EV_ERROR)) == 0);
    452 	ATF_REQUIRE(kev[0].data == 1);
    453 
    454 	/*
    455 	 * Read the timerfd to ensure we get the correct numnber of
    456 	 * expirations.
    457 	 */
    458 	ATF_REQUIRE(timerfd_read(fd, &val) == 0);
    459 	ATF_REQUIRE(val == 1);
    460 
    461 	/* And ensure that we would block if we tried again. */
    462 	ATF_REQUIRE_ERRNO(EAGAIN, timerfd_read(fd, &val) == -1);
    463 
    464 	(void) close(kq);
    465 	(void) close(fd);
    466 }
    467 
    468 /*****************************************************************************/
    469 
    470 ATF_TC(timerfd_select_poll_kevent_block);
    471 ATF_TC_HEAD(timerfd_select_poll_kevent_block, tc)
    472 {
    473 	atf_tc_set_md_var(tc, "descr",
    474 	    "validates select/poll/kevent behavior - blocking");
    475 }
    476 ATF_TC_BODY(timerfd_select_poll_kevent_block, tc)
    477 {
    478 	const struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
    479 	struct timespec then, now;
    480 	struct pollfd fds[1];
    481 	fd_set readfds;
    482 	int fd;
    483 	int kq;
    484 	struct kevent kev[1];
    485 
    486 	ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) >= 0);
    487 
    488 	ATF_REQUIRE((kq = kqueue()) >= 0);
    489 	EV_SET(&kev[0], fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
    490 	ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, &ts) == 0);
    491 
    492 	/*
    493 	 * For each of these tests, we do the following:
    494 	 *
    495 	 * - Get the current time.
    496 	 * - Set a 1-second one-shot timer.
    497 	 * - Block in the multiplexing call.
    498 	 * - Get the current time and verify that the timer expiration
    499 	 *   interval has passed.
    500 	 */
    501 
    502 	const struct itimerspec its = {
    503 		.it_value = { .tv_sec = 1, .tv_nsec = 0 },
    504 		.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
    505 	};
    506 
    507 	/* poll(2) */
    508 	fds[0].fd = fd;
    509 	fds[0].events = POLLIN | POLLRDNORM;
    510 	fds[0].revents = 0;
    511 
    512 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
    513 	ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0);
    514 	ATF_REQUIRE(poll(fds, 1, INFTIM) == 1);
    515 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
    516 	ATF_REQUIRE(fds[0].revents == (POLLIN | POLLRDNORM));
    517 	ATF_REQUIRE(now.tv_sec - then.tv_sec >= 1);
    518 
    519 	/* select(2) */
    520 	FD_ZERO(&readfds);
    521 	FD_SET(fd, &readfds);
    522 
    523 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
    524 	ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0);
    525 	ATF_REQUIRE(select(fd + 1, &readfds, NULL, NULL, NULL) == 1);
    526 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
    527 	ATF_REQUIRE(FD_ISSET(fd, &readfds));
    528 	ATF_REQUIRE(now.tv_sec - then.tv_sec >= 1);
    529 
    530 	/* kevent(2) */
    531 	memset(kev, 0, sizeof(kev));
    532 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
    533 	ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0);
    534 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, 1, NULL) == 1);
    535 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
    536 	ATF_REQUIRE(kev[0].ident == (uintptr_t)fd);
    537 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
    538 	ATF_REQUIRE((kev[0].flags & (EV_EOF | EV_ERROR)) == 0);
    539 	ATF_REQUIRE(kev[0].data == 1);
    540 
    541 	(void) close(kq);
    542 	(void) close(fd);
    543 }
    544 
    545 /*****************************************************************************/
    546 
    547 static void *
    548 timerfd_restart_helper(void * const v)
    549 {
    550 	struct helper_context * const ctx = v;
    551 
    552 	ATF_REQUIRE(wait_barrier(ctx));
    553 
    554 	/*
    555 	 * Wait 5 seconds (that should give the main thread time to
    556 	 * block), and then close the descriptor.
    557 	 */
    558 	ATF_REQUIRE(sleep(5) == 0);
    559 	ATF_REQUIRE(close(ctx->fd) == 0);
    560 
    561 	return NULL;
    562 }
    563 
    564 ATF_TC(timerfd_restart);
    565 ATF_TC_HEAD(timerfd_restart, tc)
    566 {
    567 	atf_tc_set_md_var(tc, "descr",
    568 	    "exercises the 'restart' fileop code path");
    569 }
    570 ATF_TC_BODY(timerfd_restart, tc)
    571 {
    572 	struct timespec then, now, delta;
    573 	struct helper_context ctx;
    574 	uint64_t val;
    575 	pthread_t helper;
    576 	void *join_val;
    577 
    578 	init_helper_context(&ctx);
    579 
    580 	ATF_REQUIRE((ctx.fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0);
    581 
    582 	const struct itimerspec its = {
    583 		.it_value = { .tv_sec = 60 * 60, .tv_nsec = 0 },
    584 		.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
    585 	};
    586 	ATF_REQUIRE(timerfd_settime(ctx.fd, 0, &its, NULL) == 0);
    587 
    588 
    589 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
    590 	ATF_REQUIRE(pthread_create(&helper, NULL,
    591 				   timerfd_restart_helper, &ctx) == 0);
    592 
    593 	/*
    594 	 * Wait for the helper to be ready, and then immediately block
    595 	 * in read().  The helper will close the file, and we should get
    596 	 * EBADF after a few seconds.
    597 	 */
    598 	ATF_REQUIRE(wait_barrier(&ctx));
    599 	ATF_REQUIRE_ERRNO(EBADF, timerfd_read(ctx.fd, &val) == -1);
    600 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
    601 
    602 	timespecsub(&now, &then, &delta);
    603 	ATF_REQUIRE(delta.tv_sec >= 5);
    604 
    605 	/* Reap the helper. */
    606 	ATF_REQUIRE(pthread_join(helper, &join_val) == 0);
    607 }
    608 
    609 /*****************************************************************************/
    610 
    611 ATF_TP_ADD_TCS(tp)
    612 {
    613 	ATF_TP_ADD_TC(tp, timerfd_create);
    614 	ATF_TP_ADD_TC(tp, timerfd_bogusfd);
    615 	ATF_TP_ADD_TC(tp, timerfd_block);
    616 	ATF_TP_ADD_TC(tp, timerfd_repeating);
    617 	ATF_TP_ADD_TC(tp, timerfd_abstime);
    618 	ATF_TP_ADD_TC(tp, timerfd_cancel_on_set_block);
    619 	ATF_TP_ADD_TC(tp, timerfd_cancel_on_set_immed);
    620 	ATF_TP_ADD_TC(tp, timerfd_select_poll_kevent_immed);
    621 	ATF_TP_ADD_TC(tp, timerfd_select_poll_kevent_block);
    622 	ATF_TP_ADD_TC(tp, timerfd_restart);
    623 
    624 	return atf_no_error();
    625 }
    626