xref: /netbsd-src/tests/lib/libc/sys/t_timerfd.c (revision 7778e81a140d6795646045feb8cc503ccce4d7f8)
1*7778e81aSriastradh /* $NetBSD: t_timerfd.c,v 1.11 2024/12/19 23:50:22 riastradh Exp $ */
2e714af64Sthorpej 
3e714af64Sthorpej /*-
4e714af64Sthorpej  * Copyright (c) 2020 The NetBSD Foundation, Inc.
5e714af64Sthorpej  * All rights reserved.
6e714af64Sthorpej  *
7e714af64Sthorpej  * Redistribution and use in source and binary forms, with or without
8e714af64Sthorpej  * modification, are permitted provided that the following conditions
9e714af64Sthorpej  * are met:
10e714af64Sthorpej  * 1. Redistributions of source code must retain the above copyright
11e714af64Sthorpej  *    notice, this list of conditions and the following disclaimer.
12e714af64Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
13e714af64Sthorpej  *    notice, this list of conditions and the following disclaimer in the
14e714af64Sthorpej  *    documentation and/or other materials provided with the distribution.
15e714af64Sthorpej  *
16e714af64Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17e714af64Sthorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18e714af64Sthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19e714af64Sthorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20e714af64Sthorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21e714af64Sthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22e714af64Sthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23e714af64Sthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24e714af64Sthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25e714af64Sthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26e714af64Sthorpej  * POSSIBILITY OF SUCH DAMAGE.
27e714af64Sthorpej  */
28e714af64Sthorpej 
29e714af64Sthorpej #include <sys/cdefs.h>
30e714af64Sthorpej __COPYRIGHT("@(#) Copyright (c) 2020\
31e714af64Sthorpej  The NetBSD Foundation, inc. All rights reserved.");
32*7778e81aSriastradh __RCSID("$NetBSD: t_timerfd.c,v 1.11 2024/12/19 23:50:22 riastradh Exp $");
33e714af64Sthorpej 
34e714af64Sthorpej #include <sys/types.h>
35bcd5a23fSriastradh 
36e714af64Sthorpej #include <sys/event.h>
37f92afe1eSthorpej #include <sys/ioctl.h>
38e714af64Sthorpej #include <sys/select.h>
39e714af64Sthorpej #include <sys/stat.h>
40e714af64Sthorpej #include <sys/syscall.h>
41e714af64Sthorpej #include <sys/timerfd.h>
42bcd5a23fSriastradh 
43e714af64Sthorpej #include <errno.h>
44e714af64Sthorpej #include <poll.h>
45e714af64Sthorpej #include <pthread.h>
46e714af64Sthorpej #include <stdio.h>
47bcd5a23fSriastradh #include <stdlib.h>
48e714af64Sthorpej #include <time.h>
49e714af64Sthorpej #include <unistd.h>
50e714af64Sthorpej 
51e714af64Sthorpej #include <atf-c.h>
52e714af64Sthorpej 
53bcd5a23fSriastradh #include "h_macros.h"
54f75cd5d6Shannken #include "isqemu.h"
55f75cd5d6Shannken 
56e714af64Sthorpej struct helper_context {
57e714af64Sthorpej 	int	fd;
58e714af64Sthorpej 
59e714af64Sthorpej 	pthread_barrier_t barrier;
60e714af64Sthorpej };
61e714af64Sthorpej 
62e714af64Sthorpej static void
63e714af64Sthorpej init_helper_context(struct helper_context * const ctx)
64e714af64Sthorpej {
65e714af64Sthorpej 
66e714af64Sthorpej 	memset(ctx, 0, sizeof(*ctx));
67e714af64Sthorpej 
68e714af64Sthorpej 	ATF_REQUIRE(pthread_barrier_init(&ctx->barrier, NULL, 2) == 0);
69e714af64Sthorpej }
70e714af64Sthorpej 
71e714af64Sthorpej static bool
72e714af64Sthorpej wait_barrier(struct helper_context * const ctx)
73e714af64Sthorpej {
74e714af64Sthorpej 	int rv = pthread_barrier_wait(&ctx->barrier);
75e714af64Sthorpej 
76e714af64Sthorpej 	return rv == 0 || rv == PTHREAD_BARRIER_SERIAL_THREAD;
77e714af64Sthorpej }
78e714af64Sthorpej 
79f75cd5d6Shannken static bool
80f75cd5d6Shannken check_value_against_bounds(uint64_t value, uint64_t lower, uint64_t upper)
81f75cd5d6Shannken {
82f75cd5d6Shannken 
83f75cd5d6Shannken 	/*
84f75cd5d6Shannken 	 * If running under QEMU make sure the upper bound is large
85f75cd5d6Shannken 	 * enough for the effect of kern/43997
86f75cd5d6Shannken 	 */
87f75cd5d6Shannken 	if (isQEMU()) {
88f75cd5d6Shannken 		upper *= 4;
89f75cd5d6Shannken 	}
90f75cd5d6Shannken 
91f75cd5d6Shannken 	if (value < lower || value > upper) {
92f75cd5d6Shannken 		printf("val %" PRIu64 " not in [ %" PRIu64 ", %" PRIu64 " ]\n",
93f75cd5d6Shannken 		    value, lower, upper);
94f75cd5d6Shannken 	}
95f75cd5d6Shannken 
96f75cd5d6Shannken 	return value >= lower && value <= upper;
97f75cd5d6Shannken }
98f75cd5d6Shannken 
99e714af64Sthorpej /*****************************************************************************/
100e714af64Sthorpej 
101e714af64Sthorpej static int
102e714af64Sthorpej timerfd_read(int fd, uint64_t *valp)
103e714af64Sthorpej {
104e714af64Sthorpej 	uint64_t val;
105e714af64Sthorpej 
106e714af64Sthorpej 	switch (read(fd, &val, sizeof(val))) {
107e714af64Sthorpej 	case -1:
108e714af64Sthorpej 		return -1;
109e714af64Sthorpej 
110e714af64Sthorpej 	case sizeof(val):
111e714af64Sthorpej 		*valp = val;
112e714af64Sthorpej 		return 0;
113e714af64Sthorpej 
114e714af64Sthorpej 	default:
115e714af64Sthorpej 		/* ?? Should never happen. */
116e714af64Sthorpej 		errno = EIO;
117e714af64Sthorpej 		return -1;
118e714af64Sthorpej 	}
119e714af64Sthorpej }
120e714af64Sthorpej 
121e714af64Sthorpej /*****************************************************************************/
122e714af64Sthorpej 
123e714af64Sthorpej ATF_TC(timerfd_create);
124e714af64Sthorpej ATF_TC_HEAD(timerfd_create, tc)
125e714af64Sthorpej {
126e714af64Sthorpej 	atf_tc_set_md_var(tc, "descr", "validates timerfd_create()");
127e714af64Sthorpej }
128e714af64Sthorpej ATF_TC_BODY(timerfd_create, tc)
129e714af64Sthorpej {
130e714af64Sthorpej 	int fd;
131e714af64Sthorpej 
132e714af64Sthorpej 	ATF_REQUIRE((fd = timerfd_create(CLOCK_REALTIME, 0)) >= 0);
133e714af64Sthorpej 	(void) close(fd);
134e714af64Sthorpej 
135e714af64Sthorpej 	ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0);
136e714af64Sthorpej 	(void) close(fd);
137e714af64Sthorpej 
138e714af64Sthorpej 	ATF_REQUIRE_ERRNO(EINVAL,
139e714af64Sthorpej 	    (fd = timerfd_create(CLOCK_VIRTUAL, 0)) == -1);
140e714af64Sthorpej 
141e714af64Sthorpej 	ATF_REQUIRE_ERRNO(EINVAL,
142e714af64Sthorpej 	    (fd = timerfd_create(CLOCK_PROF, 0)) == -1);
143e714af64Sthorpej 
144e714af64Sthorpej 	ATF_REQUIRE_ERRNO(EINVAL,
145e714af64Sthorpej 	    (fd = timerfd_create(CLOCK_REALTIME,
146e714af64Sthorpej 	    			    ~(TFD_CLOEXEC | TFD_NONBLOCK))) == -1);
147e714af64Sthorpej }
148e714af64Sthorpej 
149e714af64Sthorpej /*****************************************************************************/
150e714af64Sthorpej 
151bcd5a23fSriastradh ATF_TC(timerfd_write);
152bcd5a23fSriastradh ATF_TC_HEAD(timerfd_write, tc)
153bcd5a23fSriastradh {
154bcd5a23fSriastradh 	atf_tc_set_md_var(tc, "descr",
155bcd5a23fSriastradh 	    "validates rejection of writes to timerfds");
156bcd5a23fSriastradh }
157bcd5a23fSriastradh ATF_TC_BODY(timerfd_write, tc)
158bcd5a23fSriastradh {
159bcd5a23fSriastradh 	int fd;
160bcd5a23fSriastradh 	char c = 1;
161bcd5a23fSriastradh 
162bcd5a23fSriastradh 	RL(fd = timerfd_create(CLOCK_REALTIME, 0));
163bcd5a23fSriastradh 	ATF_CHECK_ERRNO(EBADF, write(fd, &c, 1) == -1);
164bcd5a23fSriastradh 	RL(close(fd));
165bcd5a23fSriastradh }
166bcd5a23fSriastradh 
167bcd5a23fSriastradh /*****************************************************************************/
168bcd5a23fSriastradh 
169e714af64Sthorpej ATF_TC(timerfd_bogusfd);
170e714af64Sthorpej ATF_TC_HEAD(timerfd_bogusfd, tc)
171e714af64Sthorpej {
172e714af64Sthorpej 	atf_tc_set_md_var(tc, "descr",
173e714af64Sthorpej 	    "validates rejection of bogus fds by timerfd_{get,set}time()");
174e714af64Sthorpej }
175e714af64Sthorpej ATF_TC_BODY(timerfd_bogusfd, tc)
176e714af64Sthorpej {
177e714af64Sthorpej 	struct itimerspec its = { 0 };
178e714af64Sthorpej 	int fd;
179e714af64Sthorpej 
180e714af64Sthorpej 	ATF_REQUIRE((fd = kqueue()) >= 0);	/* arbitrary fd type */
181e714af64Sthorpej 
182e714af64Sthorpej 	ATF_REQUIRE_ERRNO(EINVAL,
183e714af64Sthorpej 	    timerfd_gettime(fd, &its) == -1);
184e714af64Sthorpej 
185e714af64Sthorpej 	its.it_value.tv_sec = 5;
186e714af64Sthorpej 	ATF_REQUIRE_ERRNO(EINVAL,
187e714af64Sthorpej 	    timerfd_settime(fd, 0, &its, NULL) == -1);
188e714af64Sthorpej 
189e714af64Sthorpej 	(void) close(fd);
190e714af64Sthorpej }
191e714af64Sthorpej 
192e714af64Sthorpej /*****************************************************************************/
193e714af64Sthorpej 
194bcd5a23fSriastradh ATF_TC(timerfd_invalidtime);
195bcd5a23fSriastradh ATF_TC_HEAD(timerfd_invalidtime, tc)
196bcd5a23fSriastradh {
197bcd5a23fSriastradh 	atf_tc_set_md_var(tc, "descr",
198bcd5a23fSriastradh 	    "validates rejection of invalid itimerspec by timerfd_settime()");
199bcd5a23fSriastradh }
200bcd5a23fSriastradh ATF_TC_BODY(timerfd_invalidtime, tc)
201bcd5a23fSriastradh {
202bcd5a23fSriastradh 	const struct itimerspec einval_its[] = {
203bcd5a23fSriastradh 		[0] = { .it_value = {-1, 0} },
204bcd5a23fSriastradh 		[1] = { .it_value = {0, -1} },
205bcd5a23fSriastradh 		[2] = { .it_value = {0, 1000000001} },
206bcd5a23fSriastradh 		[3] = { .it_value = {1, 0}, .it_interval = {-1, 0} },
207bcd5a23fSriastradh 		[4] = { .it_value = {1, 0}, .it_interval = {0, -1} },
208bcd5a23fSriastradh 		[5] = { .it_value = {1, 0}, .it_interval = {0, 1000000001} },
209bcd5a23fSriastradh 	};
210bcd5a23fSriastradh 	struct timespec now;
211bcd5a23fSriastradh 	unsigned i;
212bcd5a23fSriastradh 	fd_set readfds;
213bcd5a23fSriastradh 	uint64_t val;
214bcd5a23fSriastradh 	int fd;
215bcd5a23fSriastradh 
216bcd5a23fSriastradh 	RL(clock_gettime(CLOCK_MONOTONIC, &now));
217bcd5a23fSriastradh 	RL(fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK));
218bcd5a23fSriastradh 
219bcd5a23fSriastradh 	for (i = 0; i < __arraycount(einval_its); i++) {
220bcd5a23fSriastradh 		struct itimerspec its;
221bcd5a23fSriastradh 
222bcd5a23fSriastradh 		fprintf(stderr, "case %u\n", i);
223bcd5a23fSriastradh 
224bcd5a23fSriastradh 		ATF_CHECK_ERRNO(EINVAL,
225bcd5a23fSriastradh 		    timerfd_settime(fd, 0, &einval_its[i], NULL) == -1);
226bcd5a23fSriastradh 
227bcd5a23fSriastradh 		/* Try the same with an absolute time near now. */
228bcd5a23fSriastradh 		its.it_value = einval_its[i].it_value;
229bcd5a23fSriastradh 		its.it_value.tv_sec += now.tv_sec + 60;
230bcd5a23fSriastradh 		ATF_CHECK_ERRNO(EINVAL,
231bcd5a23fSriastradh 		    timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL) == -1);
232bcd5a23fSriastradh 	}
233bcd5a23fSriastradh 
234bcd5a23fSriastradh 	/* Wait up to 2sec to make sure no timer got set anyway. */
235bcd5a23fSriastradh 	FD_ZERO(&readfds);
236bcd5a23fSriastradh 	FD_SET(fd, &readfds);
237bcd5a23fSriastradh 	RL(select(fd + 1, &readfds, NULL, NULL, &(struct timeval){2, 0}));
238bcd5a23fSriastradh 	ATF_CHECK(!FD_ISSET(fd, &readfds));
239bcd5a23fSriastradh 	ATF_CHECK_ERRNO(EAGAIN, timerfd_read(fd, &val) == -1);
240bcd5a23fSriastradh 
241bcd5a23fSriastradh 	RL(close(fd));
242bcd5a23fSriastradh }
243bcd5a23fSriastradh 
244bcd5a23fSriastradh /*****************************************************************************/
245bcd5a23fSriastradh 
246bcd5a23fSriastradh ATF_TC(timerfd_past);
247bcd5a23fSriastradh ATF_TC_HEAD(timerfd_past, tc)
248bcd5a23fSriastradh {
249bcd5a23fSriastradh 	atf_tc_set_md_var(tc, "descr", "validates trigger on past time");
250bcd5a23fSriastradh }
251bcd5a23fSriastradh ATF_TC_BODY(timerfd_past, tc)
252bcd5a23fSriastradh {
253bcd5a23fSriastradh 	struct itimerspec its = {.it_value = {-1, 0}, .it_interval = {0, 0}};
254bcd5a23fSriastradh 	struct timespec then, now, delta;
255bcd5a23fSriastradh 	uint64_t val;
256bcd5a23fSriastradh 	int fd;
257bcd5a23fSriastradh 
258bcd5a23fSriastradh 	RL(fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK));
259bcd5a23fSriastradh 
260bcd5a23fSriastradh 	RL(clock_gettime(CLOCK_MONOTONIC, &then));
261bcd5a23fSriastradh 	timespecadd(&then, &its.it_value, &its.it_value);
262bcd5a23fSriastradh 	RL(timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL));
263bcd5a23fSriastradh 
264bcd5a23fSriastradh 	/*
265bcd5a23fSriastradh 	 * Wait for one tick to pass.
266bcd5a23fSriastradh 	 *
267bcd5a23fSriastradh 	 * XXX Having to do this seems silly, but it matches Linux, so.
268bcd5a23fSriastradh 	 */
269bcd5a23fSriastradh 	RL(clock_nanosleep(CLOCK_MONOTONIC, 0, &(const struct timespec){0, 1},
270bcd5a23fSriastradh 		NULL));
271bcd5a23fSriastradh 
272bcd5a23fSriastradh 	RL(timerfd_read(fd, &val));
273bcd5a23fSriastradh 	RL(clock_gettime(CLOCK_MONOTONIC, &now));
274bcd5a23fSriastradh 	ATF_REQUIRE(check_value_against_bounds(val, 1, 1));
275bcd5a23fSriastradh 
276bcd5a23fSriastradh 	timespecsub(&now, &then, &delta);
277bcd5a23fSriastradh 	ATF_CHECK_MSG(check_value_against_bounds(delta.tv_sec, 0, 0),
278bcd5a23fSriastradh 	    "then=%jd.%09lu now=%jd.%09lu delta=%jd.%09lu",
279bcd5a23fSriastradh 	    (intmax_t)then.tv_sec, then.tv_nsec,
280bcd5a23fSriastradh 	    (intmax_t)now.tv_sec, now.tv_nsec,
281bcd5a23fSriastradh 	    (intmax_t)delta.tv_sec, delta.tv_nsec);
282bcd5a23fSriastradh 
283bcd5a23fSriastradh 	RL(close(fd));
284bcd5a23fSriastradh }
285bcd5a23fSriastradh 
286bcd5a23fSriastradh /*****************************************************************************/
287bcd5a23fSriastradh 
288e714af64Sthorpej ATF_TC(timerfd_block);
289e714af64Sthorpej ATF_TC_HEAD(timerfd_block, tc)
290e714af64Sthorpej {
291e714af64Sthorpej 	atf_tc_set_md_var(tc, "descr", "validates blocking behavior");
292e714af64Sthorpej }
293e714af64Sthorpej ATF_TC_BODY(timerfd_block, tc)
294e714af64Sthorpej {
295e714af64Sthorpej 	struct timespec then, now, delta;
296e714af64Sthorpej 	uint64_t val;
297e714af64Sthorpej 	int fd;
298e714af64Sthorpej 
299e714af64Sthorpej 	ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0);
300e714af64Sthorpej 
301f196a069Sriastradh 	struct itimerspec oits;
302e714af64Sthorpej 	const struct itimerspec its = {
303e714af64Sthorpej 		.it_value = { .tv_sec = 1, .tv_nsec = 0 },
304e714af64Sthorpej 		.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
305e714af64Sthorpej 	};
306e714af64Sthorpej 
307e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
308e714af64Sthorpej 	ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0);
309f196a069Sriastradh 	ATF_REQUIRE(timerfd_settime(fd, 0, &its, &oits) == 0);
310f196a069Sriastradh 	ATF_CHECK_MSG(timespeccmp(&oits.it_value, &its.it_value, <=),
311f196a069Sriastradh 	    "timerfd_settime returned %jd.%09lu remaining,"
312f196a069Sriastradh 	    " expected at most %jd.%09lu",
313f196a069Sriastradh 	    (intmax_t)oits.it_value.tv_sec, oits.it_value.tv_nsec,
314f196a069Sriastradh 	    (intmax_t)its.it_value.tv_sec, its.it_value.tv_nsec);
315e714af64Sthorpej 	ATF_REQUIRE(timerfd_read(fd, &val) == 0);
316e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
317f75cd5d6Shannken 	ATF_REQUIRE(check_value_against_bounds(val, 1, 1));
318e714af64Sthorpej 
319e714af64Sthorpej 	timespecsub(&now, &then, &delta);
320d60bdbc1Sriastradh 	ATF_REQUIRE_MSG(check_value_against_bounds(delta.tv_sec, 1, 1),
321d60bdbc1Sriastradh 	    "then=%jd.%09lu now=%jd.%09lu delta=%jd.%09lu",
322d60bdbc1Sriastradh 	    (intmax_t)then.tv_sec, then.tv_nsec,
323d60bdbc1Sriastradh 	    (intmax_t)now.tv_sec, now.tv_nsec,
324d60bdbc1Sriastradh 	    (intmax_t)delta.tv_sec, delta.tv_nsec);
325e714af64Sthorpej 
326e714af64Sthorpej 	(void) close(fd);
327e714af64Sthorpej }
328e714af64Sthorpej 
329e714af64Sthorpej /*****************************************************************************/
330e714af64Sthorpej 
331e714af64Sthorpej ATF_TC(timerfd_repeating);
332e714af64Sthorpej ATF_TC_HEAD(timerfd_repeating, tc)
333e714af64Sthorpej {
334e714af64Sthorpej 	atf_tc_set_md_var(tc, "descr", "validates repeating timer behavior");
335e714af64Sthorpej }
336e714af64Sthorpej ATF_TC_BODY(timerfd_repeating, tc)
337e714af64Sthorpej {
338e714af64Sthorpej 	struct timespec then, now, delta;
339e714af64Sthorpej 	uint64_t val;
340e714af64Sthorpej 	int fd;
341e714af64Sthorpej 
342e714af64Sthorpej 	ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC,
343e714af64Sthorpej 					    TFD_NONBLOCK)) >= 0);
344e714af64Sthorpej 
345e714af64Sthorpej 	const struct itimerspec its = {
346e714af64Sthorpej 		.it_value = { .tv_sec = 0, .tv_nsec = 200000000 },
347e714af64Sthorpej 		.it_interval = { .tv_sec = 0, .tv_nsec = 200000000 },
348e714af64Sthorpej 	};
349e714af64Sthorpej 
350e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
351e714af64Sthorpej 	ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0);
352e714af64Sthorpej 	ATF_REQUIRE(sleep(1) == 0);
353e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
354e714af64Sthorpej 	ATF_REQUIRE(timerfd_read(fd, &val) == 0);
355f75cd5d6Shannken 	/* allow some slop */
356f75cd5d6Shannken 	ATF_REQUIRE(check_value_against_bounds(val, 3, 5));
357e714af64Sthorpej 
358e714af64Sthorpej 	timespecsub(&now, &then, &delta);
359d60bdbc1Sriastradh 	ATF_REQUIRE_MSG(check_value_against_bounds(delta.tv_sec, 1, 1),
360d60bdbc1Sriastradh 	    "then=%jd.%09lu now=%jd.%09lu delta=%jd.%09lu",
361d60bdbc1Sriastradh 	    (intmax_t)then.tv_sec, then.tv_nsec,
362d60bdbc1Sriastradh 	    (intmax_t)now.tv_sec, now.tv_nsec,
363d60bdbc1Sriastradh 	    (intmax_t)delta.tv_sec, delta.tv_nsec);
364e714af64Sthorpej 
365e714af64Sthorpej 	(void) close(fd);
366e714af64Sthorpej }
367e714af64Sthorpej 
368e714af64Sthorpej /*****************************************************************************/
369e714af64Sthorpej 
370e714af64Sthorpej ATF_TC(timerfd_abstime);
371e714af64Sthorpej ATF_TC_HEAD(timerfd_abstime, tc)
372e714af64Sthorpej {
373e714af64Sthorpej 	atf_tc_set_md_var(tc, "descr", "validates specifying abstime");
374e714af64Sthorpej }
375e714af64Sthorpej ATF_TC_BODY(timerfd_abstime, tc)
376e714af64Sthorpej {
377e714af64Sthorpej 	struct timespec then, now, delta;
378e714af64Sthorpej 	uint64_t val;
379e714af64Sthorpej 	int fd;
380e714af64Sthorpej 
381e714af64Sthorpej 	ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0);
382e714af64Sthorpej 
383f196a069Sriastradh 	struct itimerspec oits, its = {
384e714af64Sthorpej 		.it_value = { .tv_sec = 0, .tv_nsec = 0 },
385e714af64Sthorpej 		.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
386e714af64Sthorpej 	};
387e714af64Sthorpej 
388e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
389f196a069Sriastradh 	delta = (struct timespec){1, 0};
390f196a069Sriastradh 	timespecadd(&then, &delta, &its.it_value);
391e714af64Sthorpej 	ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL) == 0);
392f196a069Sriastradh 	ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, &oits) == 0);
393f196a069Sriastradh 	timespecadd(&delta, (&(const struct timespec){2, 0}), /* tick slop */
394f196a069Sriastradh 	    &delta);
395f196a069Sriastradh 	ATF_CHECK_MSG(timespeccmp(&oits.it_value, &delta, <=),
396f196a069Sriastradh 	    "timerfd_settime returned %jd.%09lu remaining,"
397f196a069Sriastradh 	    " expected at most %jd.%09lu",
398f196a069Sriastradh 	    (intmax_t)oits.it_value.tv_sec, oits.it_value.tv_nsec,
399f196a069Sriastradh 	    (intmax_t)delta.tv_sec, delta.tv_nsec);
400e714af64Sthorpej 	ATF_REQUIRE(timerfd_read(fd, &val) == 0);
401e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
402f75cd5d6Shannken 	ATF_REQUIRE(check_value_against_bounds(val, 1, 1));
403e714af64Sthorpej 
404e714af64Sthorpej 	timespecsub(&now, &then, &delta);
405d60bdbc1Sriastradh 	ATF_REQUIRE_MSG(check_value_against_bounds(delta.tv_sec, 1, 1),
406d60bdbc1Sriastradh 	    "then=%jd.%09lu now=%jd.%09lu delta=%jd.%09lu",
407d60bdbc1Sriastradh 	    (intmax_t)then.tv_sec, then.tv_nsec,
408d60bdbc1Sriastradh 	    (intmax_t)now.tv_sec, now.tv_nsec,
409d60bdbc1Sriastradh 	    (intmax_t)delta.tv_sec, delta.tv_nsec);
410e714af64Sthorpej 
411e714af64Sthorpej 	(void) close(fd);
412e714af64Sthorpej }
413e714af64Sthorpej 
414e714af64Sthorpej /*****************************************************************************/
415e714af64Sthorpej 
416e714af64Sthorpej ATF_TC(timerfd_cancel_on_set_immed);
417e714af64Sthorpej ATF_TC_HEAD(timerfd_cancel_on_set_immed, tc)
418e714af64Sthorpej {
419e714af64Sthorpej 	atf_tc_set_md_var(tc, "descr", "validates cancel-on-set - immediate");
420e714af64Sthorpej 	atf_tc_set_md_var(tc, "require.user", "root");
421e714af64Sthorpej }
422e714af64Sthorpej ATF_TC_BODY(timerfd_cancel_on_set_immed, tc)
423e714af64Sthorpej {
424e714af64Sthorpej 	struct timespec now;
425e714af64Sthorpej 	uint64_t val;
426e714af64Sthorpej 	int fd;
427e714af64Sthorpej 
428e714af64Sthorpej 	ATF_REQUIRE((fd = timerfd_create(CLOCK_REALTIME, 0)) >= 0);
429e714af64Sthorpej 
430e714af64Sthorpej 	const struct itimerspec its = {
431e714af64Sthorpej 		.it_value = { .tv_sec = 60 * 60, .tv_nsec = 0 },
432e714af64Sthorpej 		.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
433e714af64Sthorpej 	};
434e714af64Sthorpej 
435e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &now) == 0);
436e714af64Sthorpej 	ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_CANCEL_ON_SET,
437e714af64Sthorpej 				    &its, NULL) == 0);
438e714af64Sthorpej 	ATF_REQUIRE(clock_settime(CLOCK_REALTIME, &now) == 0);
439e714af64Sthorpej 	ATF_REQUIRE_ERRNO(ECANCELED, timerfd_read(fd, &val) == -1);
440e714af64Sthorpej 
441e714af64Sthorpej 	(void) close(fd);
442e714af64Sthorpej }
443e714af64Sthorpej 
444e714af64Sthorpej /*****************************************************************************/
445e714af64Sthorpej 
446e714af64Sthorpej static void *
447e714af64Sthorpej timerfd_cancel_on_set_block_helper(void * const v)
448e714af64Sthorpej {
449e714af64Sthorpej 	struct helper_context * const ctx = v;
450e714af64Sthorpej 	struct timespec now;
451e714af64Sthorpej 
452e714af64Sthorpej 	ATF_REQUIRE(wait_barrier(ctx));
453e714af64Sthorpej 
454e714af64Sthorpej 	ATF_REQUIRE(sleep(2) == 0);
455e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &now) == 0);
456e714af64Sthorpej 	ATF_REQUIRE(clock_settime(CLOCK_REALTIME, &now) == 0);
457e714af64Sthorpej 
458e714af64Sthorpej 	return NULL;
459e714af64Sthorpej }
460e714af64Sthorpej 
461e714af64Sthorpej ATF_TC(timerfd_cancel_on_set_block);
462e714af64Sthorpej ATF_TC_HEAD(timerfd_cancel_on_set_block, tc)
463e714af64Sthorpej {
464e714af64Sthorpej 	atf_tc_set_md_var(tc, "descr", "validates cancel-on-set - blocking");
465e714af64Sthorpej 	atf_tc_set_md_var(tc, "require.user", "root");
466e714af64Sthorpej }
467e714af64Sthorpej ATF_TC_BODY(timerfd_cancel_on_set_block, tc)
468e714af64Sthorpej {
469e714af64Sthorpej 	struct helper_context ctx;
470e714af64Sthorpej 	pthread_t helper;
471e714af64Sthorpej 	void *join_val;
472e714af64Sthorpej 	uint64_t val;
473e714af64Sthorpej 	int fd;
474e714af64Sthorpej 
475e714af64Sthorpej 	ATF_REQUIRE((fd = timerfd_create(CLOCK_REALTIME, 0)) >= 0);
476e714af64Sthorpej 
477e714af64Sthorpej 	const struct itimerspec its = {
478e714af64Sthorpej 		.it_value = { .tv_sec = 60 * 60, .tv_nsec = 0 },
479e714af64Sthorpej 		.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
480e714af64Sthorpej 	};
481e714af64Sthorpej 
482e714af64Sthorpej 	init_helper_context(&ctx);
483e714af64Sthorpej 
484e714af64Sthorpej 	ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_CANCEL_ON_SET,
485e714af64Sthorpej 				    &its, NULL) == 0);
486e714af64Sthorpej 	ATF_REQUIRE(pthread_create(&helper, NULL,
487e714af64Sthorpej 				timerfd_cancel_on_set_block_helper, &ctx) == 0);
488e714af64Sthorpej 	ATF_REQUIRE(wait_barrier(&ctx));
489e714af64Sthorpej 	ATF_REQUIRE_ERRNO(ECANCELED, timerfd_read(fd, &val) == -1);
490e714af64Sthorpej 
491e714af64Sthorpej 	ATF_REQUIRE(pthread_join(helper, &join_val) == 0);
492e714af64Sthorpej 
493e714af64Sthorpej 	(void) close(fd);
494e714af64Sthorpej }
495e714af64Sthorpej 
496e714af64Sthorpej /*****************************************************************************/
497e714af64Sthorpej 
498e714af64Sthorpej ATF_TC(timerfd_select_poll_kevent_immed);
499e714af64Sthorpej ATF_TC_HEAD(timerfd_select_poll_kevent_immed, tc)
500e714af64Sthorpej {
501e714af64Sthorpej 	atf_tc_set_md_var(tc, "descr",
502e714af64Sthorpej 	    "validates select/poll/kevent behavior - immediate return");
503e714af64Sthorpej }
504e714af64Sthorpej ATF_TC_BODY(timerfd_select_poll_kevent_immed, tc)
505e714af64Sthorpej {
506e714af64Sthorpej 	const struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
507e714af64Sthorpej 	struct itimerspec its;
508e714af64Sthorpej 	struct timeval tv;
509e714af64Sthorpej 	struct stat st;
510e714af64Sthorpej 	struct pollfd fds[1];
511e714af64Sthorpej 	uint64_t val;
512e714af64Sthorpej 	fd_set readfds, writefds, exceptfds;
513e714af64Sthorpej 	int fd;
514e714af64Sthorpej 	int kq;
515e714af64Sthorpej 	struct kevent kev[1];
516e714af64Sthorpej 
517e714af64Sthorpej 	ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) >= 0);
518e714af64Sthorpej 
519e714af64Sthorpej 	ATF_REQUIRE((kq = kqueue()) >= 0);
520e714af64Sthorpej 	EV_SET(&kev[0], fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
521e714af64Sthorpej 	ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, &ts) == 0);
5228843a0bfSriastradh 	EV_SET(&kev[0], fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
5238843a0bfSriastradh 	ATF_CHECK_ERRNO(EINVAL, kevent(kq, kev, 1, NULL, 0, &ts) == -1);
524e714af64Sthorpej 
525e714af64Sthorpej 	/*
52654cb252aSriastradh 	 * fd should not be ready for anything.  Pass all of the event
52754cb252aSriastradh 	 * bits; we should get back nothing.
528e714af64Sthorpej 	 */
529e714af64Sthorpej 	fds[0].fd = fd;
530e714af64Sthorpej 	fds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI |
531e714af64Sthorpej 	    POLLOUT | POLLWRNORM | POLLWRBAND | POLLHUP;
532e714af64Sthorpej 	fds[0].revents = 0;
5338843a0bfSriastradh 	ATF_REQUIRE(poll(fds, 1, 0) == 0);
534e714af64Sthorpej 
535e714af64Sthorpej 	/*
53654cb252aSriastradh 	 * As above; fd should not be set on return from the select()
53754cb252aSriastradh 	 * call.
538e714af64Sthorpej 	 */
539e714af64Sthorpej 	FD_ZERO(&readfds);
540e714af64Sthorpej 	FD_ZERO(&writefds);
541e714af64Sthorpej 	FD_ZERO(&exceptfds);
542e714af64Sthorpej 	tv.tv_sec = 0;
543e714af64Sthorpej 	tv.tv_usec = 0;
544e714af64Sthorpej 	FD_SET(fd, &readfds);
545e714af64Sthorpej 	FD_SET(fd, &writefds);
546e714af64Sthorpej 	FD_SET(fd, &exceptfds);
5478843a0bfSriastradh 	ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 0);
548e714af64Sthorpej 	ATF_REQUIRE(!FD_ISSET(fd, &readfds));
54954cb252aSriastradh 	ATF_REQUIRE(!FD_ISSET(fd, &writefds));
550e714af64Sthorpej 	ATF_REQUIRE(!FD_ISSET(fd, &exceptfds));
551e714af64Sthorpej 
552e714af64Sthorpej 	/*
553e714af64Sthorpej 	 * Now set a one-shot half-second timer, wait for it to expire, and
554e714af64Sthorpej 	 * then check again.
555e714af64Sthorpej 	 */
556e714af64Sthorpej 	memset(&its, 0, sizeof(its));
557e714af64Sthorpej 	its.it_value.tv_sec = 0;
558e714af64Sthorpej 	its.it_value.tv_nsec = 500000000;
559e714af64Sthorpej 	ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0);
560e714af64Sthorpej 	ATF_REQUIRE(sleep(2) == 0);
561e714af64Sthorpej 
562e714af64Sthorpej 	/* Verify it actually fired via the stat() back-channel. */
563e714af64Sthorpej 	ATF_REQUIRE(fstat(fd, &st) == 0);
564e714af64Sthorpej 	ATF_REQUIRE(st.st_size == 1);
565e714af64Sthorpej 
566e714af64Sthorpej 	fds[0].fd = fd;
567e714af64Sthorpej 	fds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI |
568e714af64Sthorpej 	    POLLOUT | POLLWRNORM | POLLWRBAND | POLLHUP;
569e714af64Sthorpej 	fds[0].revents = 0;
570e714af64Sthorpej 	ATF_REQUIRE(poll(fds, 1, 0) == 1);
57154cb252aSriastradh 	ATF_REQUIRE(fds[0].revents == (POLLIN | POLLRDNORM));
572e714af64Sthorpej 
573e714af64Sthorpej 	FD_ZERO(&readfds);
574e714af64Sthorpej 	FD_ZERO(&writefds);
575e714af64Sthorpej 	FD_ZERO(&exceptfds);
576e714af64Sthorpej 	tv.tv_sec = 0;
577e714af64Sthorpej 	tv.tv_usec = 0;
578e714af64Sthorpej 	FD_SET(fd, &readfds);
579e714af64Sthorpej 	FD_SET(fd, &writefds);
580e714af64Sthorpej 	FD_SET(fd, &exceptfds);
5818843a0bfSriastradh 	ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 1);
582e714af64Sthorpej 	ATF_REQUIRE(FD_ISSET(fd, &readfds));
58354cb252aSriastradh 	ATF_REQUIRE(!FD_ISSET(fd, &writefds));
584e714af64Sthorpej 	ATF_REQUIRE(!FD_ISSET(fd, &exceptfds));
585e714af64Sthorpej 
586e714af64Sthorpej 	/*
587e714af64Sthorpej 	 * Check that we get an EVFILT_READ event on fd.
588e714af64Sthorpej 	 */
589e714af64Sthorpej 	memset(kev, 0, sizeof(kev));
590e714af64Sthorpej 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, 1, &ts) == 1);
591e714af64Sthorpej 	ATF_REQUIRE(kev[0].ident == (uintptr_t)fd);
592e714af64Sthorpej 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
593e714af64Sthorpej 	ATF_REQUIRE((kev[0].flags & (EV_EOF | EV_ERROR)) == 0);
594e714af64Sthorpej 	ATF_REQUIRE(kev[0].data == 1);
595e714af64Sthorpej 
596e714af64Sthorpej 	/*
597e714af64Sthorpej 	 * Read the timerfd to ensure we get the correct numnber of
598e714af64Sthorpej 	 * expirations.
599e714af64Sthorpej 	 */
600e714af64Sthorpej 	ATF_REQUIRE(timerfd_read(fd, &val) == 0);
601e714af64Sthorpej 	ATF_REQUIRE(val == 1);
602e714af64Sthorpej 
603e714af64Sthorpej 	/* And ensure that we would block if we tried again. */
604e714af64Sthorpej 	ATF_REQUIRE_ERRNO(EAGAIN, timerfd_read(fd, &val) == -1);
605e714af64Sthorpej 
606e714af64Sthorpej 	(void) close(kq);
607e714af64Sthorpej 	(void) close(fd);
608e714af64Sthorpej }
609e714af64Sthorpej 
610e714af64Sthorpej /*****************************************************************************/
611e714af64Sthorpej 
612e714af64Sthorpej ATF_TC(timerfd_select_poll_kevent_block);
613e714af64Sthorpej ATF_TC_HEAD(timerfd_select_poll_kevent_block, tc)
614e714af64Sthorpej {
615e714af64Sthorpej 	atf_tc_set_md_var(tc, "descr",
616e714af64Sthorpej 	    "validates select/poll/kevent behavior - blocking");
617e714af64Sthorpej }
618e714af64Sthorpej ATF_TC_BODY(timerfd_select_poll_kevent_block, tc)
619e714af64Sthorpej {
620e714af64Sthorpej 	const struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
621e714af64Sthorpej 	struct timespec then, now;
622e714af64Sthorpej 	struct pollfd fds[1];
623e714af64Sthorpej 	fd_set readfds;
624e714af64Sthorpej 	int fd;
625e714af64Sthorpej 	int kq;
626e714af64Sthorpej 	struct kevent kev[1];
627e714af64Sthorpej 
628e714af64Sthorpej 	ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) >= 0);
629e714af64Sthorpej 
630e714af64Sthorpej 	ATF_REQUIRE((kq = kqueue()) >= 0);
631e714af64Sthorpej 	EV_SET(&kev[0], fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
632e714af64Sthorpej 	ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, &ts) == 0);
633e714af64Sthorpej 
634e714af64Sthorpej 	/*
635e714af64Sthorpej 	 * For each of these tests, we do the following:
636e714af64Sthorpej 	 *
637e714af64Sthorpej 	 * - Get the current time.
638e714af64Sthorpej 	 * - Set a 1-second one-shot timer.
639e714af64Sthorpej 	 * - Block in the multiplexing call.
640e714af64Sthorpej 	 * - Get the current time and verify that the timer expiration
641e714af64Sthorpej 	 *   interval has passed.
642e714af64Sthorpej 	 */
643e714af64Sthorpej 
644e714af64Sthorpej 	const struct itimerspec its = {
645e714af64Sthorpej 		.it_value = { .tv_sec = 1, .tv_nsec = 0 },
646e714af64Sthorpej 		.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
647e714af64Sthorpej 	};
648e714af64Sthorpej 
649e714af64Sthorpej 	/* poll(2) */
650e714af64Sthorpej 	fds[0].fd = fd;
651e714af64Sthorpej 	fds[0].events = POLLIN | POLLRDNORM;
652e714af64Sthorpej 	fds[0].revents = 0;
653e714af64Sthorpej 
654e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
655e714af64Sthorpej 	ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0);
656e714af64Sthorpej 	ATF_REQUIRE(poll(fds, 1, INFTIM) == 1);
657e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
658e714af64Sthorpej 	ATF_REQUIRE(fds[0].revents == (POLLIN | POLLRDNORM));
659e714af64Sthorpej 	ATF_REQUIRE(now.tv_sec - then.tv_sec >= 1);
660e714af64Sthorpej 
661e714af64Sthorpej 	/* select(2) */
662e714af64Sthorpej 	FD_ZERO(&readfds);
663e714af64Sthorpej 	FD_SET(fd, &readfds);
664e714af64Sthorpej 
665e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
666e714af64Sthorpej 	ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0);
667e714af64Sthorpej 	ATF_REQUIRE(select(fd + 1, &readfds, NULL, NULL, NULL) == 1);
668e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
669e714af64Sthorpej 	ATF_REQUIRE(FD_ISSET(fd, &readfds));
670e714af64Sthorpej 	ATF_REQUIRE(now.tv_sec - then.tv_sec >= 1);
671e714af64Sthorpej 
672e714af64Sthorpej 	/* kevent(2) */
673e714af64Sthorpej 	memset(kev, 0, sizeof(kev));
674e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
675e714af64Sthorpej 	ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0);
676e714af64Sthorpej 	ATF_REQUIRE(kevent(kq, NULL, 0, kev, 1, NULL) == 1);
677e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
678e714af64Sthorpej 	ATF_REQUIRE(kev[0].ident == (uintptr_t)fd);
679e714af64Sthorpej 	ATF_REQUIRE(kev[0].filter == EVFILT_READ);
680e714af64Sthorpej 	ATF_REQUIRE((kev[0].flags & (EV_EOF | EV_ERROR)) == 0);
681e714af64Sthorpej 	ATF_REQUIRE(kev[0].data == 1);
682e714af64Sthorpej 
683e714af64Sthorpej 	(void) close(kq);
684e714af64Sthorpej 	(void) close(fd);
685e714af64Sthorpej }
686e714af64Sthorpej 
687e714af64Sthorpej /*****************************************************************************/
688e714af64Sthorpej 
689e714af64Sthorpej static void *
690e714af64Sthorpej timerfd_restart_helper(void * const v)
691e714af64Sthorpej {
692e714af64Sthorpej 	struct helper_context * const ctx = v;
693e714af64Sthorpej 
694e714af64Sthorpej 	ATF_REQUIRE(wait_barrier(ctx));
695e714af64Sthorpej 
696e714af64Sthorpej 	/*
697e714af64Sthorpej 	 * Wait 5 seconds (that should give the main thread time to
698e714af64Sthorpej 	 * block), and then close the descriptor.
699e714af64Sthorpej 	 */
700e714af64Sthorpej 	ATF_REQUIRE(sleep(5) == 0);
701e714af64Sthorpej 	ATF_REQUIRE(close(ctx->fd) == 0);
702e714af64Sthorpej 
703e714af64Sthorpej 	return NULL;
704e714af64Sthorpej }
705e714af64Sthorpej 
706e714af64Sthorpej ATF_TC(timerfd_restart);
707e714af64Sthorpej ATF_TC_HEAD(timerfd_restart, tc)
708e714af64Sthorpej {
709e714af64Sthorpej 	atf_tc_set_md_var(tc, "descr",
710e714af64Sthorpej 	    "exercises the 'restart' fileop code path");
711e714af64Sthorpej }
712e714af64Sthorpej ATF_TC_BODY(timerfd_restart, tc)
713e714af64Sthorpej {
714e714af64Sthorpej 	struct timespec then, now, delta;
715e714af64Sthorpej 	struct helper_context ctx;
716e714af64Sthorpej 	uint64_t val;
717e714af64Sthorpej 	pthread_t helper;
718e714af64Sthorpej 	void *join_val;
719e714af64Sthorpej 
720e714af64Sthorpej 	init_helper_context(&ctx);
721e714af64Sthorpej 
722e714af64Sthorpej 	ATF_REQUIRE((ctx.fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0);
723e714af64Sthorpej 
724e714af64Sthorpej 	const struct itimerspec its = {
725e714af64Sthorpej 		.it_value = { .tv_sec = 60 * 60, .tv_nsec = 0 },
726e714af64Sthorpej 		.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
727e714af64Sthorpej 	};
728e714af64Sthorpej 	ATF_REQUIRE(timerfd_settime(ctx.fd, 0, &its, NULL) == 0);
729e714af64Sthorpej 
730e714af64Sthorpej 
731e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
732e714af64Sthorpej 	ATF_REQUIRE(pthread_create(&helper, NULL,
733e714af64Sthorpej 				   timerfd_restart_helper, &ctx) == 0);
734e714af64Sthorpej 
735e714af64Sthorpej 	/*
736e714af64Sthorpej 	 * Wait for the helper to be ready, and then immediately block
737e714af64Sthorpej 	 * in read().  The helper will close the file, and we should get
738e714af64Sthorpej 	 * EBADF after a few seconds.
739e714af64Sthorpej 	 */
740e714af64Sthorpej 	ATF_REQUIRE(wait_barrier(&ctx));
741e714af64Sthorpej 	ATF_REQUIRE_ERRNO(EBADF, timerfd_read(ctx.fd, &val) == -1);
742e714af64Sthorpej 	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
743e714af64Sthorpej 
744e714af64Sthorpej 	timespecsub(&now, &then, &delta);
745e714af64Sthorpej 	ATF_REQUIRE(delta.tv_sec >= 5);
746e714af64Sthorpej 
747e714af64Sthorpej 	/* Reap the helper. */
748e714af64Sthorpej 	ATF_REQUIRE(pthread_join(helper, &join_val) == 0);
749e714af64Sthorpej }
750e714af64Sthorpej 
751e714af64Sthorpej /*****************************************************************************/
752e714af64Sthorpej 
753f92afe1eSthorpej ATF_TC(timerfd_fcntl);
754f92afe1eSthorpej ATF_TC_HEAD(timerfd_fcntl, tc)
755f92afe1eSthorpej {
756f92afe1eSthorpej 	atf_tc_set_md_var(tc, "descr",
757f92afe1eSthorpej 	    "validates fcntl behavior");
758f92afe1eSthorpej }
759f92afe1eSthorpej 
760f92afe1eSthorpej ATF_TC_BODY(timerfd_fcntl, tc)
761f92afe1eSthorpej {
762f92afe1eSthorpej 	int tfd;
763f92afe1eSthorpej 	int val;
764f92afe1eSthorpej 
765f92afe1eSthorpej 	ATF_REQUIRE((tfd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0);
766f92afe1eSthorpej 	ATF_REQUIRE((fcntl(tfd, F_GETFL) & O_NONBLOCK) == 0);
767f92afe1eSthorpej 	ATF_REQUIRE(fcntl(tfd, F_SETFL, O_NONBLOCK) == 0);
768f92afe1eSthorpej 	ATF_REQUIRE((fcntl(tfd, F_GETFL) & O_NONBLOCK) != 0);
769f92afe1eSthorpej 	ATF_REQUIRE((fcntl(tfd, F_GETFD) & FD_CLOEXEC) == 0);
770f92afe1eSthorpej 
771f92afe1eSthorpej 	/* If the timer hasn't fired, there is no readable data. */
772f92afe1eSthorpej 	ATF_REQUIRE(ioctl(tfd, FIONREAD, &val) == 0);
773f92afe1eSthorpej 	ATF_REQUIRE(val == 0);
774f92afe1eSthorpej 
775f92afe1eSthorpej 	ATF_REQUIRE_ERRNO(ENOTTY, ioctl(tfd, FIONWRITE, &val) == -1);
776f92afe1eSthorpej 	ATF_REQUIRE_ERRNO(ENOTTY, ioctl(tfd, FIONSPACE, &val) == -1);
777f92afe1eSthorpej 	(void)close(tfd);
778f92afe1eSthorpej 
779f92afe1eSthorpej 	ATF_REQUIRE((tfd = timerfd_create(CLOCK_MONOTONIC,
780f92afe1eSthorpej 					  TFD_NONBLOCK | TFD_CLOEXEC)) >= 0);
781f92afe1eSthorpej 	ATF_REQUIRE((fcntl(tfd, F_GETFL) & ~O_ACCMODE) == O_NONBLOCK);
782f92afe1eSthorpej 	ATF_REQUIRE((fcntl(tfd, F_GETFD) & FD_CLOEXEC) != 0);
783f92afe1eSthorpej 	ATF_REQUIRE(fcntl(tfd, F_SETFD, 0) == 0);
784f92afe1eSthorpej 	ATF_REQUIRE((fcntl(tfd, F_GETFD) & FD_CLOEXEC) == 0);
785f92afe1eSthorpej 	ATF_REQUIRE(fcntl(tfd, F_SETFD, FD_CLOEXEC) == 0);
786f92afe1eSthorpej 	ATF_REQUIRE((fcntl(tfd, F_GETFD) & FD_CLOEXEC) != 0);
787f92afe1eSthorpej 	(void)close(tfd);
788f92afe1eSthorpej }
789f92afe1eSthorpej 
790f92afe1eSthorpej /*****************************************************************************/
791f92afe1eSthorpej 
792e714af64Sthorpej ATF_TP_ADD_TCS(tp)
793e714af64Sthorpej {
794bcd5a23fSriastradh 
795e714af64Sthorpej 	ATF_TP_ADD_TC(tp, timerfd_create);
796bcd5a23fSriastradh 	ATF_TP_ADD_TC(tp, timerfd_write);
797e714af64Sthorpej 	ATF_TP_ADD_TC(tp, timerfd_bogusfd);
798bcd5a23fSriastradh 	ATF_TP_ADD_TC(tp, timerfd_invalidtime);
799bcd5a23fSriastradh 	ATF_TP_ADD_TC(tp, timerfd_past);
800e714af64Sthorpej 	ATF_TP_ADD_TC(tp, timerfd_block);
801e714af64Sthorpej 	ATF_TP_ADD_TC(tp, timerfd_repeating);
802e714af64Sthorpej 	ATF_TP_ADD_TC(tp, timerfd_abstime);
803e714af64Sthorpej 	ATF_TP_ADD_TC(tp, timerfd_cancel_on_set_block);
804e714af64Sthorpej 	ATF_TP_ADD_TC(tp, timerfd_cancel_on_set_immed);
805e714af64Sthorpej 	ATF_TP_ADD_TC(tp, timerfd_select_poll_kevent_immed);
806e714af64Sthorpej 	ATF_TP_ADD_TC(tp, timerfd_select_poll_kevent_block);
807e714af64Sthorpej 	ATF_TP_ADD_TC(tp, timerfd_restart);
808f92afe1eSthorpej 	ATF_TP_ADD_TC(tp, timerfd_fcntl);
809e714af64Sthorpej 
810e714af64Sthorpej 	return atf_no_error();
811e714af64Sthorpej }
812