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