xref: /freebsd/tests/sys/kqueue/libkqueue/timer.c (revision 38a52bd3)
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  * $FreeBSD$
17  */
18 
19 #include "common.h"
20 #include <sys/time.h>
21 
22 #define	MILLION 1000000
23 #define	THOUSAND 1000
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. */
28 
29 
30 /* Get the current time with microsecond precision. Used for
31  * sub-second timing to make some timer tests run faster.
32  */
33 static uint64_t
34 now(void)
35 {
36     struct timeval tv;
37 
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;
41 }
42 
43 /* Sleep for a given number of milliseconds. The timeout is assumed to
44  * be less than 1 second.
45  */
46 static void
47 mssleep(int t)
48 {
49     struct timespec stime = {
50         .tv_sec = 0,
51         .tv_nsec = US_TO_NS(MS_TO_US(t)),
52     };
53 
54     nanosleep(&stime, NULL);
55 }
56 
57 /* Sleep for a given number of microseconds. The timeout is assumed to
58  * be less than 1 second.
59  */
60 static void
61 ussleep(int t)
62 {
63     struct timespec stime = {
64         .tv_sec = 0,
65         .tv_nsec = US_TO_NS(t),
66     };
67 
68     nanosleep(&stime, NULL);
69 }
70 
71 static void
72 test_kevent_timer_add(void)
73 {
74     const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)";
75     struct kevent kev;
76 
77     test_begin(test_id);
78 
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);
82 
83     success();
84 }
85 
86 static void
87 test_kevent_timer_del(void)
88 {
89     const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)";
90     struct kevent kev;
91 
92     test_begin(test_id);
93 
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);
97 
98     test_no_kevents();
99 
100     success();
101 }
102 
103 static void
104 test_kevent_timer_get(void)
105 {
106     const char *test_id = "kevent(EVFILT_TIMER, wait)";
107     struct kevent kev;
108 
109     test_begin(test_id);
110 
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);
114 
115     kev.flags |= EV_CLEAR;
116     kev.data = 1;
117     kevent_cmp(&kev, kevent_get(kqfd));
118 
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);
122 
123     success();
124 }
125 
126 static void
127 test_oneshot(void)
128 {
129     const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)";
130     struct kevent kev;
131 
132     test_begin(test_id);
133 
134     test_no_kevents();
135 
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);
139 
140     /* Retrieve the event */
141     kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
142     kev.data = 1;
143     kevent_cmp(&kev, kevent_get(kqfd));
144 
145     /* Check if the event occurs again */
146     sleep(3);
147     test_no_kevents();
148 
149 
150     success();
151 }
152 
153 static void
154 test_periodic(void)
155 {
156     const char *test_id = "kevent(EVFILT_TIMER, periodic)";
157     struct kevent kev;
158 
159     test_begin(test_id);
160 
161     test_no_kevents();
162 
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);
166 
167     /* Retrieve the event */
168     kev.flags = EV_ADD | EV_CLEAR;
169     kev.data = 1;
170     kevent_cmp(&kev, kevent_get(kqfd));
171 
172     /* Check if the event occurs again */
173     sleep(1);
174     kevent_cmp(&kev, kevent_get(kqfd));
175 
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);
180 
181     success();
182 }
183 
184 static void
185 test_periodic_modify(void)
186 {
187     const char *test_id = "kevent(EVFILT_TIMER, periodic_modify)";
188     struct kevent kev;
189 
190     test_begin(test_id);
191 
192     test_no_kevents();
193 
194     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
195     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
196         err(1, "%s", test_id);
197 
198     /* Retrieve the event */
199     kev.flags = EV_ADD | EV_CLEAR;
200     kev.data = 1;
201     kevent_cmp(&kev, kevent_get(kqfd));
202 
203     /* Check if the event occurs again */
204     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 500, NULL);
205     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
206         err(1, "%s", test_id);
207 
208     kev.flags = EV_ADD | EV_CLEAR;
209     sleep(1);
210     kev.data = 2;	/* Should have fired twice */
211 
212     kevent_cmp(&kev, kevent_get(kqfd));
213 
214     /* Delete the event */
215     kev.flags = EV_DELETE;
216     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
217         err(1, "%s", test_id);
218 
219     success();
220 }
221 
222 #if WITH_NATIVE_KQUEUE_BUGS
223 static void
224 test_periodic_to_oneshot(void)
225 {
226     const char *test_id = "kevent(EVFILT_TIMER, period_to_oneshot)";
227     struct kevent kev;
228 
229     test_begin(test_id);
230 
231     test_no_kevents();
232 
233     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
234     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
235         err(1, "%s", test_id);
236 
237     /* Retrieve the event */
238     kev.flags = EV_ADD | EV_CLEAR;
239     kev.data = 1;
240     kevent_cmp(&kev, kevent_get(kqfd));
241 
242     /* Check if the event occurs again */
243     sleep(1);
244     kevent_cmp(&kev, kevent_get(kqfd));
245 
246     /* Switch to oneshot */
247     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500, NULL);
248     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
249         err(1, "%s", test_id);
250     kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
251 
252     sleep(1);
253     kev.data = 1;	/* Should have fired once */
254 
255     kevent_cmp(&kev, kevent_get(kqfd));
256 
257     success();
258 }
259 #endif
260 
261 static void
262 test_disable_and_enable(void)
263 {
264     const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
265     struct kevent kev;
266 
267     test_begin(test_id);
268 
269     test_no_kevents();
270 
271     /* Add the watch and immediately disable it */
272     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
273     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
274         err(1, "%s", test_id);
275     kev.flags = EV_DISABLE;
276     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
277         err(1, "%s", test_id);
278     test_no_kevents();
279 
280     /* Re-enable and check again */
281     kev.flags = EV_ENABLE;
282     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
283         err(1, "%s", test_id);
284 
285     kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
286     kev.data = 1;
287     kevent_cmp(&kev, kevent_get(kqfd));
288 
289     success();
290 }
291 
292 static void
293 test_abstime(void)
294 {
295     const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)";
296     struct kevent kev;
297     uint64_t end, start, stop;
298     const int timeout_sec = 3;
299 
300     test_begin(test_id);
301 
302     test_no_kevents();
303 
304     start = now();
305     end = start + SEC_TO_US(timeout_sec);
306     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
307       NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
308     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
309         err(1, "%s", test_id);
310 
311     /* Retrieve the event */
312     kev.flags = EV_ADD | EV_ONESHOT;
313     kev.data = 1;
314     kev.fflags = 0;
315     kevent_cmp(&kev, kevent_get(kqfd));
316 
317     stop = now();
318     if (stop < end)
319         err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
320     /* Check if the event occurs again */
321     sleep(3);
322     test_no_kevents();
323 
324     success();
325 }
326 
327 static void
328 test_abstime_epoch(void)
329 {
330     const char *test_id = "kevent(EVFILT_TIMER (EPOCH), NOTE_ABSTIME)";
331     struct kevent kev;
332 
333     test_begin(test_id);
334 
335     test_no_kevents();
336 
337     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, NOTE_ABSTIME, 0,
338         NULL);
339     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
340         err(1, "%s", test_id);
341 
342     /* Retrieve the event */
343     kev.flags = EV_ADD;
344     kev.data = 1;
345     kev.fflags = 0;
346     kevent_cmp(&kev, kevent_get(kqfd));
347 
348     /* Delete the event */
349     kev.flags = EV_DELETE;
350     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
351         err(1, "%s", test_id);
352 
353     success();
354 }
355 
356 static void
357 test_abstime_preboot(void)
358 {
359     const char *test_id = "kevent(EVFILT_TIMER (PREBOOT), EV_ONESHOT, NOTE_ABSTIME)";
360     struct kevent kev;
361     struct timespec btp;
362     uint64_t end, start, stop;
363 
364     test_begin(test_id);
365 
366     test_no_kevents();
367 
368     /*
369      * We'll expire it at just before system boot (roughly) with the hope that
370      * we'll get an ~immediate expiration, just as we do for any value specified
371      * between system boot and now.
372      */
373     start = now();
374     if (clock_gettime(CLOCK_BOOTTIME, &btp) != 0)
375       err(1, "%s", test_id);
376 
377     end = start - SEC_TO_US(btp.tv_sec + 1);
378     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
379       NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
380     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
381         err(1, "%s", test_id);
382 
383     /* Retrieve the event */
384     kev.flags = EV_ADD | EV_ONESHOT;
385     kev.data = 1;
386     kev.fflags = 0;
387     kevent_cmp(&kev, kevent_get(kqfd));
388 
389     stop = now();
390     if (stop < end)
391         err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
392     /* Check if the event occurs again */
393     sleep(3);
394     test_no_kevents();
395 
396     success();
397 }
398 
399 static void
400 test_abstime_postboot(void)
401 {
402     const char *test_id = "kevent(EVFILT_TIMER (POSTBOOT), EV_ONESHOT, NOTE_ABSTIME)";
403     struct kevent kev;
404     uint64_t end, start, stop;
405     const int timeout_sec = 1;
406 
407     test_begin(test_id);
408 
409     test_no_kevents();
410 
411     /*
412      * Set a timer for 1 second ago, it should fire immediately rather than
413      * being rejected.
414      */
415     start = now();
416     end = start - SEC_TO_US(timeout_sec);
417     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
418       NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
419     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
420         err(1, "%s", test_id);
421 
422     /* Retrieve the event */
423     kev.flags = EV_ADD | EV_ONESHOT;
424     kev.data = 1;
425     kev.fflags = 0;
426     kevent_cmp(&kev, kevent_get(kqfd));
427 
428     stop = now();
429     if (stop < end)
430         err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
431     /* Check if the event occurs again */
432     sleep(3);
433     test_no_kevents();
434 
435     success();
436 }
437 
438 static void
439 test_update(void)
440 {
441     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)";
442     struct kevent kev;
443     long elapsed;
444     uint64_t start;
445 
446     test_begin(test_id);
447 
448     test_no_kevents();
449 
450     /* First set the timer to 1 second */
451     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
452         NOTE_USECONDS, SEC_TO_US(1), (void *)1);
453     start = now();
454     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
455         err(1, "%s", test_id);
456 
457     /* Now reduce the timer to 1 ms */
458     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
459         NOTE_USECONDS, MS_TO_US(1), (void *)2);
460     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
461         err(1, "%s", test_id);
462 
463     /* Wait for the event */
464     kev.flags |= EV_CLEAR;
465     kev.fflags &= ~NOTE_USECONDS;
466     kev.data = 1;
467     kevent_cmp(&kev, kevent_get(kqfd));
468     elapsed = now() - start;
469 
470     /* Check that the timer expired after at least 1 ms, but less than
471      * 1 second. This check is to make sure that the original 1 second
472      * timeout was not used.
473      */
474     printf("timer expired after %ld us\n", elapsed);
475     if (elapsed < MS_TO_US(1))
476         errx(1, "early timer expiration: %ld us", elapsed);
477     if (elapsed > SEC_TO_US(1))
478         errx(1, "late timer expiration: %ld us", elapsed);
479 
480     success();
481 }
482 
483 static void
484 test_update_equal(void)
485 {
486     const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)";
487     struct kevent kev;
488     long elapsed;
489     uint64_t start;
490 
491     test_begin(test_id);
492 
493     test_no_kevents();
494 
495     /* First set the timer to 1 ms */
496     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
497         NOTE_USECONDS, MS_TO_US(1), NULL);
498     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
499         err(1, "%s", test_id);
500 
501     /* Sleep for a significant fraction of the timeout. */
502     ussleep(600);
503 
504     /* Now re-add the timer with the same parameters */
505     start = now();
506     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
507         err(1, "%s", test_id);
508 
509     /* Wait for the event */
510     kev.flags |= EV_CLEAR;
511     kev.fflags &= ~NOTE_USECONDS;
512     kev.data = 1;
513     kevent_cmp(&kev, kevent_get(kqfd));
514     elapsed = now() - start;
515 
516     /* Check that the timer expired after at least 1 ms. This check is
517      * to make sure that the timer re-started and that the event is
518      * not from the original add of the timer.
519      */
520     printf("timer expired after %ld us\n", elapsed);
521     if (elapsed < MS_TO_US(1))
522         errx(1, "early timer expiration: %ld us", elapsed);
523 
524     success();
525 }
526 
527 static void
528 test_update_expired(void)
529 {
530     const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)";
531     struct kevent kev;
532     long elapsed;
533     uint64_t start;
534 
535     test_begin(test_id);
536 
537     test_no_kevents();
538 
539     /* Set the timer to 1ms */
540     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
541         NOTE_USECONDS, MS_TO_US(1), NULL);
542     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
543         err(1, "%s", test_id);
544 
545     /* Wait for 2 ms to give the timer plenty of time to expire. */
546     mssleep(2);
547 
548     /* Now re-add the timer */
549     start = now();
550     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
551         err(1, "%s", test_id);
552 
553     /* Wait for the event */
554     kev.flags |= EV_CLEAR;
555     kev.fflags &= ~NOTE_USECONDS;
556     kev.data = 1;
557     kevent_cmp(&kev, kevent_get(kqfd));
558     elapsed = now() - start;
559 
560     /* Check that the timer expired after at least 1 ms.  This check
561      * is to make sure that the timer re-started and that the event is
562      * not from the original add (and expiration) of the timer.
563      */
564     printf("timer expired after %ld us\n", elapsed);
565     if (elapsed < MS_TO_US(1))
566         errx(1, "early timer expiration: %ld us", elapsed);
567 
568     /* Make sure the re-added timer does not fire. In other words,
569      * test that the event received above was the only event from the
570      * add and re-add of the timer.
571      */
572     mssleep(2);
573     test_no_kevents();
574 
575     success();
576 }
577 
578 static void
579 test_update_periodic(void)
580 {
581     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)";
582     struct kevent kev;
583     long elapsed;
584     uint64_t start, stop;
585 
586     test_begin(test_id);
587 
588     test_no_kevents();
589 
590     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL);
591     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
592         err(1, "%s", test_id);
593 
594     /* Retrieve the event */
595     kev.flags = EV_ADD | EV_CLEAR;
596     kev.data = 1;
597     kevent_cmp(&kev, kevent_get(kqfd));
598 
599     /* Check if the event occurs again */
600     sleep(1);
601     kevent_cmp(&kev, kevent_get(kqfd));
602 
603     /* Re-add with new timeout. */
604     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL);
605     start = now();
606     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
607         err(1, "%s", test_id);
608 
609     /* Retrieve the event */
610     kev.flags = EV_ADD | EV_CLEAR;
611     kev.data = 1;
612     kevent_cmp(&kev, kevent_get(kqfd));
613 
614     stop = now();
615     elapsed = stop - start;
616 
617     /* Check that the timer expired after at least 2 ms.
618      */
619     printf("timer expired after %ld us\n", elapsed);
620     if (elapsed < MS_TO_US(2))
621         errx(1, "early timer expiration: %ld us", elapsed);
622 
623     /* Delete the event */
624     kev.flags = EV_DELETE;
625     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
626         err(1, "%s", test_id);
627 
628     success();
629 }
630 
631 static void
632 test_update_timing(void)
633 {
634 #define	MIN_SLEEP 500
635 #define	MAX_SLEEP 1500
636     const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)";
637     struct kevent kev;
638     int iteration;
639     int sleeptime;
640     long elapsed;
641     uint64_t start, stop;
642 
643     test_begin(test_id);
644 
645     test_no_kevents();
646 
647     /* Re-try the update tests with a variety of delays between the
648      * original timer activation and the update of the timer. The goal
649      * is to show that in all cases the only timer event that is
650      * received is from the update and not the original timer add.
651      */
652     for (sleeptime = MIN_SLEEP, iteration = 1;
653          sleeptime < MAX_SLEEP;
654          ++sleeptime, ++iteration) {
655 
656         /* First set the timer to 1 ms */
657         EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
658             NOTE_USECONDS, MS_TO_US(1), NULL);
659         if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
660             err(1, "%s", test_id);
661 
662         /* Delay; the delay ranges from less than to greater than the
663          * timer period.
664          */
665         ussleep(sleeptime);
666 
667         /* Now re-add the timer with the same parameters */
668         start = now();
669         if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
670             err(1, "%s", test_id);
671 
672         /* Wait for the event */
673         kev.flags |= EV_CLEAR;
674         kev.fflags &= ~NOTE_USECONDS;
675         kev.data = 1;
676         kevent_cmp(&kev, kevent_get(kqfd));
677         stop = now();
678         elapsed = stop - start;
679 
680         /* Check that the timer expired after at least 1 ms. This
681          * check is to make sure that the timer re-started and that
682          * the event is not from the original add of the timer.
683          */
684         if (elapsed < MS_TO_US(1))
685             errx(1, "early timer expiration: %ld us", elapsed);
686 
687         /* Make sure the re-added timer does not fire. In other words,
688          * test that the event received above was the only event from
689          * the add and re-add of the timer.
690          */
691         mssleep(2);
692         test_no_kevents_quietly();
693     }
694 
695     success();
696 }
697 
698 static void
699 test_dispatch(void)
700 {
701     const char *test_id = "kevent(EVFILT_TIMER, EV_ADD | EV_DISPATCH)";
702     struct kevent kev;
703 
704     test_no_kevents();
705 
706     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_DISPATCH, 0, 200, NULL);
707     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
708         err(1, "%s", test_id);
709 
710     /* Get one event */
711     kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
712     kev.data = 1;
713     kevent_cmp(&kev, kevent_get(kqfd));
714 
715     /* Confirm that the knote is disabled due to EV_DISPATCH */
716     usleep(500000);
717     test_no_kevents();
718 
719     /* Enable the knote and make sure no events are pending */
720     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_DISPATCH, 0, 200, NULL);
721     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
722         err(1, "%s", test_id);
723     test_no_kevents();
724 
725     /* Get the next event */
726     usleep(1100000); /* 1100 ms */
727     kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
728     kev.data = 5;
729     kevent_cmp(&kev, kevent_get(kqfd));
730 
731     /* Remove the knote and ensure the event no longer fires */
732     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
733     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
734         err(1, "%s", test_id);
735     usleep(500000); /* 500ms */
736     test_no_kevents();
737 
738     success();
739 }
740 
741 void
742 test_evfilt_timer(void)
743 {
744     kqfd = kqueue();
745     test_kevent_timer_add();
746     test_kevent_timer_del();
747     test_kevent_timer_get();
748     test_oneshot();
749     test_periodic();
750     test_periodic_modify();
751 #if WITH_NATIVE_KQUEUE_BUGS
752     test_periodic_to_oneshot();
753 #endif
754     test_abstime();
755     test_abstime_epoch();
756     test_abstime_preboot();
757     test_abstime_postboot();
758     test_update();
759     test_update_equal();
760     test_update_expired();
761     test_update_timing();
762     test_update_periodic();
763     test_disable_and_enable();
764     test_dispatch();
765     close(kqfd);
766 }
767