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.
20 #define MILLION 1000000
22 #define SEC_TO_MS(t) ((t) * THOUSAND) /* Convert seconds to milliseconds. */
23 #define SEC_TO_US(t) ((t) * MILLION) /* Convert seconds to microseconds. */
24 #define MS_TO_US(t) ((t) * THOUSAND) /* Convert milliseconds to microseconds. */
25 #define US_TO_NS(t) ((t) * THOUSAND) /* Convert microseconds to nanoseconds. */
28 /* Get the current time with microsecond precision. Used for
29 * sub-second timing to make some timer tests run faster.
36 gettimeofday(&tv, NULL);
37 /* Promote potentially 32-bit time_t to uint64_t before conversion. */
38 return SEC_TO_US((uint64_t)tv.tv_sec) + tv.tv_usec;
41 /* Sleep for a given number of milliseconds. The timeout is assumed to
42 * be less than 1 second.
47 struct timespec stime = {
49 .tv_nsec = US_TO_NS(MS_TO_US(t)),
52 nanosleep(&stime, NULL);
55 /* Sleep for a given number of microseconds. The timeout is assumed to
56 * be less than 1 second.
61 struct timespec stime = {
63 .tv_nsec = US_TO_NS(t),
66 nanosleep(&stime, NULL);
70 test_kevent_timer_add(void)
72 const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)";
77 EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
78 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
79 err(1, "%s", test_id);
85 test_kevent_timer_del(void)
87 const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)";
92 EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
93 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
94 err(1, "%s", test_id);
102 test_kevent_timer_get(void)
104 const char *test_id = "kevent(EVFILT_TIMER, wait)";
109 EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
110 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
111 err(1, "%s", test_id);
113 kev.flags |= EV_CLEAR;
115 kevent_cmp(&kev, kevent_get(kqfd));
117 EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
118 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
119 err(1, "%s", test_id);
127 const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)";
134 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL);
135 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
136 err(1, "%s", test_id);
138 /* Retrieve the event */
139 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
141 kevent_cmp(&kev, kevent_get(kqfd));
143 /* Check if the event occurs again */
154 const char *test_id = "kevent(EVFILT_TIMER, periodic)";
161 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL);
162 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
163 err(1, "%s", test_id);
165 /* Retrieve the event */
166 kev.flags = EV_ADD | EV_CLEAR;
168 kevent_cmp(&kev, kevent_get(kqfd));
170 /* Check if the event occurs again */
172 kevent_cmp(&kev, kevent_get(kqfd));
174 /* Delete the event */
175 kev.flags = EV_DELETE;
176 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
177 err(1, "%s", test_id);
183 test_periodic_modify(void)
185 const char *test_id = "kevent(EVFILT_TIMER, periodic_modify)";
192 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
193 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
194 err(1, "%s", test_id);
196 /* Retrieve the event */
197 kev.flags = EV_ADD | EV_CLEAR;
199 kevent_cmp(&kev, kevent_get(kqfd));
201 /* Check if the event occurs again */
202 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 500, NULL);
203 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
204 err(1, "%s", test_id);
206 kev.flags = EV_ADD | EV_CLEAR;
208 kev.data = 2; /* Should have fired twice */
210 kevent_cmp(&kev, kevent_get(kqfd));
212 /* Delete the event */
213 kev.flags = EV_DELETE;
214 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
215 err(1, "%s", test_id);
220 #if WITH_NATIVE_KQUEUE_BUGS
222 test_periodic_to_oneshot(void)
224 const char *test_id = "kevent(EVFILT_TIMER, period_to_oneshot)";
231 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
232 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
233 err(1, "%s", test_id);
235 /* Retrieve the event */
236 kev.flags = EV_ADD | EV_CLEAR;
238 kevent_cmp(&kev, kevent_get(kqfd));
240 /* Check if the event occurs again */
242 kevent_cmp(&kev, kevent_get(kqfd));
244 /* Switch to oneshot */
245 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500, NULL);
246 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
247 err(1, "%s", test_id);
248 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
251 kev.data = 1; /* Should have fired once */
253 kevent_cmp(&kev, kevent_get(kqfd));
260 test_disable_and_enable(void)
262 const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
269 /* Add the watch and immediately disable it */
270 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
271 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
272 err(1, "%s", test_id);
273 kev.flags = EV_DISABLE;
274 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
275 err(1, "%s", test_id);
278 /* Re-enable and check again */
279 kev.flags = EV_ENABLE;
280 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
281 err(1, "%s", test_id);
283 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
285 kevent_cmp(&kev, kevent_get(kqfd));
293 const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)";
295 uint64_t end, start, stop;
296 const int timeout_sec = 3;
303 end = start + SEC_TO_US(timeout_sec);
304 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
305 NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
306 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
307 err(1, "%s", test_id);
309 /* Retrieve the event */
310 kev.flags = EV_ADD | EV_ONESHOT;
313 kevent_cmp(&kev, kevent_get(kqfd));
317 err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
318 /* Check if the event occurs again */
326 test_abstime_epoch(void)
328 const char *test_id = "kevent(EVFILT_TIMER (EPOCH), NOTE_ABSTIME)";
335 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, NOTE_ABSTIME, 0,
337 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
338 err(1, "%s", test_id);
340 /* Retrieve the event */
344 kevent_cmp(&kev, kevent_get(kqfd));
346 /* Delete the event */
347 kev.flags = EV_DELETE;
348 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
349 err(1, "%s", test_id);
355 test_abstime_preboot(void)
357 const char *test_id = "kevent(EVFILT_TIMER (PREBOOT), EV_ONESHOT, NOTE_ABSTIME)";
360 uint64_t end, start, stop;
367 * We'll expire it at just before system boot (roughly) with the hope that
368 * we'll get an ~immediate expiration, just as we do for any value specified
369 * between system boot and now.
372 if (clock_gettime(CLOCK_BOOTTIME, &btp) != 0)
373 err(1, "%s", test_id);
375 end = start - SEC_TO_US(btp.tv_sec + 1);
376 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
377 NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
378 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
379 err(1, "%s", test_id);
381 /* Retrieve the event */
382 kev.flags = EV_ADD | EV_ONESHOT;
385 kevent_cmp(&kev, kevent_get(kqfd));
389 err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
390 /* Check if the event occurs again */
398 test_abstime_postboot(void)
400 const char *test_id = "kevent(EVFILT_TIMER (POSTBOOT), EV_ONESHOT, NOTE_ABSTIME)";
402 uint64_t end, start, stop;
403 const int timeout_sec = 1;
410 * Set a timer for 1 second ago, it should fire immediately rather than
414 end = start - SEC_TO_US(timeout_sec);
415 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
416 NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
417 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
418 err(1, "%s", test_id);
420 /* Retrieve the event */
421 kev.flags = EV_ADD | EV_ONESHOT;
424 kevent_cmp(&kev, kevent_get(kqfd));
428 err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
429 /* Check if the event occurs again */
439 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)";
448 /* First set the timer to 1 second */
449 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
450 NOTE_USECONDS, SEC_TO_US(1), (void *)1);
452 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
453 err(1, "%s", test_id);
455 /* Now reduce the timer to 1 ms */
456 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
457 NOTE_USECONDS, MS_TO_US(1), (void *)2);
458 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
459 err(1, "%s", test_id);
461 /* Wait for the event */
462 kev.flags |= EV_CLEAR;
463 kev.fflags &= ~NOTE_USECONDS;
465 kevent_cmp(&kev, kevent_get(kqfd));
466 elapsed = now() - start;
468 /* Check that the timer expired after at least 1 ms, but less than
469 * 1 second. This check is to make sure that the original 1 second
470 * timeout was not used.
472 printf("timer expired after %ld us\n", elapsed);
473 if (elapsed < MS_TO_US(1))
474 errx(1, "early timer expiration: %ld us", elapsed);
475 if (elapsed > SEC_TO_US(1))
476 errx(1, "late timer expiration: %ld us", elapsed);
482 test_update_equal(void)
484 const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)";
493 /* First set the timer to 1 ms */
494 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
495 NOTE_USECONDS, MS_TO_US(1), NULL);
496 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
497 err(1, "%s", test_id);
499 /* Sleep for a significant fraction of the timeout. */
502 /* Now re-add the timer with the same parameters */
504 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
505 err(1, "%s", test_id);
507 /* Wait for the event */
508 kev.flags |= EV_CLEAR;
509 kev.fflags &= ~NOTE_USECONDS;
511 kevent_cmp(&kev, kevent_get(kqfd));
512 elapsed = now() - start;
514 /* Check that the timer expired after at least 1 ms. This check is
515 * to make sure that the timer re-started and that the event is
516 * not from the original add of the timer.
518 printf("timer expired after %ld us\n", elapsed);
519 if (elapsed < MS_TO_US(1))
520 errx(1, "early timer expiration: %ld us", elapsed);
526 test_update_expired(void)
528 const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)";
537 /* Set the timer to 1ms */
538 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
539 NOTE_USECONDS, MS_TO_US(1), NULL);
540 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
541 err(1, "%s", test_id);
543 /* Wait for 2 ms to give the timer plenty of time to expire. */
546 /* Now re-add the timer */
548 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
549 err(1, "%s", test_id);
551 /* Wait for the event */
552 kev.flags |= EV_CLEAR;
553 kev.fflags &= ~NOTE_USECONDS;
555 kevent_cmp(&kev, kevent_get(kqfd));
556 elapsed = now() - start;
558 /* Check that the timer expired after at least 1 ms. This check
559 * is to make sure that the timer re-started and that the event is
560 * not from the original add (and expiration) of the timer.
562 printf("timer expired after %ld us\n", elapsed);
563 if (elapsed < MS_TO_US(1))
564 errx(1, "early timer expiration: %ld us", elapsed);
566 /* Make sure the re-added timer does not fire. In other words,
567 * test that the event received above was the only event from the
568 * add and re-add of the timer.
577 test_update_periodic(void)
579 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)";
582 uint64_t start, stop;
588 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL);
589 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
590 err(1, "%s", test_id);
592 /* Retrieve the event */
593 kev.flags = EV_ADD | EV_CLEAR;
595 kevent_cmp(&kev, kevent_get(kqfd));
597 /* Check if the event occurs again */
599 kevent_cmp(&kev, kevent_get(kqfd));
601 /* Re-add with new timeout. */
602 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL);
604 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
605 err(1, "%s", test_id);
607 /* Retrieve the event */
608 kev.flags = EV_ADD | EV_CLEAR;
610 kevent_cmp(&kev, kevent_get(kqfd));
613 elapsed = stop - start;
615 /* Check that the timer expired after at least 2 ms.
617 printf("timer expired after %ld us\n", elapsed);
618 if (elapsed < MS_TO_US(2))
619 errx(1, "early timer expiration: %ld us", elapsed);
621 /* Delete the event */
622 kev.flags = EV_DELETE;
623 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
624 err(1, "%s", test_id);
630 test_update_timing(void)
632 #define MIN_SLEEP 500
633 #define MAX_SLEEP 1500
634 const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)";
639 uint64_t start, stop;
645 /* Re-try the update tests with a variety of delays between the
646 * original timer activation and the update of the timer. The goal
647 * is to show that in all cases the only timer event that is
648 * received is from the update and not the original timer add.
650 for (sleeptime = MIN_SLEEP, iteration = 1;
651 sleeptime < MAX_SLEEP;
652 ++sleeptime, ++iteration) {
654 /* First set the timer to 1 ms */
655 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
656 NOTE_USECONDS, MS_TO_US(1), NULL);
657 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
658 err(1, "%s", test_id);
660 /* Delay; the delay ranges from less than to greater than the
665 /* Now re-add the timer with the same parameters */
667 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
668 err(1, "%s", test_id);
670 /* Wait for the event */
671 kev.flags |= EV_CLEAR;
672 kev.fflags &= ~NOTE_USECONDS;
674 kevent_cmp(&kev, kevent_get(kqfd));
676 elapsed = stop - start;
678 /* Check that the timer expired after at least 1 ms. This
679 * check is to make sure that the timer re-started and that
680 * the event is not from the original add of the timer.
682 if (elapsed < MS_TO_US(1))
683 errx(1, "early timer expiration: %ld us", elapsed);
685 /* Make sure the re-added timer does not fire. In other words,
686 * test that the event received above was the only event from
687 * the add and re-add of the timer.
690 test_no_kevents_quietly();
699 const char *test_id = "kevent(EVFILT_TIMER, EV_ADD | EV_DISPATCH)";
704 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_DISPATCH, 0, 200, NULL);
705 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
706 err(1, "%s", test_id);
709 kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
711 kevent_cmp(&kev, kevent_get(kqfd));
713 /* Confirm that the knote is disabled due to EV_DISPATCH */
717 /* Enable the knote and make sure no events are pending */
718 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_DISPATCH, 0, 200, NULL);
719 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
720 err(1, "%s", test_id);
723 /* Get the next event */
724 usleep(1100000); /* 1100 ms */
725 kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
727 kevent_cmp(&kev, kevent_get(kqfd));
729 /* Remove the knote and ensure the event no longer fires */
730 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
731 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
732 err(1, "%s", test_id);
733 usleep(500000); /* 500ms */
740 test_evfilt_timer(void)
743 test_kevent_timer_add();
744 test_kevent_timer_del();
745 test_kevent_timer_get();
748 test_periodic_modify();
749 #if WITH_NATIVE_KQUEUE_BUGS
750 test_periodic_to_oneshot();
753 test_abstime_epoch();
754 test_abstime_preboot();
755 test_abstime_postboot();
758 test_update_expired();
759 test_update_timing();
760 test_update_periodic();
761 test_disable_and_enable();