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 44static bool 45check_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 72ATF_TC(basic_timer); 73ATF_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 86ATF_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 156ATF_TC(count_expirations); 157ATF_TC_HEAD(count_expirations, tc) 158{ 159 atf_tc_set_md_var(tc, "descr", 160 "tests counting timer expirations"); 161} 162 163ATF_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 186ATF_TC(modify); 187ATF_TC_HEAD(modify, tc) 188{ 189 atf_tc_set_md_var(tc, "descr", 190 "tests modifying a timer"); 191} 192 193ATF_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 268ATF_TC(abstime); 269ATF_TC_HEAD(abstime, tc) 270{ 271 atf_tc_set_md_var(tc, "descr", 272 "tests timers with NOTE_ABSTIME"); 273} 274 275ATF_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 309static void 310do_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 335ATF_TC(timer_units); 336ATF_TC_HEAD(timer_units, tc) 337{ 338 atf_tc_set_md_var(tc, "descr", 339 "tests timers with NOTE_* units modifiers"); 340} 341 342ATF_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 350ATF_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