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