xref: /netbsd-src/tests/lib/libc/sys/t_timerfd.c (revision 53b02e147d4ed531c0d2a5ca9b3e8026ba3e99b5)
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