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 */
31static uint64_t
32now(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 */
44static void
45mssleep(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 */
58static void
59ussleep(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
69static void
70test_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
84static void
85test_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
101static void
102test_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
124static void
125test_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
151static void
152test_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
182static void
183test_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
221static void
222test_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
259static void
260test_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
290static void
291test_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
325static void
326test_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
354static void
355test_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
397static void
398test_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
436static void
437test_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
481static void
482test_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
525static void
526test_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
576static void
577test_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
629static void
630test_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
696static void
697test_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
739void
740test_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