xref: /freebsd/tests/sys/kqueue/libkqueue/timer.c (revision b3e76948)
1 /*
2  * Copyright (c) 2009 Mark Heily <mark@heily.com>
3  *
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.
7  *
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.
15  */
16 
17 #include "common.h"
18 #include <sys/time.h>
19 
20 #define	MILLION 1000000
21 #define	THOUSAND 1000
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. */
26 
27 
28 /* Get the current time with microsecond precision. Used for
29  * sub-second timing to make some timer tests run faster.
30  */
31 static uint64_t
now(void)32 now(void)
33 {
34     struct timeval tv;
35 
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;
39 }
40 
41 /* Sleep for a given number of milliseconds. The timeout is assumed to
42  * be less than 1 second.
43  */
44 static void
mssleep(int t)45 mssleep(int t)
46 {
47     struct timespec stime = {
48         .tv_sec = 0,
49         .tv_nsec = US_TO_NS(MS_TO_US(t)),
50     };
51 
52     nanosleep(&stime, NULL);
53 }
54 
55 /* Sleep for a given number of microseconds. The timeout is assumed to
56  * be less than 1 second.
57  */
58 static void
ussleep(int t)59 ussleep(int t)
60 {
61     struct timespec stime = {
62         .tv_sec = 0,
63         .tv_nsec = US_TO_NS(t),
64     };
65 
66     nanosleep(&stime, NULL);
67 }
68 
69 static void
test_kevent_timer_add(void)70 test_kevent_timer_add(void)
71 {
72     const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)";
73     struct kevent kev;
74 
75     test_begin(test_id);
76 
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);
80 
81     success();
82 }
83 
84 static void
test_kevent_timer_del(void)85 test_kevent_timer_del(void)
86 {
87     const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)";
88     struct kevent kev;
89 
90     test_begin(test_id);
91 
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);
95 
96     test_no_kevents();
97 
98     success();
99 }
100 
101 static void
test_kevent_timer_get(void)102 test_kevent_timer_get(void)
103 {
104     const char *test_id = "kevent(EVFILT_TIMER, wait)";
105     struct kevent kev;
106 
107     test_begin(test_id);
108 
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);
112 
113     kev.flags |= EV_CLEAR;
114     kev.data = 1;
115     kevent_cmp(&kev, kevent_get(kqfd));
116 
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);
120 
121     success();
122 }
123 
124 static void
test_oneshot(void)125 test_oneshot(void)
126 {
127     const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)";
128     struct kevent kev;
129 
130     test_begin(test_id);
131 
132     test_no_kevents();
133 
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);
137 
138     /* Retrieve the event */
139     kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
140     kev.data = 1;
141     kevent_cmp(&kev, kevent_get(kqfd));
142 
143     /* Check if the event occurs again */
144     sleep(3);
145     test_no_kevents();
146 
147 
148     success();
149 }
150 
151 static void
test_periodic(void)152 test_periodic(void)
153 {
154     const char *test_id = "kevent(EVFILT_TIMER, periodic)";
155     struct kevent kev;
156 
157     test_begin(test_id);
158 
159     test_no_kevents();
160 
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);
164 
165     /* Retrieve the event */
166     kev.flags = EV_ADD | EV_CLEAR;
167     kev.data = 1;
168     kevent_cmp(&kev, kevent_get(kqfd));
169 
170     /* Check if the event occurs again */
171     sleep(1);
172     kevent_cmp(&kev, kevent_get(kqfd));
173 
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);
178 
179     success();
180 }
181 
182 static void
test_periodic_modify(void)183 test_periodic_modify(void)
184 {
185     const char *test_id = "kevent(EVFILT_TIMER, periodic_modify)";
186     struct kevent kev;
187 
188     test_begin(test_id);
189 
190     test_no_kevents();
191 
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);
195 
196     /* Retrieve the event */
197     kev.flags = EV_ADD | EV_CLEAR;
198     kev.data = 1;
199     kevent_cmp(&kev, kevent_get(kqfd));
200 
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);
205 
206     kev.flags = EV_ADD | EV_CLEAR;
207     sleep(1);
208     kev.data = 2;	/* Should have fired twice */
209 
210     kevent_cmp(&kev, kevent_get(kqfd));
211 
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);
216 
217     success();
218 }
219 
220 #if WITH_NATIVE_KQUEUE_BUGS
221 static void
test_periodic_to_oneshot(void)222 test_periodic_to_oneshot(void)
223 {
224     const char *test_id = "kevent(EVFILT_TIMER, period_to_oneshot)";
225     struct kevent kev;
226 
227     test_begin(test_id);
228 
229     test_no_kevents();
230 
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);
234 
235     /* Retrieve the event */
236     kev.flags = EV_ADD | EV_CLEAR;
237     kev.data = 1;
238     kevent_cmp(&kev, kevent_get(kqfd));
239 
240     /* Check if the event occurs again */
241     sleep(1);
242     kevent_cmp(&kev, kevent_get(kqfd));
243 
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;
249 
250     sleep(1);
251     kev.data = 1;	/* Should have fired once */
252 
253     kevent_cmp(&kev, kevent_get(kqfd));
254 
255     success();
256 }
257 #endif
258 
259 static void
test_disable_and_enable(void)260 test_disable_and_enable(void)
261 {
262     const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
263     struct kevent kev;
264 
265     test_begin(test_id);
266 
267     test_no_kevents();
268 
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);
276     test_no_kevents();
277 
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);
282 
283     kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
284     kev.data = 1;
285     kevent_cmp(&kev, kevent_get(kqfd));
286 
287     success();
288 }
289 
290 static void
test_abstime(void)291 test_abstime(void)
292 {
293     const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)";
294     struct kevent kev;
295     uint64_t end, start, stop;
296     const int timeout_sec = 3;
297 
298     test_begin(test_id);
299 
300     test_no_kevents();
301 
302     start = now();
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);
308 
309     /* Retrieve the event */
310     kev.flags = EV_ADD | EV_ONESHOT;
311     kev.data = 1;
312     kev.fflags = 0;
313     kevent_cmp(&kev, kevent_get(kqfd));
314 
315     stop = now();
316     if (stop < end)
317         err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
318     /* Check if the event occurs again */
319     sleep(3);
320     test_no_kevents();
321 
322     success();
323 }
324 
325 static void
test_abstime_epoch(void)326 test_abstime_epoch(void)
327 {
328     const char *test_id = "kevent(EVFILT_TIMER (EPOCH), NOTE_ABSTIME)";
329     struct kevent kev;
330 
331     test_begin(test_id);
332 
333     test_no_kevents();
334 
335     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, NOTE_ABSTIME, 0,
336         NULL);
337     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
338         err(1, "%s", test_id);
339 
340     /* Retrieve the event */
341     kev.flags = EV_ADD;
342     kev.data = 1;
343     kev.fflags = 0;
344     kevent_cmp(&kev, kevent_get(kqfd));
345 
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);
350 
351     success();
352 }
353 
354 static void
test_abstime_preboot(void)355 test_abstime_preboot(void)
356 {
357     const char *test_id = "kevent(EVFILT_TIMER (PREBOOT), EV_ONESHOT, NOTE_ABSTIME)";
358     struct kevent kev;
359     struct timespec btp;
360     uint64_t end, start, stop;
361 
362     test_begin(test_id);
363 
364     test_no_kevents();
365 
366     /*
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.
370      */
371     start = now();
372     if (clock_gettime(CLOCK_BOOTTIME, &btp) != 0)
373       err(1, "%s", test_id);
374 
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);
380 
381     /* Retrieve the event */
382     kev.flags = EV_ADD | EV_ONESHOT;
383     kev.data = 1;
384     kev.fflags = 0;
385     kevent_cmp(&kev, kevent_get(kqfd));
386 
387     stop = now();
388     if (stop < end)
389         err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
390     /* Check if the event occurs again */
391     sleep(3);
392     test_no_kevents();
393 
394     success();
395 }
396 
397 static void
test_abstime_postboot(void)398 test_abstime_postboot(void)
399 {
400     const char *test_id = "kevent(EVFILT_TIMER (POSTBOOT), EV_ONESHOT, NOTE_ABSTIME)";
401     struct kevent kev;
402     uint64_t end, start, stop;
403     const int timeout_sec = 1;
404 
405     test_begin(test_id);
406 
407     test_no_kevents();
408 
409     /*
410      * Set a timer for 1 second ago, it should fire immediately rather than
411      * being rejected.
412      */
413     start = now();
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);
419 
420     /* Retrieve the event */
421     kev.flags = EV_ADD | EV_ONESHOT;
422     kev.data = 1;
423     kev.fflags = 0;
424     kevent_cmp(&kev, kevent_get(kqfd));
425 
426     stop = now();
427     if (stop < end)
428         err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
429     /* Check if the event occurs again */
430     sleep(3);
431     test_no_kevents();
432 
433     success();
434 }
435 
436 static void
test_update(void)437 test_update(void)
438 {
439     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)";
440     struct kevent kev;
441     long elapsed;
442     uint64_t start;
443 
444     test_begin(test_id);
445 
446     test_no_kevents();
447 
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);
451     start = now();
452     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
453         err(1, "%s", test_id);
454 
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);
460 
461     /* Wait for the event */
462     kev.flags |= EV_CLEAR;
463     kev.fflags &= ~NOTE_USECONDS;
464     kev.data = 1;
465     kevent_cmp(&kev, kevent_get(kqfd));
466     elapsed = now() - start;
467 
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.
471      */
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);
477 
478     success();
479 }
480 
481 static void
test_update_equal(void)482 test_update_equal(void)
483 {
484     const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)";
485     struct kevent kev;
486     long elapsed;
487     uint64_t start;
488 
489     test_begin(test_id);
490 
491     test_no_kevents();
492 
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);
498 
499     /* Sleep for a significant fraction of the timeout. */
500     ussleep(600);
501 
502     /* Now re-add the timer with the same parameters */
503     start = now();
504     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
505         err(1, "%s", test_id);
506 
507     /* Wait for the event */
508     kev.flags |= EV_CLEAR;
509     kev.fflags &= ~NOTE_USECONDS;
510     kev.data = 1;
511     kevent_cmp(&kev, kevent_get(kqfd));
512     elapsed = now() - start;
513 
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.
517      */
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);
521 
522     success();
523 }
524 
525 static void
test_update_expired(void)526 test_update_expired(void)
527 {
528     const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)";
529     struct kevent kev;
530     long elapsed;
531     uint64_t start;
532 
533     test_begin(test_id);
534 
535     test_no_kevents();
536 
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);
542 
543     /* Wait for 2 ms to give the timer plenty of time to expire. */
544     mssleep(2);
545 
546     /* Now re-add the timer */
547     start = now();
548     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
549         err(1, "%s", test_id);
550 
551     /* Wait for the event */
552     kev.flags |= EV_CLEAR;
553     kev.fflags &= ~NOTE_USECONDS;
554     kev.data = 1;
555     kevent_cmp(&kev, kevent_get(kqfd));
556     elapsed = now() - start;
557 
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.
561      */
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);
565 
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.
569      */
570     mssleep(2);
571     test_no_kevents();
572 
573     success();
574 }
575 
576 static void
test_update_periodic(void)577 test_update_periodic(void)
578 {
579     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)";
580     struct kevent kev;
581     long elapsed;
582     uint64_t start, stop;
583 
584     test_begin(test_id);
585 
586     test_no_kevents();
587 
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);
591 
592     /* Retrieve the event */
593     kev.flags = EV_ADD | EV_CLEAR;
594     kev.data = 1;
595     kevent_cmp(&kev, kevent_get(kqfd));
596 
597     /* Check if the event occurs again */
598     sleep(1);
599     kevent_cmp(&kev, kevent_get(kqfd));
600 
601     /* Re-add with new timeout. */
602     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL);
603     start = now();
604     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
605         err(1, "%s", test_id);
606 
607     /* Retrieve the event */
608     kev.flags = EV_ADD | EV_CLEAR;
609     kev.data = 1;
610     kevent_cmp(&kev, kevent_get(kqfd));
611 
612     stop = now();
613     elapsed = stop - start;
614 
615     /* Check that the timer expired after at least 2 ms.
616      */
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);
620 
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);
625 
626     success();
627 }
628 
629 static void
test_update_timing(void)630 test_update_timing(void)
631 {
632 #define	MIN_SLEEP 500
633 #define	MAX_SLEEP 1500
634     const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)";
635     struct kevent kev;
636     int iteration;
637     int sleeptime;
638     long elapsed;
639     uint64_t start, stop;
640 
641     test_begin(test_id);
642 
643     test_no_kevents();
644 
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.
649      */
650     for (sleeptime = MIN_SLEEP, iteration = 1;
651          sleeptime < MAX_SLEEP;
652          ++sleeptime, ++iteration) {
653 
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);
659 
660         /* Delay; the delay ranges from less than to greater than the
661          * timer period.
662          */
663         ussleep(sleeptime);
664 
665         /* Now re-add the timer with the same parameters */
666         start = now();
667         if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
668             err(1, "%s", test_id);
669 
670         /* Wait for the event */
671         kev.flags |= EV_CLEAR;
672         kev.fflags &= ~NOTE_USECONDS;
673         kev.data = 1;
674         kevent_cmp(&kev, kevent_get(kqfd));
675         stop = now();
676         elapsed = stop - start;
677 
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.
681          */
682         if (elapsed < MS_TO_US(1))
683             errx(1, "early timer expiration: %ld us", elapsed);
684 
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.
688          */
689         mssleep(2);
690         test_no_kevents_quietly();
691     }
692 
693     success();
694 }
695 
696 static void
test_dispatch(void)697 test_dispatch(void)
698 {
699     const char *test_id = "kevent(EVFILT_TIMER, EV_ADD | EV_DISPATCH)";
700     struct kevent kev;
701 
702     test_no_kevents();
703 
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);
707 
708     /* Get one event */
709     kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
710     kev.data = 1;
711     kevent_cmp(&kev, kevent_get(kqfd));
712 
713     /* Confirm that the knote is disabled due to EV_DISPATCH */
714     usleep(500000);
715     test_no_kevents();
716 
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);
721     test_no_kevents();
722 
723     /* Get the next event */
724     usleep(1100000); /* 1100 ms */
725     kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
726     kev.data = 5;
727     kevent_cmp(&kev, kevent_get(kqfd));
728 
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 */
734     test_no_kevents();
735 
736     success();
737 }
738 
739 void
test_evfilt_timer(void)740 test_evfilt_timer(void)
741 {
742     kqfd = kqueue();
743     test_kevent_timer_add();
744     test_kevent_timer_del();
745     test_kevent_timer_get();
746     test_oneshot();
747     test_periodic();
748     test_periodic_modify();
749 #if WITH_NATIVE_KQUEUE_BUGS
750     test_periodic_to_oneshot();
751 #endif
752     test_abstime();
753     test_abstime_epoch();
754     test_abstime_preboot();
755     test_abstime_postboot();
756     test_update();
757     test_update_equal();
758     test_update_expired();
759     test_update_timing();
760     test_update_periodic();
761     test_disable_and_enable();
762     test_dispatch();
763     close(kqfd);
764 }
765