160a396a4SRobert Watson /*
260a396a4SRobert Watson * Copyright (c) 2009 Mark Heily <mark@heily.com>
360a396a4SRobert Watson *
460a396a4SRobert Watson * Permission to use, copy, modify, and distribute this software for any
560a396a4SRobert Watson * purpose with or without fee is hereby granted, provided that the above
660a396a4SRobert Watson * copyright notice and this permission notice appear in all copies.
760a396a4SRobert Watson *
860a396a4SRobert Watson * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
960a396a4SRobert Watson * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1060a396a4SRobert Watson * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1160a396a4SRobert Watson * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1260a396a4SRobert Watson * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1360a396a4SRobert Watson * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1460a396a4SRobert Watson * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1560a396a4SRobert Watson */
1660a396a4SRobert Watson
1760a396a4SRobert Watson #include "common.h"
182b34e843SKonstantin Belousov #include <sys/time.h>
1960a396a4SRobert Watson
2095c05062SDavid Bright #define MILLION 1000000
2195c05062SDavid Bright #define THOUSAND 1000
2295c05062SDavid Bright #define SEC_TO_MS(t) ((t) * THOUSAND) /* Convert seconds to milliseconds. */
2395c05062SDavid Bright #define SEC_TO_US(t) ((t) * MILLION) /* Convert seconds to microseconds. */
2495c05062SDavid Bright #define MS_TO_US(t) ((t) * THOUSAND) /* Convert milliseconds to microseconds. */
2595c05062SDavid Bright #define US_TO_NS(t) ((t) * THOUSAND) /* Convert microseconds to nanoseconds. */
2695c05062SDavid Bright
2760a396a4SRobert Watson
2895c05062SDavid Bright /* Get the current time with microsecond precision. Used for
2995c05062SDavid Bright * sub-second timing to make some timer tests run faster.
3095c05062SDavid Bright */
310fbdc372SKyle Evans static uint64_t
now(void)3295c05062SDavid Bright now(void)
3395c05062SDavid Bright {
3495c05062SDavid Bright struct timeval tv;
3595c05062SDavid Bright
3695c05062SDavid Bright gettimeofday(&tv, NULL);
370fbdc372SKyle Evans /* Promote potentially 32-bit time_t to uint64_t before conversion. */
380fbdc372SKyle Evans return SEC_TO_US((uint64_t)tv.tv_sec) + tv.tv_usec;
3995c05062SDavid Bright }
4095c05062SDavid Bright
4195c05062SDavid Bright /* Sleep for a given number of milliseconds. The timeout is assumed to
4295c05062SDavid Bright * be less than 1 second.
4395c05062SDavid Bright */
44c9c283bdSAlex Richardson static void
mssleep(int t)4595c05062SDavid Bright mssleep(int t)
4695c05062SDavid Bright {
4795c05062SDavid Bright struct timespec stime = {
4895c05062SDavid Bright .tv_sec = 0,
4995c05062SDavid Bright .tv_nsec = US_TO_NS(MS_TO_US(t)),
5095c05062SDavid Bright };
5195c05062SDavid Bright
5295c05062SDavid Bright nanosleep(&stime, NULL);
5395c05062SDavid Bright }
5495c05062SDavid Bright
5595c05062SDavid Bright /* Sleep for a given number of microseconds. The timeout is assumed to
5695c05062SDavid Bright * be less than 1 second.
5795c05062SDavid Bright */
58c9c283bdSAlex Richardson static void
ussleep(int t)5995c05062SDavid Bright ussleep(int t)
6095c05062SDavid Bright {
6195c05062SDavid Bright struct timespec stime = {
6295c05062SDavid Bright .tv_sec = 0,
6395c05062SDavid Bright .tv_nsec = US_TO_NS(t),
6495c05062SDavid Bright };
6595c05062SDavid Bright
6695c05062SDavid Bright nanosleep(&stime, NULL);
6795c05062SDavid Bright }
6895c05062SDavid Bright
69c9c283bdSAlex Richardson static void
test_kevent_timer_add(void)7060a396a4SRobert Watson test_kevent_timer_add(void)
7160a396a4SRobert Watson {
7260a396a4SRobert Watson const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)";
7360a396a4SRobert Watson struct kevent kev;
7460a396a4SRobert Watson
7560a396a4SRobert Watson test_begin(test_id);
7660a396a4SRobert Watson
7760a396a4SRobert Watson EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
7860a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
7960a396a4SRobert Watson err(1, "%s", test_id);
8060a396a4SRobert Watson
8160a396a4SRobert Watson success();
8260a396a4SRobert Watson }
8360a396a4SRobert Watson
84c9c283bdSAlex Richardson static void
test_kevent_timer_del(void)8560a396a4SRobert Watson test_kevent_timer_del(void)
8660a396a4SRobert Watson {
8760a396a4SRobert Watson const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)";
8860a396a4SRobert Watson struct kevent kev;
8960a396a4SRobert Watson
9060a396a4SRobert Watson test_begin(test_id);
9160a396a4SRobert Watson
9260a396a4SRobert Watson EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
9360a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
9460a396a4SRobert Watson err(1, "%s", test_id);
9560a396a4SRobert Watson
9660a396a4SRobert Watson test_no_kevents();
9760a396a4SRobert Watson
9860a396a4SRobert Watson success();
9960a396a4SRobert Watson }
10060a396a4SRobert Watson
101c9c283bdSAlex Richardson static void
test_kevent_timer_get(void)10260a396a4SRobert Watson test_kevent_timer_get(void)
10360a396a4SRobert Watson {
10460a396a4SRobert Watson const char *test_id = "kevent(EVFILT_TIMER, wait)";
10560a396a4SRobert Watson struct kevent kev;
10660a396a4SRobert Watson
10760a396a4SRobert Watson test_begin(test_id);
10860a396a4SRobert Watson
10960a396a4SRobert Watson EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
11060a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
11160a396a4SRobert Watson err(1, "%s", test_id);
11260a396a4SRobert Watson
11360a396a4SRobert Watson kev.flags |= EV_CLEAR;
11460a396a4SRobert Watson kev.data = 1;
11560a396a4SRobert Watson kevent_cmp(&kev, kevent_get(kqfd));
11660a396a4SRobert Watson
11760a396a4SRobert Watson EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
11860a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
11960a396a4SRobert Watson err(1, "%s", test_id);
12060a396a4SRobert Watson
12160a396a4SRobert Watson success();
12260a396a4SRobert Watson }
12360a396a4SRobert Watson
12460a396a4SRobert Watson static void
test_oneshot(void)12560a396a4SRobert Watson test_oneshot(void)
12660a396a4SRobert Watson {
12760a396a4SRobert Watson const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)";
12860a396a4SRobert Watson struct kevent kev;
12960a396a4SRobert Watson
13060a396a4SRobert Watson test_begin(test_id);
13160a396a4SRobert Watson
13260a396a4SRobert Watson test_no_kevents();
13360a396a4SRobert Watson
13460a396a4SRobert Watson EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL);
13560a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
13660a396a4SRobert Watson err(1, "%s", test_id);
13760a396a4SRobert Watson
13860a396a4SRobert Watson /* Retrieve the event */
13960a396a4SRobert Watson kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
14060a396a4SRobert Watson kev.data = 1;
14160a396a4SRobert Watson kevent_cmp(&kev, kevent_get(kqfd));
14260a396a4SRobert Watson
14360a396a4SRobert Watson /* Check if the event occurs again */
14460a396a4SRobert Watson sleep(3);
14560a396a4SRobert Watson test_no_kevents();
14660a396a4SRobert Watson
14760a396a4SRobert Watson
14860a396a4SRobert Watson success();
14960a396a4SRobert Watson }
15060a396a4SRobert Watson
15160a396a4SRobert Watson static void
test_periodic(void)15260a396a4SRobert Watson test_periodic(void)
15360a396a4SRobert Watson {
15460a396a4SRobert Watson const char *test_id = "kevent(EVFILT_TIMER, periodic)";
15560a396a4SRobert Watson struct kevent kev;
15660a396a4SRobert Watson
15760a396a4SRobert Watson test_begin(test_id);
15860a396a4SRobert Watson
15960a396a4SRobert Watson test_no_kevents();
16060a396a4SRobert Watson
16160a396a4SRobert Watson EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL);
16260a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
16360a396a4SRobert Watson err(1, "%s", test_id);
16460a396a4SRobert Watson
16560a396a4SRobert Watson /* Retrieve the event */
16660a396a4SRobert Watson kev.flags = EV_ADD | EV_CLEAR;
16760a396a4SRobert Watson kev.data = 1;
16860a396a4SRobert Watson kevent_cmp(&kev, kevent_get(kqfd));
16960a396a4SRobert Watson
17060a396a4SRobert Watson /* Check if the event occurs again */
17160a396a4SRobert Watson sleep(1);
17260a396a4SRobert Watson kevent_cmp(&kev, kevent_get(kqfd));
17360a396a4SRobert Watson
17460a396a4SRobert Watson /* Delete the event */
17560a396a4SRobert Watson kev.flags = EV_DELETE;
17660a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
17760a396a4SRobert Watson err(1, "%s", test_id);
17860a396a4SRobert Watson
17960a396a4SRobert Watson success();
18060a396a4SRobert Watson }
18160a396a4SRobert Watson
18260a396a4SRobert Watson static void
test_periodic_modify(void)183d6d4f9b4SMark Johnston test_periodic_modify(void)
184d6d4f9b4SMark Johnston {
185d6d4f9b4SMark Johnston const char *test_id = "kevent(EVFILT_TIMER, periodic_modify)";
186d6d4f9b4SMark Johnston struct kevent kev;
187d6d4f9b4SMark Johnston
188d6d4f9b4SMark Johnston test_begin(test_id);
189d6d4f9b4SMark Johnston
190d6d4f9b4SMark Johnston test_no_kevents();
191d6d4f9b4SMark Johnston
192d6d4f9b4SMark Johnston EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
193d6d4f9b4SMark Johnston if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
194d6d4f9b4SMark Johnston err(1, "%s", test_id);
195d6d4f9b4SMark Johnston
196d6d4f9b4SMark Johnston /* Retrieve the event */
197d6d4f9b4SMark Johnston kev.flags = EV_ADD | EV_CLEAR;
198d6d4f9b4SMark Johnston kev.data = 1;
199d6d4f9b4SMark Johnston kevent_cmp(&kev, kevent_get(kqfd));
200d6d4f9b4SMark Johnston
201d6d4f9b4SMark Johnston /* Check if the event occurs again */
202994bec47SGleb Smirnoff EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 495, NULL);
203d6d4f9b4SMark Johnston if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
204d6d4f9b4SMark Johnston err(1, "%s", test_id);
205d6d4f9b4SMark Johnston
206d6d4f9b4SMark Johnston kev.flags = EV_ADD | EV_CLEAR;
207d6d4f9b4SMark Johnston sleep(1);
208d6d4f9b4SMark Johnston kev.data = 2; /* Should have fired twice */
209d6d4f9b4SMark Johnston
210d6d4f9b4SMark Johnston kevent_cmp(&kev, kevent_get(kqfd));
211d6d4f9b4SMark Johnston
212d6d4f9b4SMark Johnston /* Delete the event */
213d6d4f9b4SMark Johnston kev.flags = EV_DELETE;
214d6d4f9b4SMark Johnston if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
215d6d4f9b4SMark Johnston err(1, "%s", test_id);
216d6d4f9b4SMark Johnston
217d6d4f9b4SMark Johnston success();
218d6d4f9b4SMark Johnston }
219d6d4f9b4SMark Johnston
220d6d4f9b4SMark Johnston #if WITH_NATIVE_KQUEUE_BUGS
221d6d4f9b4SMark Johnston static void
test_periodic_to_oneshot(void)222d6d4f9b4SMark Johnston test_periodic_to_oneshot(void)
223d6d4f9b4SMark Johnston {
224d6d4f9b4SMark Johnston const char *test_id = "kevent(EVFILT_TIMER, period_to_oneshot)";
225d6d4f9b4SMark Johnston struct kevent kev;
226d6d4f9b4SMark Johnston
227d6d4f9b4SMark Johnston test_begin(test_id);
228d6d4f9b4SMark Johnston
229d6d4f9b4SMark Johnston test_no_kevents();
230d6d4f9b4SMark Johnston
231d6d4f9b4SMark Johnston EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
232d6d4f9b4SMark Johnston if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
233d6d4f9b4SMark Johnston err(1, "%s", test_id);
234d6d4f9b4SMark Johnston
235d6d4f9b4SMark Johnston /* Retrieve the event */
236d6d4f9b4SMark Johnston kev.flags = EV_ADD | EV_CLEAR;
237d6d4f9b4SMark Johnston kev.data = 1;
238d6d4f9b4SMark Johnston kevent_cmp(&kev, kevent_get(kqfd));
239d6d4f9b4SMark Johnston
240d6d4f9b4SMark Johnston /* Check if the event occurs again */
241d6d4f9b4SMark Johnston sleep(1);
242d6d4f9b4SMark Johnston kevent_cmp(&kev, kevent_get(kqfd));
243d6d4f9b4SMark Johnston
244d6d4f9b4SMark Johnston /* Switch to oneshot */
245d6d4f9b4SMark Johnston EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500, NULL);
246d6d4f9b4SMark Johnston if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
247d6d4f9b4SMark Johnston err(1, "%s", test_id);
248d6d4f9b4SMark Johnston kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
249d6d4f9b4SMark Johnston
250d6d4f9b4SMark Johnston sleep(1);
251d6d4f9b4SMark Johnston kev.data = 1; /* Should have fired once */
252d6d4f9b4SMark Johnston
253d6d4f9b4SMark Johnston kevent_cmp(&kev, kevent_get(kqfd));
254d6d4f9b4SMark Johnston
255d6d4f9b4SMark Johnston success();
256d6d4f9b4SMark Johnston }
257d6d4f9b4SMark Johnston #endif
258d6d4f9b4SMark Johnston
259d6d4f9b4SMark Johnston static void
test_disable_and_enable(void)260d6d4f9b4SMark Johnston test_disable_and_enable(void)
26160a396a4SRobert Watson {
26260a396a4SRobert Watson const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
26360a396a4SRobert Watson struct kevent kev;
26460a396a4SRobert Watson
26560a396a4SRobert Watson test_begin(test_id);
26660a396a4SRobert Watson
26760a396a4SRobert Watson test_no_kevents();
26860a396a4SRobert Watson
26960a396a4SRobert Watson /* Add the watch and immediately disable it */
27060a396a4SRobert Watson EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
27160a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
27260a396a4SRobert Watson err(1, "%s", test_id);
27360a396a4SRobert Watson kev.flags = EV_DISABLE;
27460a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
27560a396a4SRobert Watson err(1, "%s", test_id);
27660a396a4SRobert Watson test_no_kevents();
27760a396a4SRobert Watson
27860a396a4SRobert Watson /* Re-enable and check again */
27960a396a4SRobert Watson kev.flags = EV_ENABLE;
28060a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
28160a396a4SRobert Watson err(1, "%s", test_id);
28260a396a4SRobert Watson
28360a396a4SRobert Watson kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
28460a396a4SRobert Watson kev.data = 1;
28560a396a4SRobert Watson kevent_cmp(&kev, kevent_get(kqfd));
28660a396a4SRobert Watson
28760a396a4SRobert Watson success();
28860a396a4SRobert Watson }
28960a396a4SRobert Watson
2902b34e843SKonstantin Belousov static void
test_abstime(void)2912b34e843SKonstantin Belousov test_abstime(void)
2922b34e843SKonstantin Belousov {
2932b34e843SKonstantin Belousov const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)";
2942b34e843SKonstantin Belousov struct kevent kev;
2950fbdc372SKyle Evans uint64_t end, start, stop;
296c17dd0e8SKyle Evans const int timeout_sec = 3;
2972b34e843SKonstantin Belousov
2982b34e843SKonstantin Belousov test_begin(test_id);
2992b34e843SKonstantin Belousov
3002b34e843SKonstantin Belousov test_no_kevents();
3012b34e843SKonstantin Belousov
302c17dd0e8SKyle Evans start = now();
303c17dd0e8SKyle Evans end = start + SEC_TO_US(timeout_sec);
3042b34e843SKonstantin Belousov EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
305c17dd0e8SKyle Evans NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
3062b34e843SKonstantin Belousov if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
3072b34e843SKonstantin Belousov err(1, "%s", test_id);
3082b34e843SKonstantin Belousov
3092b34e843SKonstantin Belousov /* Retrieve the event */
3102b34e843SKonstantin Belousov kev.flags = EV_ADD | EV_ONESHOT;
3112b34e843SKonstantin Belousov kev.data = 1;
3122b34e843SKonstantin Belousov kev.fflags = 0;
3132b34e843SKonstantin Belousov kevent_cmp(&kev, kevent_get(kqfd));
3142b34e843SKonstantin Belousov
315c17dd0e8SKyle Evans stop = now();
316c17dd0e8SKyle Evans if (stop < end)
317c17dd0e8SKyle Evans err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
3182b34e843SKonstantin Belousov /* Check if the event occurs again */
3192b34e843SKonstantin Belousov sleep(3);
3202b34e843SKonstantin Belousov test_no_kevents();
3212b34e843SKonstantin Belousov
3222b34e843SKonstantin Belousov success();
3232b34e843SKonstantin Belousov }
3242b34e843SKonstantin Belousov
32595c05062SDavid Bright static void
test_abstime_epoch(void)3262f4dbe27SKyle Evans test_abstime_epoch(void)
3272f4dbe27SKyle Evans {
3282f4dbe27SKyle Evans const char *test_id = "kevent(EVFILT_TIMER (EPOCH), NOTE_ABSTIME)";
3292f4dbe27SKyle Evans struct kevent kev;
3302f4dbe27SKyle Evans
3312f4dbe27SKyle Evans test_begin(test_id);
3322f4dbe27SKyle Evans
3332f4dbe27SKyle Evans test_no_kevents();
3342f4dbe27SKyle Evans
3352f4dbe27SKyle Evans EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, NOTE_ABSTIME, 0,
3362f4dbe27SKyle Evans NULL);
3372f4dbe27SKyle Evans if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
3382f4dbe27SKyle Evans err(1, "%s", test_id);
3392f4dbe27SKyle Evans
3402f4dbe27SKyle Evans /* Retrieve the event */
3412f4dbe27SKyle Evans kev.flags = EV_ADD;
3422f4dbe27SKyle Evans kev.data = 1;
3432f4dbe27SKyle Evans kev.fflags = 0;
3442f4dbe27SKyle Evans kevent_cmp(&kev, kevent_get(kqfd));
3452f4dbe27SKyle Evans
3462f4dbe27SKyle Evans /* Delete the event */
3472f4dbe27SKyle Evans kev.flags = EV_DELETE;
3482f4dbe27SKyle Evans if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
3492f4dbe27SKyle Evans err(1, "%s", test_id);
3502f4dbe27SKyle Evans
3512f4dbe27SKyle Evans success();
3522f4dbe27SKyle Evans }
3532f4dbe27SKyle Evans
3542f4dbe27SKyle Evans static void
test_abstime_preboot(void)3559c999a25SKyle Evans test_abstime_preboot(void)
3569c999a25SKyle Evans {
3579c999a25SKyle Evans const char *test_id = "kevent(EVFILT_TIMER (PREBOOT), EV_ONESHOT, NOTE_ABSTIME)";
3589c999a25SKyle Evans struct kevent kev;
3599c999a25SKyle Evans struct timespec btp;
3609c999a25SKyle Evans uint64_t end, start, stop;
3619c999a25SKyle Evans
3629c999a25SKyle Evans test_begin(test_id);
3639c999a25SKyle Evans
3649c999a25SKyle Evans test_no_kevents();
3659c999a25SKyle Evans
3669c999a25SKyle Evans /*
3679c999a25SKyle Evans * We'll expire it at just before system boot (roughly) with the hope that
3689c999a25SKyle Evans * we'll get an ~immediate expiration, just as we do for any value specified
3699c999a25SKyle Evans * between system boot and now.
3709c999a25SKyle Evans */
3719c999a25SKyle Evans start = now();
3729c999a25SKyle Evans if (clock_gettime(CLOCK_BOOTTIME, &btp) != 0)
3739c999a25SKyle Evans err(1, "%s", test_id);
3749c999a25SKyle Evans
3759c999a25SKyle Evans end = start - SEC_TO_US(btp.tv_sec + 1);
3769c999a25SKyle Evans EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
3779c999a25SKyle Evans NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
3789c999a25SKyle Evans if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
3799c999a25SKyle Evans err(1, "%s", test_id);
3809c999a25SKyle Evans
3819c999a25SKyle Evans /* Retrieve the event */
3829c999a25SKyle Evans kev.flags = EV_ADD | EV_ONESHOT;
3839c999a25SKyle Evans kev.data = 1;
3849c999a25SKyle Evans kev.fflags = 0;
3859c999a25SKyle Evans kevent_cmp(&kev, kevent_get(kqfd));
3869c999a25SKyle Evans
3879c999a25SKyle Evans stop = now();
3889c999a25SKyle Evans if (stop < end)
3899c999a25SKyle Evans err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
3909c999a25SKyle Evans /* Check if the event occurs again */
3919c999a25SKyle Evans sleep(3);
3929c999a25SKyle Evans test_no_kevents();
3939c999a25SKyle Evans
3949c999a25SKyle Evans success();
3959c999a25SKyle Evans }
3969c999a25SKyle Evans
3979c999a25SKyle Evans static void
test_abstime_postboot(void)3989c999a25SKyle Evans test_abstime_postboot(void)
3999c999a25SKyle Evans {
4009c999a25SKyle Evans const char *test_id = "kevent(EVFILT_TIMER (POSTBOOT), EV_ONESHOT, NOTE_ABSTIME)";
4019c999a25SKyle Evans struct kevent kev;
4029c999a25SKyle Evans uint64_t end, start, stop;
4039c999a25SKyle Evans const int timeout_sec = 1;
4049c999a25SKyle Evans
4059c999a25SKyle Evans test_begin(test_id);
4069c999a25SKyle Evans
4079c999a25SKyle Evans test_no_kevents();
4089c999a25SKyle Evans
4099c999a25SKyle Evans /*
4109c999a25SKyle Evans * Set a timer for 1 second ago, it should fire immediately rather than
4119c999a25SKyle Evans * being rejected.
4129c999a25SKyle Evans */
4139c999a25SKyle Evans start = now();
4149c999a25SKyle Evans end = start - SEC_TO_US(timeout_sec);
4159c999a25SKyle Evans EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
4169c999a25SKyle Evans NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
4179c999a25SKyle Evans if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
4189c999a25SKyle Evans err(1, "%s", test_id);
4199c999a25SKyle Evans
4209c999a25SKyle Evans /* Retrieve the event */
4219c999a25SKyle Evans kev.flags = EV_ADD | EV_ONESHOT;
4229c999a25SKyle Evans kev.data = 1;
4239c999a25SKyle Evans kev.fflags = 0;
4249c999a25SKyle Evans kevent_cmp(&kev, kevent_get(kqfd));
4259c999a25SKyle Evans
4269c999a25SKyle Evans stop = now();
4279c999a25SKyle Evans if (stop < end)
4289c999a25SKyle Evans err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
4299c999a25SKyle Evans /* Check if the event occurs again */
4309c999a25SKyle Evans sleep(3);
4319c999a25SKyle Evans test_no_kevents();
4329c999a25SKyle Evans
4339c999a25SKyle Evans success();
4349c999a25SKyle Evans }
4359c999a25SKyle Evans
4369c999a25SKyle Evans static void
test_update(void)43795c05062SDavid Bright test_update(void)
43895c05062SDavid Bright {
43995c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)";
44095c05062SDavid Bright struct kevent kev;
44195c05062SDavid Bright long elapsed;
4420fbdc372SKyle Evans uint64_t start;
44395c05062SDavid Bright
44495c05062SDavid Bright test_begin(test_id);
44595c05062SDavid Bright
44695c05062SDavid Bright test_no_kevents();
44795c05062SDavid Bright
44895c05062SDavid Bright /* First set the timer to 1 second */
44995c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
45095c05062SDavid Bright NOTE_USECONDS, SEC_TO_US(1), (void *)1);
45195c05062SDavid Bright start = now();
45295c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
45395c05062SDavid Bright err(1, "%s", test_id);
45495c05062SDavid Bright
45595c05062SDavid Bright /* Now reduce the timer to 1 ms */
45695c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
45795c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), (void *)2);
45895c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
45995c05062SDavid Bright err(1, "%s", test_id);
46095c05062SDavid Bright
46195c05062SDavid Bright /* Wait for the event */
46295c05062SDavid Bright kev.flags |= EV_CLEAR;
46395c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS;
46495c05062SDavid Bright kev.data = 1;
46595c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd));
46695c05062SDavid Bright elapsed = now() - start;
46795c05062SDavid Bright
46895c05062SDavid Bright /* Check that the timer expired after at least 1 ms, but less than
46995c05062SDavid Bright * 1 second. This check is to make sure that the original 1 second
47095c05062SDavid Bright * timeout was not used.
47195c05062SDavid Bright */
47295c05062SDavid Bright printf("timer expired after %ld us\n", elapsed);
47395c05062SDavid Bright if (elapsed < MS_TO_US(1))
47495c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed);
47595c05062SDavid Bright if (elapsed > SEC_TO_US(1))
47695c05062SDavid Bright errx(1, "late timer expiration: %ld us", elapsed);
47795c05062SDavid Bright
47895c05062SDavid Bright success();
47995c05062SDavid Bright }
48095c05062SDavid Bright
48195c05062SDavid Bright static void
test_update_equal(void)48295c05062SDavid Bright test_update_equal(void)
48395c05062SDavid Bright {
48495c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)";
48595c05062SDavid Bright struct kevent kev;
48695c05062SDavid Bright long elapsed;
4870fbdc372SKyle Evans uint64_t start;
48895c05062SDavid Bright
48995c05062SDavid Bright test_begin(test_id);
49095c05062SDavid Bright
49195c05062SDavid Bright test_no_kevents();
49295c05062SDavid Bright
49395c05062SDavid Bright /* First set the timer to 1 ms */
49495c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
49595c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), NULL);
49695c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
49795c05062SDavid Bright err(1, "%s", test_id);
49895c05062SDavid Bright
49995c05062SDavid Bright /* Sleep for a significant fraction of the timeout. */
50095c05062SDavid Bright ussleep(600);
50195c05062SDavid Bright
50295c05062SDavid Bright /* Now re-add the timer with the same parameters */
50395c05062SDavid Bright start = now();
50495c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
50595c05062SDavid Bright err(1, "%s", test_id);
50695c05062SDavid Bright
50795c05062SDavid Bright /* Wait for the event */
50895c05062SDavid Bright kev.flags |= EV_CLEAR;
50995c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS;
51095c05062SDavid Bright kev.data = 1;
51195c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd));
51295c05062SDavid Bright elapsed = now() - start;
51395c05062SDavid Bright
51495c05062SDavid Bright /* Check that the timer expired after at least 1 ms. This check is
51595c05062SDavid Bright * to make sure that the timer re-started and that the event is
51695c05062SDavid Bright * not from the original add of the timer.
51795c05062SDavid Bright */
51895c05062SDavid Bright printf("timer expired after %ld us\n", elapsed);
51995c05062SDavid Bright if (elapsed < MS_TO_US(1))
52095c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed);
52195c05062SDavid Bright
52295c05062SDavid Bright success();
52395c05062SDavid Bright }
52495c05062SDavid Bright
52595c05062SDavid Bright static void
test_update_expired(void)52695c05062SDavid Bright test_update_expired(void)
52795c05062SDavid Bright {
52895c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)";
52995c05062SDavid Bright struct kevent kev;
53095c05062SDavid Bright long elapsed;
5310fbdc372SKyle Evans uint64_t start;
53295c05062SDavid Bright
53395c05062SDavid Bright test_begin(test_id);
53495c05062SDavid Bright
53595c05062SDavid Bright test_no_kevents();
53695c05062SDavid Bright
53795c05062SDavid Bright /* Set the timer to 1ms */
53895c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
53995c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), NULL);
54095c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
54195c05062SDavid Bright err(1, "%s", test_id);
54295c05062SDavid Bright
54395c05062SDavid Bright /* Wait for 2 ms to give the timer plenty of time to expire. */
54495c05062SDavid Bright mssleep(2);
54595c05062SDavid Bright
54695c05062SDavid Bright /* Now re-add the timer */
54795c05062SDavid Bright start = now();
54895c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
54995c05062SDavid Bright err(1, "%s", test_id);
55095c05062SDavid Bright
55195c05062SDavid Bright /* Wait for the event */
55295c05062SDavid Bright kev.flags |= EV_CLEAR;
55395c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS;
55495c05062SDavid Bright kev.data = 1;
55595c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd));
55695c05062SDavid Bright elapsed = now() - start;
55795c05062SDavid Bright
55895c05062SDavid Bright /* Check that the timer expired after at least 1 ms. This check
55995c05062SDavid Bright * is to make sure that the timer re-started and that the event is
56095c05062SDavid Bright * not from the original add (and expiration) of the timer.
56195c05062SDavid Bright */
56295c05062SDavid Bright printf("timer expired after %ld us\n", elapsed);
56395c05062SDavid Bright if (elapsed < MS_TO_US(1))
56495c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed);
56595c05062SDavid Bright
56695c05062SDavid Bright /* Make sure the re-added timer does not fire. In other words,
56795c05062SDavid Bright * test that the event received above was the only event from the
56895c05062SDavid Bright * add and re-add of the timer.
56995c05062SDavid Bright */
57095c05062SDavid Bright mssleep(2);
57195c05062SDavid Bright test_no_kevents();
57295c05062SDavid Bright
57395c05062SDavid Bright success();
57495c05062SDavid Bright }
57595c05062SDavid Bright
57695c05062SDavid Bright static void
test_update_periodic(void)57795c05062SDavid Bright test_update_periodic(void)
57895c05062SDavid Bright {
57995c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)";
58095c05062SDavid Bright struct kevent kev;
58195c05062SDavid Bright long elapsed;
5820fbdc372SKyle Evans uint64_t start, stop;
58395c05062SDavid Bright
58495c05062SDavid Bright test_begin(test_id);
58595c05062SDavid Bright
58695c05062SDavid Bright test_no_kevents();
58795c05062SDavid Bright
58895c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL);
58995c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
59095c05062SDavid Bright err(1, "%s", test_id);
59195c05062SDavid Bright
59295c05062SDavid Bright /* Retrieve the event */
59395c05062SDavid Bright kev.flags = EV_ADD | EV_CLEAR;
59495c05062SDavid Bright kev.data = 1;
59595c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd));
59695c05062SDavid Bright
59795c05062SDavid Bright /* Check if the event occurs again */
59895c05062SDavid Bright sleep(1);
59995c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd));
60095c05062SDavid Bright
60195c05062SDavid Bright /* Re-add with new timeout. */
60295c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL);
60395c05062SDavid Bright start = now();
60495c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
60595c05062SDavid Bright err(1, "%s", test_id);
60695c05062SDavid Bright
60795c05062SDavid Bright /* Retrieve the event */
60895c05062SDavid Bright kev.flags = EV_ADD | EV_CLEAR;
60995c05062SDavid Bright kev.data = 1;
61095c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd));
61195c05062SDavid Bright
61295c05062SDavid Bright stop = now();
61395c05062SDavid Bright elapsed = stop - start;
61495c05062SDavid Bright
61595c05062SDavid Bright /* Check that the timer expired after at least 2 ms.
61695c05062SDavid Bright */
61795c05062SDavid Bright printf("timer expired after %ld us\n", elapsed);
61895c05062SDavid Bright if (elapsed < MS_TO_US(2))
61995c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed);
62095c05062SDavid Bright
62195c05062SDavid Bright /* Delete the event */
62295c05062SDavid Bright kev.flags = EV_DELETE;
62395c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
62495c05062SDavid Bright err(1, "%s", test_id);
62595c05062SDavid Bright
62695c05062SDavid Bright success();
62795c05062SDavid Bright }
62895c05062SDavid Bright
62995c05062SDavid Bright static void
test_update_timing(void)63095c05062SDavid Bright test_update_timing(void)
63195c05062SDavid Bright {
63295c05062SDavid Bright #define MIN_SLEEP 500
63395c05062SDavid Bright #define MAX_SLEEP 1500
63495c05062SDavid Bright const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)";
63595c05062SDavid Bright struct kevent kev;
63695c05062SDavid Bright int iteration;
63795c05062SDavid Bright int sleeptime;
63895c05062SDavid Bright long elapsed;
6390fbdc372SKyle Evans uint64_t start, stop;
64095c05062SDavid Bright
64195c05062SDavid Bright test_begin(test_id);
64295c05062SDavid Bright
64395c05062SDavid Bright test_no_kevents();
64495c05062SDavid Bright
64595c05062SDavid Bright /* Re-try the update tests with a variety of delays between the
64695c05062SDavid Bright * original timer activation and the update of the timer. The goal
64795c05062SDavid Bright * is to show that in all cases the only timer event that is
64895c05062SDavid Bright * received is from the update and not the original timer add.
64995c05062SDavid Bright */
65095c05062SDavid Bright for (sleeptime = MIN_SLEEP, iteration = 1;
65195c05062SDavid Bright sleeptime < MAX_SLEEP;
65295c05062SDavid Bright ++sleeptime, ++iteration) {
65395c05062SDavid Bright
65495c05062SDavid Bright /* First set the timer to 1 ms */
65595c05062SDavid Bright EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
65695c05062SDavid Bright NOTE_USECONDS, MS_TO_US(1), NULL);
65795c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
65895c05062SDavid Bright err(1, "%s", test_id);
65995c05062SDavid Bright
66095c05062SDavid Bright /* Delay; the delay ranges from less than to greater than the
66195c05062SDavid Bright * timer period.
66295c05062SDavid Bright */
66395c05062SDavid Bright ussleep(sleeptime);
66495c05062SDavid Bright
66595c05062SDavid Bright /* Now re-add the timer with the same parameters */
66695c05062SDavid Bright start = now();
66795c05062SDavid Bright if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
66895c05062SDavid Bright err(1, "%s", test_id);
66995c05062SDavid Bright
67095c05062SDavid Bright /* Wait for the event */
67195c05062SDavid Bright kev.flags |= EV_CLEAR;
67295c05062SDavid Bright kev.fflags &= ~NOTE_USECONDS;
67395c05062SDavid Bright kev.data = 1;
67495c05062SDavid Bright kevent_cmp(&kev, kevent_get(kqfd));
67595c05062SDavid Bright stop = now();
67695c05062SDavid Bright elapsed = stop - start;
67795c05062SDavid Bright
67895c05062SDavid Bright /* Check that the timer expired after at least 1 ms. This
67995c05062SDavid Bright * check is to make sure that the timer re-started and that
68095c05062SDavid Bright * the event is not from the original add of the timer.
68195c05062SDavid Bright */
68295c05062SDavid Bright if (elapsed < MS_TO_US(1))
68395c05062SDavid Bright errx(1, "early timer expiration: %ld us", elapsed);
68495c05062SDavid Bright
68595c05062SDavid Bright /* Make sure the re-added timer does not fire. In other words,
68695c05062SDavid Bright * test that the event received above was the only event from
68795c05062SDavid Bright * the add and re-add of the timer.
68895c05062SDavid Bright */
68995c05062SDavid Bright mssleep(2);
69095c05062SDavid Bright test_no_kevents_quietly();
69195c05062SDavid Bright }
69295c05062SDavid Bright
69395c05062SDavid Bright success();
69495c05062SDavid Bright }
69595c05062SDavid Bright
696d6d4f9b4SMark Johnston static void
test_dispatch(void)697d6d4f9b4SMark Johnston test_dispatch(void)
698d6d4f9b4SMark Johnston {
699d6d4f9b4SMark Johnston const char *test_id = "kevent(EVFILT_TIMER, EV_ADD | EV_DISPATCH)";
700d6d4f9b4SMark Johnston struct kevent kev;
701d6d4f9b4SMark Johnston
702d6d4f9b4SMark Johnston test_no_kevents();
703d6d4f9b4SMark Johnston
704d6d4f9b4SMark Johnston EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_DISPATCH, 0, 200, NULL);
705d6d4f9b4SMark Johnston if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
706d6d4f9b4SMark Johnston err(1, "%s", test_id);
707d6d4f9b4SMark Johnston
708d6d4f9b4SMark Johnston /* Get one event */
709d6d4f9b4SMark Johnston kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
710d6d4f9b4SMark Johnston kev.data = 1;
711d6d4f9b4SMark Johnston kevent_cmp(&kev, kevent_get(kqfd));
712d6d4f9b4SMark Johnston
713d6d4f9b4SMark Johnston /* Confirm that the knote is disabled due to EV_DISPATCH */
714d6d4f9b4SMark Johnston usleep(500000);
715d6d4f9b4SMark Johnston test_no_kevents();
716d6d4f9b4SMark Johnston
717d6d4f9b4SMark Johnston /* Enable the knote and make sure no events are pending */
718d6d4f9b4SMark Johnston EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_DISPATCH, 0, 200, NULL);
719d6d4f9b4SMark Johnston if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
720d6d4f9b4SMark Johnston err(1, "%s", test_id);
721d6d4f9b4SMark Johnston test_no_kevents();
722d6d4f9b4SMark Johnston
723d6d4f9b4SMark Johnston /* Get the next event */
724d6d4f9b4SMark Johnston usleep(1100000); /* 1100 ms */
725d6d4f9b4SMark Johnston kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
726d6d4f9b4SMark Johnston kev.data = 5;
727d6d4f9b4SMark Johnston kevent_cmp(&kev, kevent_get(kqfd));
728d6d4f9b4SMark Johnston
729d6d4f9b4SMark Johnston /* Remove the knote and ensure the event no longer fires */
730d6d4f9b4SMark Johnston EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
731d6d4f9b4SMark Johnston if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
732d6d4f9b4SMark Johnston err(1, "%s", test_id);
733d6d4f9b4SMark Johnston usleep(500000); /* 500ms */
734d6d4f9b4SMark Johnston test_no_kevents();
735d6d4f9b4SMark Johnston
736d6d4f9b4SMark Johnston success();
737d6d4f9b4SMark Johnston }
738d6d4f9b4SMark Johnston
73960a396a4SRobert Watson void
test_evfilt_timer(void)740c9c283bdSAlex Richardson test_evfilt_timer(void)
74160a396a4SRobert Watson {
74260a396a4SRobert Watson kqfd = kqueue();
74360a396a4SRobert Watson test_kevent_timer_add();
74460a396a4SRobert Watson test_kevent_timer_del();
74560a396a4SRobert Watson test_kevent_timer_get();
74660a396a4SRobert Watson test_oneshot();
74760a396a4SRobert Watson test_periodic();
748d6d4f9b4SMark Johnston test_periodic_modify();
749d6d4f9b4SMark Johnston #if WITH_NATIVE_KQUEUE_BUGS
750d6d4f9b4SMark Johnston test_periodic_to_oneshot();
751d6d4f9b4SMark Johnston #endif
7522b34e843SKonstantin Belousov test_abstime();
7532f4dbe27SKyle Evans test_abstime_epoch();
7549c999a25SKyle Evans test_abstime_preboot();
7559c999a25SKyle Evans test_abstime_postboot();
75695c05062SDavid Bright test_update();
75795c05062SDavid Bright test_update_equal();
75895c05062SDavid Bright test_update_expired();
75995c05062SDavid Bright test_update_timing();
76095c05062SDavid Bright test_update_periodic();
761d6d4f9b4SMark Johnston test_disable_and_enable();
762d6d4f9b4SMark Johnston test_dispatch();
76360a396a4SRobert Watson close(kqfd);
76460a396a4SRobert Watson }
765