t_timer.c revision 1.1 1 /* $NetBSD: t_timer.c,v 1.1 2021/10/13 04:57:19 thorpej 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.1 2021/10/13 04:57:19 thorpej 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 ATF_TC(basic_timer);
43 ATF_TC_HEAD(basic_timer, tc)
44 {
45 atf_tc_set_md_var(tc, "descr",
46 "tests basic EVFILT_TIMER functionality");
47 }
48
49 #define TIME1 1000 /* 1000ms -> 1s */
50 #define TIME1_COUNT 5
51 #define TIME2 6000 /* 6000ms -> 6s */
52
53 #define TIME1_TOTAL_SEC ((TIME1 * TIME1_COUNT) / 1000)
54 #define TIME2_TOTAL_SEC (TIME2 / 1000)
55
56 ATF_TC_BODY(basic_timer, tc)
57 {
58 struct kevent event[2];
59 int ntimer1 = 0, ntimer2 = 0;
60 struct timespec ots, ts;
61 int kq;
62
63 ATF_REQUIRE((kq = kqueue()) >= 0);
64
65 EV_SET(&event[0], 1, EVFILT_TIMER, EV_ADD, 0, TIME1, NULL);
66 EV_SET(&event[1], 2, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, TIME2, NULL);
67
68 ATF_REQUIRE(kevent(kq, event, 2, NULL, 0, NULL) == 0);
69 ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ots) == 0);
70
71 for (;;) {
72 ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, NULL) == 1);
73 ATF_REQUIRE(event[0].filter == EVFILT_TIMER);
74 ATF_REQUIRE(event[0].ident == 1 ||
75 event[0].ident == 2);
76 if (event[0].ident == 1) {
77 ATF_REQUIRE(ntimer1 < TIME1_COUNT);
78 if (++ntimer1 == TIME1_COUNT) {
79 /*
80 * Make sure TIME1_TOTAL_SEC seconds have
81 * elapsed, allowing for a little slop.
82 */
83 ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC,
84 &ts) == 0);
85 timespecsub(&ts, &ots, &ts);
86 ATF_REQUIRE(ts.tv_sec ==
87 (TIME1_TOTAL_SEC - 1) ||
88 ts.tv_sec == TIME1_TOTAL_SEC);
89 if (ts.tv_sec == TIME1_TOTAL_SEC - 1) {
90 ATF_REQUIRE(ts.tv_nsec >=
91 900000000);
92 }
93 EV_SET(&event[0], 1, EVFILT_TIMER, EV_DELETE,
94 0, 0, NULL);
95 ATF_REQUIRE(kevent(kq, event, 1, NULL, 0,
96 NULL) == 0);
97 }
98 } else {
99 ATF_REQUIRE(ntimer1 == TIME1_COUNT);
100 ATF_REQUIRE(ntimer2 == 0);
101 ntimer2++;
102 /*
103 * Make sure TIME2_TOTAL_SEC seconds have
104 * elapsed, allowing for a little slop.
105 */
106 ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC,
107 &ts) == 0);
108 timespecsub(&ts, &ots, &ts);
109 ATF_REQUIRE(ts.tv_sec ==
110 (TIME2_TOTAL_SEC - 1) ||
111 ts.tv_sec == TIME2_TOTAL_SEC);
112 if (ts.tv_sec == TIME2_TOTAL_SEC - 1) {
113 ATF_REQUIRE(ts.tv_nsec >= 900000000);
114 }
115 EV_SET(&event[0], 2, EVFILT_TIMER, EV_DELETE,
116 0, 0, NULL);
117 ATF_REQUIRE_ERRNO(ENOENT,
118 kevent(kq, event, 1, NULL, 0, NULL) == -1);
119 break;
120 }
121 }
122
123 /*
124 * Now block in kqueue for TIME2_TOTAL_SEC, and ensure we
125 * don't receive any new events.
126 */
127 ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ots) == 0);
128 ts.tv_sec = TIME2_TOTAL_SEC;
129 ts.tv_nsec = 0;
130 ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 0);
131 ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
132 timespecsub(&ts, &ots, &ts);
133 ATF_REQUIRE(ts.tv_sec == (TIME2_TOTAL_SEC - 1) ||
134 ts.tv_sec == TIME2_TOTAL_SEC ||
135 ts.tv_sec == (TIME2_TOTAL_SEC + 1));
136 if (ts.tv_sec == TIME2_TOTAL_SEC - 1) {
137 ATF_REQUIRE(ts.tv_nsec >= 900000000);
138 } else if (ts.tv_sec == TIME2_TOTAL_SEC + 1) {
139 ATF_REQUIRE(ts.tv_nsec < 500000000);
140 }
141 }
142
143 ATF_TC(count_expirations);
144 ATF_TC_HEAD(count_expirations, tc)
145 {
146 atf_tc_set_md_var(tc, "descr",
147 "tests counting timer expirations");
148 }
149
150 ATF_TC_BODY(count_expirations, tc)
151 {
152 struct kevent event[1];
153 struct timespec ts = { 0, 0 };
154 struct timespec sleepts;
155 int kq;
156
157 ATF_REQUIRE((kq = kqueue()) >= 0);
158
159 EV_SET(&event[0], 1, EVFILT_TIMER, EV_ADD, 0, TIME1, NULL);
160 ATF_REQUIRE(kevent(kq, event, 1, NULL, 0, NULL) == 0);
161
162 /* Sleep a little longer to mitigate timing jitter. */
163 sleepts.tv_sec = TIME1_TOTAL_SEC;
164 sleepts.tv_nsec = 500000000;
165 ATF_REQUIRE(nanosleep(&sleepts, NULL) == 0);
166
167 ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
168 ATF_REQUIRE(event[0].ident == 1);
169 ATF_REQUIRE(event[0].data == TIME1_COUNT ||
170 event[0].data == TIME1_COUNT + 1);
171 }
172
173 ATF_TC(abstime);
174 ATF_TC_HEAD(abstime, tc)
175 {
176 atf_tc_set_md_var(tc, "descr",
177 "tests timers with NOTE_ABSTIME");
178 }
179
180 ATF_TC_BODY(abstime, tc)
181 {
182 struct kevent event[1];
183 struct timespec ts, ots;
184 time_t seconds;
185 int kq;
186
187 ATF_REQUIRE((kq = kqueue()) >= 0);
188
189 ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &ots) == 0);
190 ATF_REQUIRE(ots.tv_sec < INTPTR_MAX - TIME1_TOTAL_SEC);
191
192 seconds = ots.tv_sec + TIME1_TOTAL_SEC;
193 if (ots.tv_nsec >= 500000000) {
194 seconds++;
195 }
196
197 EV_SET(&event[0], 1, EVFILT_TIMER, EV_ADD,
198 NOTE_ABSTIME | NOTE_SECONDS, seconds, NULL);
199 ATF_REQUIRE(kevent(kq, event, 1, event, 1, NULL) == 1);
200
201 ATF_REQUIRE(clock_gettime(CLOCK_REALTIME, &ts) == 0);
202 timespecsub(&ts, &ots, &ts);
203
204 /*
205 * We're not going for precision here; just verify that it was
206 * delivered anywhere between 4.5-6.whatever seconds later.
207 */
208 ATF_REQUIRE(ts.tv_sec >= 4 && ts.tv_sec <= 6);
209 if (ts.tv_sec == 4) {
210 ATF_REQUIRE(ts.tv_nsec >= 500000000);
211 }
212
213 ts.tv_sec = 0;
214 ts.tv_nsec = 0;
215 ATF_REQUIRE(kevent(kq, NULL, 0, event, 1, &ts) == 1);
216 }
217
218 #define PREC_TIMEOUT_SEC 2
219
220 static void
221 do_test_timer_units(const char *which, uint32_t fflag, int64_t data)
222 {
223 struct kevent event[1];
224 struct timespec ts, ots;
225 int kq;
226
227 ATF_REQUIRE((kq = kqueue()) >= 0);
228
229 EV_SET(&event[0], 1, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
230 fflag, data, NULL);
231
232 ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ots) == 0);
233 ATF_REQUIRE(kevent(kq, event, 1, event, 1, NULL) == 1);
234 ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
235
236 timespecsub(&ts, &ots, &ts);
237 ATF_REQUIRE_MSG(ts.tv_sec == (PREC_TIMEOUT_SEC - 1) ||
238 ts.tv_sec == PREC_TIMEOUT_SEC,
239 "units '%s' failed [sec]", which);
240 if (ts.tv_sec == PREC_TIMEOUT_SEC - 1) {
241 ATF_REQUIRE_MSG(ts.tv_nsec >= 900000000,
242 "units '%s' failed [nsec]", which);
243 }
244
245 (void)close(kq);
246 }
247
248 #define test_timer_units(fflag, data) \
249 do_test_timer_units(#fflag, fflag, data)
250
251 ATF_TC(timer_units);
252 ATF_TC_HEAD(timer_units, tc)
253 {
254 atf_tc_set_md_var(tc, "descr",
255 "tests timers with NOTE_* units modifiers");
256 }
257
258 ATF_TC_BODY(timer_units, tc)
259 {
260 test_timer_units(NOTE_SECONDS, PREC_TIMEOUT_SEC);
261 test_timer_units(NOTE_MSECONDS, PREC_TIMEOUT_SEC * 1000);
262 test_timer_units(NOTE_USECONDS, PREC_TIMEOUT_SEC * 1000000);
263 test_timer_units(NOTE_NSECONDS, PREC_TIMEOUT_SEC * 1000000000);
264 }
265
266 ATF_TP_ADD_TCS(tp)
267 {
268 ATF_TP_ADD_TC(tp, basic_timer);
269 ATF_TP_ADD_TC(tp, count_expirations);
270 ATF_TP_ADD_TC(tp, abstime);
271 ATF_TP_ADD_TC(tp, timer_units);
272
273 return atf_no_error();
274 }
275