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