xref: /netbsd-src/tests/kernel/kqueue/t_timer.c (revision ae0245f0df673b85ba0c283bf444f7b2468957ab)
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 
44 static bool
check_timespec(struct timespec * ts,time_t seconds)45 check_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 
72 ATF_TC(basic_timer);
ATF_TC_HEAD(basic_timer,tc)73 ATF_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 
ATF_TC_BODY(basic_timer,tc)86 ATF_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 
156 ATF_TC(count_expirations);
ATF_TC_HEAD(count_expirations,tc)157 ATF_TC_HEAD(count_expirations, tc)
158 {
159 	atf_tc_set_md_var(tc, "descr",
160 	    "tests counting timer expirations");
161 }
162 
ATF_TC_BODY(count_expirations,tc)163 ATF_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 
186 ATF_TC(modify);
ATF_TC_HEAD(modify,tc)187 ATF_TC_HEAD(modify, tc)
188 {
189 	atf_tc_set_md_var(tc, "descr",
190 	    "tests modifying a timer");
191 }
192 
ATF_TC_BODY(modify,tc)193 ATF_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 
268 ATF_TC(abstime);
ATF_TC_HEAD(abstime,tc)269 ATF_TC_HEAD(abstime, tc)
270 {
271 	atf_tc_set_md_var(tc, "descr",
272 	    "tests timers with NOTE_ABSTIME");
273 }
274 
ATF_TC_BODY(abstime,tc)275 ATF_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 
309 static void
do_test_timer_units(const char * which,uint32_t fflag,int64_t data)310 do_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 
335 ATF_TC(timer_units);
ATF_TC_HEAD(timer_units,tc)336 ATF_TC_HEAD(timer_units, tc)
337 {
338 	atf_tc_set_md_var(tc, "descr",
339 	    "tests timers with NOTE_* units modifiers");
340 }
341 
ATF_TC_BODY(timer_units,tc)342 ATF_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 
ATF_TP_ADD_TCS(tp)350 ATF_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