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