1/* $NetBSD: t_timer.c,v 1.4 2021/11/21 09:35:39 hannken Exp $ */
2
3/*-
4 * Copyright (c) 2021 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__RCSID("$NetBSD: t_timer.c,v 1.4 2021/11/21 09:35:39 hannken Exp $");
31
32#include <sys/types.h>
33#include <sys/event.h>
34#include <errno.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <time.h>
38#include <unistd.h>
39
40#include <atf-c.h>
41
42#include "isqemu.h"
43
44static bool
45check_timespec(struct timespec *ts, time_t seconds)
46{
47	time_t upper = seconds;
48	bool result = true;
49
50	/*
51	 * If running under QEMU make sure the upper bound is large
52	 * enough for the effect of kern/43997
53	 */
54	if (isQEMU()) {
55		upper *= 4;
56	}
57
58	if (ts->tv_sec < seconds - 1 ||
59	    (ts->tv_sec == seconds - 1 && ts->tv_nsec < 500000000))
60		result = false;
61	else if (ts->tv_sec > upper ||
62	    (ts->tv_sec == upper && ts->tv_nsec >= 500000000))
63		result = false;
64
65	printf("time %" PRId64 ".%09ld %sin [ %" PRId64 ".5, %" PRId64 ".5 )\n",
66		ts->tv_sec, ts->tv_nsec, (result ? "" : "not "),
67		seconds - 1, upper);
68
69	return result;
70}
71
72ATF_TC(basic_timer);
73ATF_TC_HEAD(basic_timer, tc)
74{
75	atf_tc_set_md_var(tc, "descr",
76	    "tests basic EVFILT_TIMER functionality");
77}
78
79#define	TIME1		1000		/* 1000ms -> 1s */
80#define	TIME1_COUNT	5
81#define	TIME2		6000		/* 6000ms -> 6s */
82
83#define	TIME1_TOTAL_SEC	((TIME1 * TIME1_COUNT) / 1000)
84#define	TIME2_TOTAL_SEC	(TIME2 / 1000)
85
86ATF_TC_BODY(basic_timer, tc)
87{
88	struct kevent event[2];
89	int ntimer1 = 0, ntimer2 = 0;
90	struct timespec ots, ts;
91	int kq;
92
93	ATF_REQUIRE((kq = kqueue()) >= 0);
94
95	EV_SET(&event[0], 1, EVFILT_TIMER, EV_ADD, 0, TIME1, NULL);
96	EV_SET(&event[1], 2, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, TIME2, NULL);
97
98	ATF_REQUIRE(kevent(kq, event, 2, NULL, 0, NULL) == 0);
99	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ots) == 0);
100
101	for (;;) {
102		ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, NULL) == 1);
103		ATF_REQUIRE(event[0].filter == EVFILT_TIMER);
104		ATF_REQUIRE(event[0].ident == 1 ||
105			    event[0].ident == 2);
106		if (event[0].ident == 1) {
107			ATF_REQUIRE(ntimer1 < TIME1_COUNT);
108			if (++ntimer1 == TIME1_COUNT) {
109				/*
110				 * Make sure TIME1_TOTAL_SEC seconds have
111				 * elapsed, allowing for a little slop.
112				 */
113				ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC,
114				    &ts) == 0);
115				timespecsub(&ts, &ots, &ts);
116				ATF_REQUIRE(check_timespec(&ts,
117				    TIME1_TOTAL_SEC));
118				EV_SET(&event[0], 1, EVFILT_TIMER, EV_DELETE,
119				    0, 0, NULL);
120				ATF_REQUIRE(kevent(kq, event, 1, NULL, 0,
121				    NULL) == 0);
122			}
123		} else {
124			ATF_REQUIRE(ntimer1 == TIME1_COUNT);
125			ATF_REQUIRE(ntimer2 == 0);
126			ntimer2++;
127			/*
128			 * Make sure TIME2_TOTAL_SEC seconds have
129			 * elapsed, allowing for a little slop.
130			 */
131			ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC,
132			    &ts) == 0);
133			timespecsub(&ts, &ots, &ts);
134			ATF_REQUIRE(check_timespec(&ts, TIME2_TOTAL_SEC));
135			EV_SET(&event[0], 2, EVFILT_TIMER, EV_DELETE,
136			    0, 0, NULL);
137			ATF_REQUIRE_ERRNO(ENOENT,
138			    kevent(kq, event, 1, NULL, 0, NULL) == -1);
139			break;
140		}
141	}
142
143	/*
144	 * Now block in kqueue for TIME2_TOTAL_SEC, and ensure we
145	 * don't receive any new events.
146	 */
147	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ots) == 0);
148	ts.tv_sec = TIME2_TOTAL_SEC;
149	ts.tv_nsec = 0;
150	ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 0);
151	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
152	timespecsub(&ts, &ots, &ts);
153	ATF_REQUIRE(check_timespec(&ts, TIME2_TOTAL_SEC));
154}
155
156ATF_TC(count_expirations);
157ATF_TC_HEAD(count_expirations, tc)
158{
159	atf_tc_set_md_var(tc, "descr",
160	    "tests counting timer expirations");
161}
162
163ATF_TC_BODY(count_expirations, tc)
164{
165	struct kevent event[1];
166	struct timespec ts = { 0, 0 };
167	struct timespec sleepts;
168	int kq;
169
170	ATF_REQUIRE((kq = kqueue()) >= 0);
171
172	EV_SET(&event[0], 1, EVFILT_TIMER, EV_ADD, 0, TIME1, NULL);
173	ATF_REQUIRE(kevent(kq, event, 1, NULL, 0, NULL) == 0);
174
175	/* Sleep a little longer to mitigate timing jitter. */
176	sleepts.tv_sec = TIME1_TOTAL_SEC;
177	sleepts.tv_nsec = 500000000;
178	ATF_REQUIRE(nanosleep(&sleepts, NULL) == 0);
179
180	ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
181	ATF_REQUIRE(event[0].ident == 1);
182	ATF_REQUIRE(event[0].data == TIME1_COUNT ||
183		    event[0].data == TIME1_COUNT + 1);
184}
185
186ATF_TC(modify);
187ATF_TC_HEAD(modify, tc)
188{
189	atf_tc_set_md_var(tc, "descr",
190	    "tests modifying a timer");
191}
192
193ATF_TC_BODY(modify, tc)
194{
195	struct kevent event[1];
196	struct timespec ts = { 0, 0 };
197	struct timespec sleepts;
198	int kq;
199
200	ATF_REQUIRE((kq = kqueue()) >= 0);
201
202	/*
203	 * Start a 500ms timer, sleep for 5 seconds, and check
204	 * the total count.
205	 */
206	EV_SET(&event[0], 1, EVFILT_TIMER, EV_ADD, 0, 500, NULL);
207	ATF_REQUIRE(kevent(kq, event, 1, NULL, 0, NULL) == 0);
208
209	sleepts.tv_sec = 5;
210	sleepts.tv_nsec = 0;
211	ATF_REQUIRE(nanosleep(&sleepts, NULL) == 0);
212
213	ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
214	ATF_REQUIRE(event[0].ident == 1);
215	ATF_REQUIRE(event[0].data >= 9 && event[0].data <= 11);
216
217	/*
218	 * Modify to a 4 second timer, sleep for 5 seconds, and check
219	 * the total count.
220	 */
221	EV_SET(&event[0], 1, EVFILT_TIMER, EV_ADD, 0, 4000, NULL);
222	ATF_REQUIRE(kevent(kq, event, 1, NULL, 0, NULL) == 0);
223
224	/*
225	 * Before we sleep, verify that the knote for this timer is
226	 * no longer activated.
227	 */
228	ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 0);
229
230	sleepts.tv_sec = 5;
231	sleepts.tv_nsec = 0;
232	ATF_REQUIRE(nanosleep(&sleepts, NULL) == 0);
233
234	ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
235	ATF_REQUIRE(event[0].ident == 1);
236	ATF_REQUIRE(event[0].data == 1);
237
238	/*
239	 * Start a 500ms timer, sleep for 2 seconds.
240	 */
241	EV_SET(&event[0], 1, EVFILT_TIMER, EV_ADD, 0, 500, NULL);
242	ATF_REQUIRE(kevent(kq, event, 1, NULL, 0, NULL) == 0);
243
244	sleepts.tv_sec = 2;
245	sleepts.tv_nsec = 0;
246	ATF_REQUIRE(nanosleep(&sleepts, NULL) == 0);
247
248	/*
249	 * Set the SAME timer, sleep for 2 seconds.
250	 */
251	EV_SET(&event[0], 1, EVFILT_TIMER, EV_ADD, 0, 500, NULL);
252	ATF_REQUIRE(kevent(kq, event, 1, NULL, 0, NULL) == 0);
253
254	sleepts.tv_sec = 2;
255	sleepts.tv_nsec = 0;
256	ATF_REQUIRE(nanosleep(&sleepts, NULL) == 0);
257
258	/*
259	 * The kernel should have reset the count when modifying the
260	 * timer, so we should only expect to see the expiration count
261	 * for the second sleep.
262	 */
263	ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
264	ATF_REQUIRE(event[0].ident == 1);
265	ATF_REQUIRE(event[0].data >= 3 && event[0].data <= 5);
266}
267
268ATF_TC(abstime);
269ATF_TC_HEAD(abstime, tc)
270{
271	atf_tc_set_md_var(tc, "descr",
272	    "tests timers with NOTE_ABSTIME");
273}
274
275ATF_TC_BODY(abstime, tc)
276{
277	struct kevent event[1];
278	struct timespec ts, ots;
279	time_t seconds;
280	int kq;
281
282	ATF_REQUIRE((kq = kqueue()) >= 0);
283
284	ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &ots) == 0);
285	ATF_REQUIRE(ots.tv_sec < INTPTR_MAX - TIME1_TOTAL_SEC);
286
287	seconds = ots.tv_sec + TIME1_TOTAL_SEC;
288
289	EV_SET(&event[0], 1, EVFILT_TIMER, EV_ADD,
290	    NOTE_ABSTIME | NOTE_SECONDS, seconds, NULL);
291	ATF_REQUIRE(kevent(kq, event, 1, event, 1, NULL) == 1);
292
293	ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &ts) == 0);
294	timespecsub(&ts, &ots, &ts);
295
296	/*
297	 * We're not going for precision here; just verify that it was
298	 * delivered anywhere between 4.5-6.whatever seconds later.
299	 */
300	ATF_REQUIRE(check_timespec(&ts, 4) || check_timespec(&ts, 5));
301
302	ts.tv_sec = 0;
303	ts.tv_nsec = 0;
304	ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
305}
306
307#define	PREC_TIMEOUT_SEC	2
308
309static void
310do_test_timer_units(const char *which, uint32_t fflag, int64_t data)
311{
312	struct kevent event[1];
313	struct timespec ts, ots;
314	int kq;
315
316	ATF_REQUIRE((kq = kqueue()) >= 0);
317
318	EV_SET(&event[0], 1, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
319	    fflag, data, NULL);
320
321	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ots) == 0);
322	ATF_REQUIRE(kevent(kq, event, 1, event, 1, NULL) == 1);
323	ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
324
325	timespecsub(&ts, &ots, &ts);
326	ATF_REQUIRE_MSG(check_timespec(&ts, PREC_TIMEOUT_SEC),
327	    "units '%s' failed", which);
328
329	(void)close(kq);
330}
331
332#define	test_timer_units(fflag, data)				\
333	do_test_timer_units(#fflag, fflag, data)
334
335ATF_TC(timer_units);
336ATF_TC_HEAD(timer_units, tc)
337{
338	atf_tc_set_md_var(tc, "descr",
339	    "tests timers with NOTE_* units modifiers");
340}
341
342ATF_TC_BODY(timer_units, tc)
343{
344	test_timer_units(NOTE_SECONDS,  PREC_TIMEOUT_SEC);
345	test_timer_units(NOTE_MSECONDS, PREC_TIMEOUT_SEC * 1000);
346	test_timer_units(NOTE_USECONDS, PREC_TIMEOUT_SEC * 1000000);
347	test_timer_units(NOTE_NSECONDS, PREC_TIMEOUT_SEC * 1000000000);
348}
349
350ATF_TP_ADD_TCS(tp)
351{
352	ATF_TP_ADD_TC(tp, basic_timer);
353	ATF_TP_ADD_TC(tp, count_expirations);
354	ATF_TP_ADD_TC(tp, abstime);
355	ATF_TP_ADD_TC(tp, timer_units);
356	ATF_TP_ADD_TC(tp, modify);
357
358	return atf_no_error();
359}
360