2 * Copyright (c) 2009 Mark Heily <mark@heily.com>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 #define MILLION 1000000
24 #define SEC_TO_MS(t) ((t) * THOUSAND) /* Convert seconds to milliseconds. */
25 #define SEC_TO_US(t) ((t) * MILLION) /* Convert seconds to microseconds. */
26 #define MS_TO_US(t) ((t) * THOUSAND) /* Convert milliseconds to microseconds. */
27 #define US_TO_NS(t) ((t) * THOUSAND) /* Convert microseconds to nanoseconds. */
30 /* Get the current time with microsecond precision. Used for
31 * sub-second timing to make some timer tests run faster.
38 gettimeofday(&tv, NULL);
39 /* Promote potentially 32-bit time_t to uint64_t before conversion. */
40 return SEC_TO_US((uint64_t)tv.tv_sec) + tv.tv_usec;
43 /* Sleep for a given number of milliseconds. The timeout is assumed to
44 * be less than 1 second.
49 struct timespec stime = {
51 .tv_nsec = US_TO_NS(MS_TO_US(t)),
54 nanosleep(&stime, NULL);
57 /* Sleep for a given number of microseconds. The timeout is assumed to
58 * be less than 1 second.
63 struct timespec stime = {
65 .tv_nsec = US_TO_NS(t),
68 nanosleep(&stime, NULL);
72 test_kevent_timer_add(void)
74 const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)";
79 EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
80 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
81 err(1, "%s", test_id);
87 test_kevent_timer_del(void)
89 const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)";
94 EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
95 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
96 err(1, "%s", test_id);
104 test_kevent_timer_get(void)
106 const char *test_id = "kevent(EVFILT_TIMER, wait)";
111 EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
112 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
113 err(1, "%s", test_id);
115 kev.flags |= EV_CLEAR;
117 kevent_cmp(&kev, kevent_get(kqfd));
119 EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
120 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
121 err(1, "%s", test_id);
129 const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)";
136 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL);
137 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
138 err(1, "%s", test_id);
140 /* Retrieve the event */
141 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
143 kevent_cmp(&kev, kevent_get(kqfd));
145 /* Check if the event occurs again */
156 const char *test_id = "kevent(EVFILT_TIMER, periodic)";
163 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL);
164 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
165 err(1, "%s", test_id);
167 /* Retrieve the event */
168 kev.flags = EV_ADD | EV_CLEAR;
170 kevent_cmp(&kev, kevent_get(kqfd));
172 /* Check if the event occurs again */
174 kevent_cmp(&kev, kevent_get(kqfd));
176 /* Delete the event */
177 kev.flags = EV_DELETE;
178 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
179 err(1, "%s", test_id);
185 disable_and_enable(void)
187 const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
194 /* Add the watch and immediately disable it */
195 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
196 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
197 err(1, "%s", test_id);
198 kev.flags = EV_DISABLE;
199 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
200 err(1, "%s", test_id);
203 /* Re-enable and check again */
204 kev.flags = EV_ENABLE;
205 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
206 err(1, "%s", test_id);
208 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
210 kevent_cmp(&kev, kevent_get(kqfd));
218 const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)";
220 uint64_t end, start, stop;
221 const int timeout_sec = 3;
228 end = start + SEC_TO_US(timeout_sec);
229 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
230 NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
231 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
232 err(1, "%s", test_id);
234 /* Retrieve the event */
235 kev.flags = EV_ADD | EV_ONESHOT;
238 kevent_cmp(&kev, kevent_get(kqfd));
242 err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
243 /* Check if the event occurs again */
251 test_abstime_epoch(void)
253 const char *test_id = "kevent(EVFILT_TIMER (EPOCH), NOTE_ABSTIME)";
260 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, NOTE_ABSTIME, 0,
262 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
263 err(1, "%s", test_id);
265 /* Retrieve the event */
269 kevent_cmp(&kev, kevent_get(kqfd));
271 /* Delete the event */
272 kev.flags = EV_DELETE;
273 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
274 err(1, "%s", test_id);
280 test_abstime_preboot(void)
282 const char *test_id = "kevent(EVFILT_TIMER (PREBOOT), EV_ONESHOT, NOTE_ABSTIME)";
285 uint64_t end, start, stop;
292 * We'll expire it at just before system boot (roughly) with the hope that
293 * we'll get an ~immediate expiration, just as we do for any value specified
294 * between system boot and now.
297 if (clock_gettime(CLOCK_BOOTTIME, &btp) != 0)
298 err(1, "%s", test_id);
300 end = start - SEC_TO_US(btp.tv_sec + 1);
301 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
302 NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
303 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
304 err(1, "%s", test_id);
306 /* Retrieve the event */
307 kev.flags = EV_ADD | EV_ONESHOT;
310 kevent_cmp(&kev, kevent_get(kqfd));
314 err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
315 /* Check if the event occurs again */
323 test_abstime_postboot(void)
325 const char *test_id = "kevent(EVFILT_TIMER (POSTBOOT), EV_ONESHOT, NOTE_ABSTIME)";
327 uint64_t end, start, stop;
328 const int timeout_sec = 1;
335 * Set a timer for 1 second ago, it should fire immediately rather than
339 end = start - SEC_TO_US(timeout_sec);
340 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
341 NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
342 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
343 err(1, "%s", test_id);
345 /* Retrieve the event */
346 kev.flags = EV_ADD | EV_ONESHOT;
349 kevent_cmp(&kev, kevent_get(kqfd));
353 err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
354 /* Check if the event occurs again */
364 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)";
373 /* First set the timer to 1 second */
374 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
375 NOTE_USECONDS, SEC_TO_US(1), (void *)1);
377 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
378 err(1, "%s", test_id);
380 /* Now reduce the timer to 1 ms */
381 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
382 NOTE_USECONDS, MS_TO_US(1), (void *)2);
383 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
384 err(1, "%s", test_id);
386 /* Wait for the event */
387 kev.flags |= EV_CLEAR;
388 kev.fflags &= ~NOTE_USECONDS;
390 kevent_cmp(&kev, kevent_get(kqfd));
391 elapsed = now() - start;
393 /* Check that the timer expired after at least 1 ms, but less than
394 * 1 second. This check is to make sure that the original 1 second
395 * timeout was not used.
397 printf("timer expired after %ld us\n", elapsed);
398 if (elapsed < MS_TO_US(1))
399 errx(1, "early timer expiration: %ld us", elapsed);
400 if (elapsed > SEC_TO_US(1))
401 errx(1, "late timer expiration: %ld us", elapsed);
407 test_update_equal(void)
409 const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)";
418 /* First set the timer to 1 ms */
419 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
420 NOTE_USECONDS, MS_TO_US(1), NULL);
421 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
422 err(1, "%s", test_id);
424 /* Sleep for a significant fraction of the timeout. */
427 /* Now re-add the timer with the same parameters */
429 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
430 err(1, "%s", test_id);
432 /* Wait for the event */
433 kev.flags |= EV_CLEAR;
434 kev.fflags &= ~NOTE_USECONDS;
436 kevent_cmp(&kev, kevent_get(kqfd));
437 elapsed = now() - start;
439 /* Check that the timer expired after at least 1 ms. This check is
440 * to make sure that the timer re-started and that the event is
441 * not from the original add of the timer.
443 printf("timer expired after %ld us\n", elapsed);
444 if (elapsed < MS_TO_US(1))
445 errx(1, "early timer expiration: %ld us", elapsed);
451 test_update_expired(void)
453 const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)";
462 /* Set the timer to 1ms */
463 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
464 NOTE_USECONDS, MS_TO_US(1), NULL);
465 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
466 err(1, "%s", test_id);
468 /* Wait for 2 ms to give the timer plenty of time to expire. */
471 /* Now re-add the timer */
473 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
474 err(1, "%s", test_id);
476 /* Wait for the event */
477 kev.flags |= EV_CLEAR;
478 kev.fflags &= ~NOTE_USECONDS;
480 kevent_cmp(&kev, kevent_get(kqfd));
481 elapsed = now() - start;
483 /* Check that the timer expired after at least 1 ms. This check
484 * is to make sure that the timer re-started and that the event is
485 * not from the original add (and expiration) of the timer.
487 printf("timer expired after %ld us\n", elapsed);
488 if (elapsed < MS_TO_US(1))
489 errx(1, "early timer expiration: %ld us", elapsed);
491 /* Make sure the re-added timer does not fire. In other words,
492 * test that the event received above was the only event from the
493 * add and re-add of the timer.
502 test_update_periodic(void)
504 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)";
507 uint64_t start, stop;
513 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL);
514 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
515 err(1, "%s", test_id);
517 /* Retrieve the event */
518 kev.flags = EV_ADD | EV_CLEAR;
520 kevent_cmp(&kev, kevent_get(kqfd));
522 /* Check if the event occurs again */
524 kevent_cmp(&kev, kevent_get(kqfd));
526 /* Re-add with new timeout. */
527 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL);
529 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
530 err(1, "%s", test_id);
532 /* Retrieve the event */
533 kev.flags = EV_ADD | EV_CLEAR;
535 kevent_cmp(&kev, kevent_get(kqfd));
538 elapsed = stop - start;
540 /* Check that the timer expired after at least 2 ms.
542 printf("timer expired after %ld us\n", elapsed);
543 if (elapsed < MS_TO_US(2))
544 errx(1, "early timer expiration: %ld us", elapsed);
546 /* Delete the event */
547 kev.flags = EV_DELETE;
548 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
549 err(1, "%s", test_id);
555 test_update_timing(void)
557 #define MIN_SLEEP 500
558 #define MAX_SLEEP 1500
559 const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)";
564 uint64_t start, stop;
570 /* Re-try the update tests with a variety of delays between the
571 * original timer activation and the update of the timer. The goal
572 * is to show that in all cases the only timer event that is
573 * received is from the update and not the original timer add.
575 for (sleeptime = MIN_SLEEP, iteration = 1;
576 sleeptime < MAX_SLEEP;
577 ++sleeptime, ++iteration) {
579 /* First set the timer to 1 ms */
580 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
581 NOTE_USECONDS, MS_TO_US(1), NULL);
582 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
583 err(1, "%s", test_id);
585 /* Delay; the delay ranges from less than to greater than the
590 /* Now re-add the timer with the same parameters */
592 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
593 err(1, "%s", test_id);
595 /* Wait for the event */
596 kev.flags |= EV_CLEAR;
597 kev.fflags &= ~NOTE_USECONDS;
599 kevent_cmp(&kev, kevent_get(kqfd));
601 elapsed = stop - start;
603 /* Check that the timer expired after at least 1 ms. This
604 * check is to make sure that the timer re-started and that
605 * the event is not from the original add of the timer.
607 if (elapsed < MS_TO_US(1))
608 errx(1, "early timer expiration: %ld us", elapsed);
610 /* Make sure the re-added timer does not fire. In other words,
611 * test that the event received above was the only event from
612 * the add and re-add of the timer.
615 test_no_kevents_quietly();
625 test_kevent_timer_add();
626 test_kevent_timer_del();
627 test_kevent_timer_get();
631 test_abstime_epoch();
632 test_abstime_preboot();
633 test_abstime_postboot();
636 test_update_expired();
637 test_update_timing();
638 test_update_periodic();
639 disable_and_enable();