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. */
31 /* Get the current time with microsecond precision. Used for
32 * sub-second timing to make some timer tests run faster.
39 gettimeofday(&tv, NULL);
40 return SEC_TO_US(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)";
222 const int timeout = 3;
229 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
230 NOTE_ABSTIME | NOTE_SECONDS, start + timeout, 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));
240 if (stop < start + timeout)
241 err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)(start + timeout));
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)";
403 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL);
404 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
405 err(1, "%s", test_id);
407 /* Retrieve the event */
408 kev.flags = EV_ADD | EV_CLEAR;
410 kevent_cmp(&kev, kevent_get(kqfd));
412 /* Check if the event occurs again */
414 kevent_cmp(&kev, kevent_get(kqfd));
416 /* Re-add with new timeout. */
417 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL);
419 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
420 err(1, "%s", test_id);
422 /* Retrieve the event */
423 kev.flags = EV_ADD | EV_CLEAR;
425 kevent_cmp(&kev, kevent_get(kqfd));
428 elapsed = stop - start;
430 /* Check that the timer expired after at least 2 ms.
432 printf("timer expired after %ld us\n", elapsed);
433 if (elapsed < MS_TO_US(2))
434 errx(1, "early timer expiration: %ld us", elapsed);
436 /* Delete the event */
437 kev.flags = EV_DELETE;
438 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
439 err(1, "%s", test_id);
445 test_update_timing(void)
447 #define MIN_SLEEP 500
448 #define MAX_SLEEP 1500
449 const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)";
461 /* Re-try the update tests with a variety of delays between the
462 * original timer activation and the update of the timer. The goal
463 * is to show that in all cases the only timer event that is
464 * received is from the update and not the original timer add.
466 for (sleeptime = MIN_SLEEP, iteration = 1;
467 sleeptime < MAX_SLEEP;
468 ++sleeptime, ++iteration) {
470 /* First set the timer to 1 ms */
471 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
472 NOTE_USECONDS, MS_TO_US(1), NULL);
473 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
474 err(1, "%s", test_id);
476 /* Delay; the delay ranges from less than to greater than the
481 /* Now re-add the timer with the same parameters */
483 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
484 err(1, "%s", test_id);
486 /* Wait for the event */
487 kev.flags |= EV_CLEAR;
488 kev.fflags &= ~NOTE_USECONDS;
490 kevent_cmp(&kev, kevent_get(kqfd));
492 elapsed = stop - start;
494 /* Check that the timer expired after at least 1 ms. This
495 * check is to make sure that the timer re-started and that
496 * the event is not from the original add of the timer.
498 if (elapsed < MS_TO_US(1))
499 errx(1, "early timer expiration: %ld us", elapsed);
501 /* Make sure the re-added timer does not fire. In other words,
502 * test that the event received above was the only event from
503 * the add and re-add of the timer.
506 test_no_kevents_quietly();
516 test_kevent_timer_add();
517 test_kevent_timer_del();
518 test_kevent_timer_get();
524 test_update_expired();
525 test_update_timing();
526 test_update_periodic();
527 disable_and_enable();