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.
22 #define MILLION 1000000
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. */
30 /* Get the current time with microsecond precision. Used for
31 * sub-second timing to make some timer tests run faster.
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;
43 /* Sleep for a given number of milliseconds. The timeout is assumed to
44 * be less than 1 second.
49 struct timespec stime = {
51 .tv_nsec = US_TO_NS(MS_TO_US(t)),
54 nanosleep(&stime, NULL);
57 /* Sleep for a given number of microseconds. The timeout is assumed to
58 * be less than 1 second.
63 struct timespec stime = {
65 .tv_nsec = US_TO_NS(t),
68 nanosleep(&stime, NULL);
72 test_kevent_timer_add(void)
74 const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)";
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);
87 test_kevent_timer_del(void)
89 const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)";
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);
104 test_kevent_timer_get(void)
106 const char *test_id = "kevent(EVFILT_TIMER, wait)";
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);
115 kev.flags |= EV_CLEAR;
117 kevent_cmp(&kev, kevent_get(kqfd));
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);
129 const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)";
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);
140 /* Retrieve the event */
141 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
143 kevent_cmp(&kev, kevent_get(kqfd));
145 /* Check if the event occurs again */
156 const char *test_id = "kevent(EVFILT_TIMER, periodic)";
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);
167 /* Retrieve the event */
168 kev.flags = EV_ADD | EV_CLEAR;
170 kevent_cmp(&kev, kevent_get(kqfd));
172 /* Check if the event occurs again */
174 kevent_cmp(&kev, kevent_get(kqfd));
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);
185 disable_and_enable(void)
187 const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
194 /* Add the watch and immediately disable it */
195 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
196 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
197 err(1, "%s", test_id);
198 kev.flags = EV_DISABLE;
199 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
200 err(1, "%s", test_id);
203 /* Re-enable and check again */
204 kev.flags = EV_ENABLE;
205 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
206 err(1, "%s", test_id);
208 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
210 kevent_cmp(&kev, kevent_get(kqfd));
218 const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)";
220 uint64_t end, start, stop;
221 const int timeout_sec = 3;
228 end = start + SEC_TO_US(timeout_sec);
229 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
230 NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
231 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
232 err(1, "%s", test_id);
234 /* Retrieve the event */
235 kev.flags = EV_ADD | EV_ONESHOT;
238 kevent_cmp(&kev, kevent_get(kqfd));
242 err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
243 /* Check if the event occurs again */
253 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)";
262 /* First set the timer to 1 second */
263 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
264 NOTE_USECONDS, SEC_TO_US(1), (void *)1);
266 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
267 err(1, "%s", test_id);
269 /* Now reduce the timer to 1 ms */
270 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
271 NOTE_USECONDS, MS_TO_US(1), (void *)2);
272 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
273 err(1, "%s", test_id);
275 /* Wait for the event */
276 kev.flags |= EV_CLEAR;
277 kev.fflags &= ~NOTE_USECONDS;
279 kevent_cmp(&kev, kevent_get(kqfd));
280 elapsed = now() - start;
282 /* Check that the timer expired after at least 1 ms, but less than
283 * 1 second. This check is to make sure that the original 1 second
284 * timeout was not used.
286 printf("timer expired after %ld us\n", elapsed);
287 if (elapsed < MS_TO_US(1))
288 errx(1, "early timer expiration: %ld us", elapsed);
289 if (elapsed > SEC_TO_US(1))
290 errx(1, "late timer expiration: %ld us", elapsed);
296 test_update_equal(void)
298 const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)";
307 /* First set the timer to 1 ms */
308 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
309 NOTE_USECONDS, MS_TO_US(1), NULL);
310 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
311 err(1, "%s", test_id);
313 /* Sleep for a significant fraction of the timeout. */
316 /* Now re-add the timer with the same parameters */
318 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
319 err(1, "%s", test_id);
321 /* Wait for the event */
322 kev.flags |= EV_CLEAR;
323 kev.fflags &= ~NOTE_USECONDS;
325 kevent_cmp(&kev, kevent_get(kqfd));
326 elapsed = now() - start;
328 /* Check that the timer expired after at least 1 ms. This check is
329 * to make sure that the timer re-started and that the event is
330 * not from the original add of the timer.
332 printf("timer expired after %ld us\n", elapsed);
333 if (elapsed < MS_TO_US(1))
334 errx(1, "early timer expiration: %ld us", elapsed);
340 test_update_expired(void)
342 const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)";
351 /* Set the timer to 1ms */
352 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
353 NOTE_USECONDS, MS_TO_US(1), NULL);
354 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
355 err(1, "%s", test_id);
357 /* Wait for 2 ms to give the timer plenty of time to expire. */
360 /* Now re-add the timer */
362 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
363 err(1, "%s", test_id);
365 /* Wait for the event */
366 kev.flags |= EV_CLEAR;
367 kev.fflags &= ~NOTE_USECONDS;
369 kevent_cmp(&kev, kevent_get(kqfd));
370 elapsed = now() - start;
372 /* Check that the timer expired after at least 1 ms. This check
373 * is to make sure that the timer re-started and that the event is
374 * not from the original add (and expiration) of the timer.
376 printf("timer expired after %ld us\n", elapsed);
377 if (elapsed < MS_TO_US(1))
378 errx(1, "early timer expiration: %ld us", elapsed);
380 /* Make sure the re-added timer does not fire. In other words,
381 * test that the event received above was the only event from the
382 * add and re-add of the timer.
391 test_update_periodic(void)
393 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)";
396 uint64_t start, stop;
402 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL);
403 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
404 err(1, "%s", test_id);
406 /* Retrieve the event */
407 kev.flags = EV_ADD | EV_CLEAR;
409 kevent_cmp(&kev, kevent_get(kqfd));
411 /* Check if the event occurs again */
413 kevent_cmp(&kev, kevent_get(kqfd));
415 /* Re-add with new timeout. */
416 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL);
418 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
419 err(1, "%s", test_id);
421 /* Retrieve the event */
422 kev.flags = EV_ADD | EV_CLEAR;
424 kevent_cmp(&kev, kevent_get(kqfd));
427 elapsed = stop - start;
429 /* Check that the timer expired after at least 2 ms.
431 printf("timer expired after %ld us\n", elapsed);
432 if (elapsed < MS_TO_US(2))
433 errx(1, "early timer expiration: %ld us", elapsed);
435 /* Delete the event */
436 kev.flags = EV_DELETE;
437 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
438 err(1, "%s", test_id);
444 test_update_timing(void)
446 #define MIN_SLEEP 500
447 #define MAX_SLEEP 1500
448 const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)";
453 uint64_t start, stop;
459 /* Re-try the update tests with a variety of delays between the
460 * original timer activation and the update of the timer. The goal
461 * is to show that in all cases the only timer event that is
462 * received is from the update and not the original timer add.
464 for (sleeptime = MIN_SLEEP, iteration = 1;
465 sleeptime < MAX_SLEEP;
466 ++sleeptime, ++iteration) {
468 /* First set the timer to 1 ms */
469 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
470 NOTE_USECONDS, MS_TO_US(1), NULL);
471 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
472 err(1, "%s", test_id);
474 /* Delay; the delay ranges from less than to greater than the
479 /* Now re-add the timer with the same parameters */
481 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
482 err(1, "%s", test_id);
484 /* Wait for the event */
485 kev.flags |= EV_CLEAR;
486 kev.fflags &= ~NOTE_USECONDS;
488 kevent_cmp(&kev, kevent_get(kqfd));
490 elapsed = stop - start;
492 /* Check that the timer expired after at least 1 ms. This
493 * check is to make sure that the timer re-started and that
494 * the event is not from the original add of the timer.
496 if (elapsed < MS_TO_US(1))
497 errx(1, "early timer expiration: %ld us", elapsed);
499 /* Make sure the re-added timer does not fire. In other words,
500 * test that the event received above was the only event from
501 * the add and re-add of the timer.
504 test_no_kevents_quietly();
511 test_evfilt_timer(void)
514 test_kevent_timer_add();
515 test_kevent_timer_del();
516 test_kevent_timer_get();
522 test_update_expired();
523 test_update_timing();
524 test_update_periodic();
525 disable_and_enable();