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.
40 gettimeofday(&tv, NULL);
41 return SEC_TO_US(tv.tv_sec) + tv.tv_usec;
44 /* Sleep for a given number of milliseconds. The timeout is assumed to
45 * be less than 1 second.
51 struct timespec stime = {
53 .tv_nsec = US_TO_NS(MS_TO_US(t)),
56 nanosleep(&stime, NULL);
59 /* Sleep for a given number of microseconds. The timeout is assumed to
60 * be less than 1 second.
66 struct timespec stime = {
68 .tv_nsec = US_TO_NS(t),
71 nanosleep(&stime, NULL);
75 test_kevent_timer_add(void)
77 const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)";
82 EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
83 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
84 err(1, "%s", test_id);
90 test_kevent_timer_del(void)
92 const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)";
97 EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
98 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
99 err(1, "%s", test_id);
107 test_kevent_timer_get(void)
109 const char *test_id = "kevent(EVFILT_TIMER, wait)";
114 EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
115 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
116 err(1, "%s", test_id);
118 kev.flags |= EV_CLEAR;
120 kevent_cmp(&kev, kevent_get(kqfd));
122 EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
123 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
124 err(1, "%s", test_id);
132 const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)";
139 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL);
140 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
141 err(1, "%s", test_id);
143 /* Retrieve the event */
144 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
146 kevent_cmp(&kev, kevent_get(kqfd));
148 /* Check if the event occurs again */
159 const char *test_id = "kevent(EVFILT_TIMER, periodic)";
166 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL);
167 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
168 err(1, "%s", test_id);
170 /* Retrieve the event */
171 kev.flags = EV_ADD | EV_CLEAR;
173 kevent_cmp(&kev, kevent_get(kqfd));
175 /* Check if the event occurs again */
177 kevent_cmp(&kev, kevent_get(kqfd));
179 /* Delete the event */
180 kev.flags = EV_DELETE;
181 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
182 err(1, "%s", test_id);
188 disable_and_enable(void)
190 const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
197 /* Add the watch and immediately disable it */
198 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
199 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
200 err(1, "%s", test_id);
201 kev.flags = EV_DISABLE;
202 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
203 err(1, "%s", test_id);
206 /* Re-enable and check again */
207 kev.flags = EV_ENABLE;
208 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
209 err(1, "%s", test_id);
211 kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
213 kevent_cmp(&kev, kevent_get(kqfd));
221 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)";
230 /* First set the timer to 1 second */
231 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
232 NOTE_USECONDS, SEC_TO_US(1), (void *)1);
234 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
235 err(1, "%s", test_id);
237 /* Now reduce the timer to 1 ms */
238 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
239 NOTE_USECONDS, MS_TO_US(1), (void *)2);
240 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
241 err(1, "%s", test_id);
243 /* Wait for the event */
244 kev.flags |= EV_CLEAR;
245 kev.fflags &= ~NOTE_USECONDS;
247 kevent_cmp(&kev, kevent_get(kqfd));
248 elapsed = now() - start;
250 /* Check that the timer expired after at least 1 ms, but less than
251 * 1 second. This check is to make sure that the original 1 second
252 * timeout was not used.
254 printf("timer expired after %ld us\n", elapsed);
255 if (elapsed < MS_TO_US(1))
256 errx(1, "early timer expiration: %ld us", elapsed);
257 if (elapsed > SEC_TO_US(1))
258 errx(1, "late timer expiration: %ld us", elapsed);
264 test_update_equal(void)
266 const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)";
275 /* First set the timer to 1 ms */
276 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
277 NOTE_USECONDS, MS_TO_US(1), NULL);
278 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
279 err(1, "%s", test_id);
281 /* Sleep for a significant fraction of the timeout. */
284 /* Now re-add the timer with the same parameters */
286 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
287 err(1, "%s", test_id);
289 /* Wait for the event */
290 kev.flags |= EV_CLEAR;
291 kev.fflags &= ~NOTE_USECONDS;
293 kevent_cmp(&kev, kevent_get(kqfd));
294 elapsed = now() - start;
296 /* Check that the timer expired after at least 1 ms. This check is
297 * to make sure that the timer re-started and that the event is
298 * not from the original add of the timer.
300 printf("timer expired after %ld us\n", elapsed);
301 if (elapsed < MS_TO_US(1))
302 errx(1, "early timer expiration: %ld us", elapsed);
308 test_update_expired(void)
310 const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)";
319 /* Set the timer to 1ms */
320 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
321 NOTE_USECONDS, MS_TO_US(1), NULL);
322 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
323 err(1, "%s", test_id);
325 /* Wait for 2 ms to give the timer plenty of time to expire. */
328 /* Now re-add the timer */
330 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
331 err(1, "%s", test_id);
333 /* Wait for the event */
334 kev.flags |= EV_CLEAR;
335 kev.fflags &= ~NOTE_USECONDS;
337 kevent_cmp(&kev, kevent_get(kqfd));
338 elapsed = now() - start;
340 /* Check that the timer expired after at least 1 ms. This check
341 * is to make sure that the timer re-started and that the event is
342 * not from the original add (and expiration) of the timer.
344 printf("timer expired after %ld us\n", elapsed);
345 if (elapsed < MS_TO_US(1))
346 errx(1, "early timer expiration: %ld us", elapsed);
348 /* Make sure the re-added timer does not fire. In other words,
349 * test that the event received above was the only event from the
350 * add and re-add of the timer.
359 test_update_periodic(void)
361 const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)";
371 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL);
372 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
373 err(1, "%s", test_id);
375 /* Retrieve the event */
376 kev.flags = EV_ADD | EV_CLEAR;
378 kevent_cmp(&kev, kevent_get(kqfd));
380 /* Check if the event occurs again */
382 kevent_cmp(&kev, kevent_get(kqfd));
384 /* Re-add with new timeout. */
385 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL);
387 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
388 err(1, "%s", test_id);
390 /* Retrieve the event */
391 kev.flags = EV_ADD | EV_CLEAR;
393 kevent_cmp(&kev, kevent_get(kqfd));
396 elapsed = stop - start;
398 /* Check that the timer expired after at least 2 ms.
400 printf("timer expired after %ld us\n", elapsed);
401 if (elapsed < MS_TO_US(2))
402 errx(1, "early timer expiration: %ld us", elapsed);
404 /* Delete the event */
405 kev.flags = EV_DELETE;
406 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
407 err(1, "%s", test_id);
413 test_update_timing(void)
415 #define MIN_SLEEP 500
416 #define MAX_SLEEP 1500
417 const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)";
429 /* Re-try the update tests with a variety of delays between the
430 * original timer activation and the update of the timer. The goal
431 * is to show that in all cases the only timer event that is
432 * received is from the update and not the original timer add.
434 for (sleeptime = MIN_SLEEP, iteration = 1;
435 sleeptime < MAX_SLEEP;
436 ++sleeptime, ++iteration) {
438 /* First set the timer to 1 ms */
439 EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
440 NOTE_USECONDS, MS_TO_US(1), NULL);
441 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
442 err(1, "%s", test_id);
444 /* Delay; the delay ranges from less than to greater than the
449 /* Now re-add the timer with the same parameters */
451 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
452 err(1, "%s", test_id);
454 /* Wait for the event */
455 kev.flags |= EV_CLEAR;
456 kev.fflags &= ~NOTE_USECONDS;
458 kevent_cmp(&kev, kevent_get(kqfd));
460 elapsed = stop - start;
462 /* Check that the timer expired after at least 1 ms. This
463 * check is to make sure that the timer re-started and that
464 * the event is not from the original add of the timer.
466 if (elapsed < MS_TO_US(1))
467 errx(1, "early timer expiration: %ld us", elapsed);
469 /* Make sure the re-added timer does not fire. In other words,
470 * test that the event received above was the only event from
471 * the add and re-add of the timer.
474 test_no_kevents_quietly();
484 test_kevent_timer_add();
485 test_kevent_timer_del();
486 test_kevent_timer_get();
491 test_update_expired();
492 test_update_timing();
493 test_update_periodic();
494 disable_and_enable();