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 return SEC_TO_US(tv.tv_sec) + tv.tv_usec;
42 /* Sleep for a given number of milliseconds. The timeout is assumed to
43 * be less than 1 second.
48 struct timespec stime = {
50 .tv_nsec = US_TO_NS(MS_TO_US(t)),
53 nanosleep(&stime, NULL);
56 /* Sleep for a given number of microseconds. The timeout is assumed to
57 * be less than 1 second.
62 struct timespec stime = {
64 .tv_nsec = US_TO_NS(t),
67 nanosleep(&stime, NULL);
71 test_kevent_timer_add(void)
73 const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)";
78 EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
79 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
80 err(1, "%s", test_id);
86 test_kevent_timer_del(void)
88 const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)";
93 EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
94 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
95 err(1, "%s", test_id);
103 test_kevent_timer_get(void)
105 const char *test_id = "kevent(EVFILT_TIMER, wait)";
110 EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
111 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
112 err(1, "%s", test_id);
114 kev.flags |= EV_CLEAR;
116 kevent_cmp(&kev, kevent_get(kqfd));
118 EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
119 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
120 err(1, "%s", test_id);
128 const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)";
135 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL);
136 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
137 err(1, "%s", test_id);
139 /* Retrieve the event */
140 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
142 kevent_cmp(&kev, kevent_get(kqfd));
144 /* Check if the event occurs again */
155 const char *test_id = "kevent(EVFILT_TIMER, periodic)";
162 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL);
163 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
164 err(1, "%s", test_id);
166 /* Retrieve the event */
167 kev.flags = EV_ADD | EV_CLEAR;
169 kevent_cmp(&kev, kevent_get(kqfd));
171 /* Check if the event occurs again */
173 kevent_cmp(&kev, kevent_get(kqfd));
175 /* Delete the event */
176 kev.flags = EV_DELETE;
177 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
178 err(1, "%s", test_id);
184 disable_and_enable(void)
186 const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
193 /* Add the watch and immediately disable it */
194 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
195 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
196 err(1, "%s", test_id);
197 kev.flags = EV_DISABLE;
198 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
199 err(1, "%s", test_id);
202 /* Re-enable and check again */
203 kev.flags = EV_ENABLE;
204 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
205 err(1, "%s", test_id);
207 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
209 kevent_cmp(&kev, kevent_get(kqfd));
217 const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)";
221 const int timeout = 3;
228 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
229 NOTE_ABSTIME | NOTE_SECONDS, start + timeout, NULL);
230 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
231 err(1, "%s", test_id);
233 /* Retrieve the event */
234 kev.flags = EV_ADD | EV_ONESHOT;
237 kevent_cmp(&kev, kevent_get(kqfd));
239 if (stop < start + timeout)
240 err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)(start + timeout));
242 /* Check if the event occurs again */
252 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)";
261 /* First set the timer to 1 second */
262 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
263 NOTE_USECONDS, SEC_TO_US(1), (void *)1);
265 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
266 err(1, "%s", test_id);
268 /* Now reduce the timer to 1 ms */
269 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
270 NOTE_USECONDS, MS_TO_US(1), (void *)2);
271 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
272 err(1, "%s", test_id);
274 /* Wait for the event */
275 kev.flags |= EV_CLEAR;
276 kev.fflags &= ~NOTE_USECONDS;
278 kevent_cmp(&kev, kevent_get(kqfd));
279 elapsed = now() - start;
281 /* Check that the timer expired after at least 1 ms, but less than
282 * 1 second. This check is to make sure that the original 1 second
283 * timeout was not used.
285 printf("timer expired after %ld us\n", elapsed);
286 if (elapsed < MS_TO_US(1))
287 errx(1, "early timer expiration: %ld us", elapsed);
288 if (elapsed > SEC_TO_US(1))
289 errx(1, "late timer expiration: %ld us", elapsed);
295 test_update_equal(void)
297 const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)";
306 /* First set the timer to 1 ms */
307 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
308 NOTE_USECONDS, MS_TO_US(1), NULL);
309 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
310 err(1, "%s", test_id);
312 /* Sleep for a significant fraction of the timeout. */
315 /* Now re-add the timer with the same parameters */
317 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
318 err(1, "%s", test_id);
320 /* Wait for the event */
321 kev.flags |= EV_CLEAR;
322 kev.fflags &= ~NOTE_USECONDS;
324 kevent_cmp(&kev, kevent_get(kqfd));
325 elapsed = now() - start;
327 /* Check that the timer expired after at least 1 ms. This check is
328 * to make sure that the timer re-started and that the event is
329 * not from the original add of the timer.
331 printf("timer expired after %ld us\n", elapsed);
332 if (elapsed < MS_TO_US(1))
333 errx(1, "early timer expiration: %ld us", elapsed);
339 test_update_expired(void)
341 const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)";
350 /* Set the timer to 1ms */
351 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
352 NOTE_USECONDS, MS_TO_US(1), NULL);
353 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
354 err(1, "%s", test_id);
356 /* Wait for 2 ms to give the timer plenty of time to expire. */
359 /* Now re-add the timer */
361 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
362 err(1, "%s", test_id);
364 /* Wait for the event */
365 kev.flags |= EV_CLEAR;
366 kev.fflags &= ~NOTE_USECONDS;
368 kevent_cmp(&kev, kevent_get(kqfd));
369 elapsed = now() - start;
371 /* Check that the timer expired after at least 1 ms. This check
372 * is to make sure that the timer re-started and that the event is
373 * not from the original add (and expiration) of the timer.
375 printf("timer expired after %ld us\n", elapsed);
376 if (elapsed < MS_TO_US(1))
377 errx(1, "early timer expiration: %ld us", elapsed);
379 /* Make sure the re-added timer does not fire. In other words,
380 * test that the event received above was the only event from the
381 * add and re-add of the timer.
390 test_update_periodic(void)
392 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)";
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)";
460 /* Re-try the update tests with a variety of delays between the
461 * original timer activation and the update of the timer. The goal
462 * is to show that in all cases the only timer event that is
463 * received is from the update and not the original timer add.
465 for (sleeptime = MIN_SLEEP, iteration = 1;
466 sleeptime < MAX_SLEEP;
467 ++sleeptime, ++iteration) {
469 /* First set the timer to 1 ms */
470 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
471 NOTE_USECONDS, MS_TO_US(1), NULL);
472 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
473 err(1, "%s", test_id);
475 /* Delay; the delay ranges from less than to greater than the
480 /* Now re-add the timer with the same parameters */
482 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
483 err(1, "%s", test_id);
485 /* Wait for the event */
486 kev.flags |= EV_CLEAR;
487 kev.fflags &= ~NOTE_USECONDS;
489 kevent_cmp(&kev, kevent_get(kqfd));
491 elapsed = stop - start;
493 /* Check that the timer expired after at least 1 ms. This
494 * check is to make sure that the timer re-started and that
495 * the event is not from the original add of the timer.
497 if (elapsed < MS_TO_US(1))
498 errx(1, "early timer expiration: %ld us", elapsed);
500 /* Make sure the re-added timer does not fire. In other words,
501 * test that the event received above was the only event from
502 * the add and re-add of the timer.
505 test_no_kevents_quietly();
515 test_kevent_timer_add();
516 test_kevent_timer_del();
517 test_kevent_timer_get();
523 test_update_expired();
524 test_update_timing();
525 test_update_periodic();
526 disable_and_enable();