xref: /freebsd/tests/sys/kqueue/libkqueue/timer.c (revision 9c999a259f00b35f0467acd351fea9157ed7e1e4)
1cb5fe245SEnji Cooper /*
2cb5fe245SEnji Cooper  * Copyright (c) 2009 Mark Heily <mark@heily.com>
3cb5fe245SEnji Cooper  *
4cb5fe245SEnji Cooper  * Permission to use, copy, modify, and distribute this software for any
5cb5fe245SEnji Cooper  * purpose with or without fee is hereby granted, provided that the above
6cb5fe245SEnji Cooper  * copyright notice and this permission notice appear in all copies.
7cb5fe245SEnji Cooper  *
8cb5fe245SEnji Cooper  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9cb5fe245SEnji Cooper  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10cb5fe245SEnji Cooper  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11cb5fe245SEnji Cooper  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12cb5fe245SEnji Cooper  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13cb5fe245SEnji Cooper  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14cb5fe245SEnji Cooper  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15cb5fe245SEnji Cooper  *
16cb5fe245SEnji Cooper  * $FreeBSD$
17cb5fe245SEnji Cooper  */
18cb5fe245SEnji Cooper 
19cb5fe245SEnji Cooper #include "common.h"
202b34e843SKonstantin Belousov #include <sys/time.h>
21cb5fe245SEnji Cooper 
2295c05062SDavid Bright #define	MILLION 1000000
2395c05062SDavid Bright #define	THOUSAND 1000
2495c05062SDavid Bright #define	SEC_TO_MS(t) ((t) * THOUSAND)	/* Convert seconds to milliseconds. */
2595c05062SDavid Bright #define	SEC_TO_US(t) ((t) * MILLION)	/* Convert seconds to microseconds. */
2695c05062SDavid Bright #define	MS_TO_US(t)  ((t) * THOUSAND)	/* Convert milliseconds to microseconds. */
2795c05062SDavid Bright #define	US_TO_NS(t)  ((t) * THOUSAND)	/* Convert microseconds to nanoseconds. */
2895c05062SDavid Bright 
29cb5fe245SEnji Cooper 
3095c05062SDavid Bright /* Get the current time with microsecond precision. Used for
3195c05062SDavid Bright  * sub-second timing to make some timer tests run faster.
3295c05062SDavid Bright  */
330fbdc372SKyle Evans static uint64_t
3495c05062SDavid Bright now(void)
3595c05062SDavid Bright {
3695c05062SDavid Bright     struct timeval tv;
3795c05062SDavid Bright 
3895c05062SDavid Bright     gettimeofday(&tv, NULL);
390fbdc372SKyle Evans     /* Promote potentially 32-bit time_t to uint64_t before conversion. */
400fbdc372SKyle Evans     return SEC_TO_US((uint64_t)tv.tv_sec) + tv.tv_usec;
4195c05062SDavid Bright }
4295c05062SDavid Bright 
4395c05062SDavid Bright /* Sleep for a given number of milliseconds. The timeout is assumed to
4495c05062SDavid Bright  * be less than 1 second.
4595c05062SDavid Bright  */
46c9c283bdSAlex Richardson static void
4795c05062SDavid Bright mssleep(int t)
4895c05062SDavid Bright {
4995c05062SDavid Bright     struct timespec stime = {
5095c05062SDavid Bright         .tv_sec = 0,
5195c05062SDavid Bright         .tv_nsec = US_TO_NS(MS_TO_US(t)),
5295c05062SDavid Bright     };
5395c05062SDavid Bright 
5495c05062SDavid Bright     nanosleep(&stime, NULL);
5595c05062SDavid Bright }
5695c05062SDavid Bright 
5795c05062SDavid Bright /* Sleep for a given number of microseconds. The timeout is assumed to
5895c05062SDavid Bright  * be less than 1 second.
5995c05062SDavid Bright  */
60c9c283bdSAlex Richardson static void
6195c05062SDavid Bright ussleep(int t)
6295c05062SDavid Bright {
6395c05062SDavid Bright     struct timespec stime = {
6495c05062SDavid Bright         .tv_sec = 0,
6595c05062SDavid Bright         .tv_nsec = US_TO_NS(t),
6695c05062SDavid Bright     };
6795c05062SDavid Bright 
6895c05062SDavid Bright     nanosleep(&stime, NULL);
6995c05062SDavid Bright }
7095c05062SDavid Bright 
71c9c283bdSAlex Richardson static void
72cb5fe245SEnji Cooper test_kevent_timer_add(void)
73cb5fe245SEnji Cooper {
74cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)";
75cb5fe245SEnji Cooper     struct kevent kev;
76cb5fe245SEnji Cooper 
77cb5fe245SEnji Cooper     test_begin(test_id);
78cb5fe245SEnji Cooper 
79cb5fe245SEnji Cooper     EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
80cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
81cb5fe245SEnji Cooper         err(1, "%s", test_id);
82cb5fe245SEnji Cooper 
83cb5fe245SEnji Cooper     success();
84cb5fe245SEnji Cooper }
85cb5fe245SEnji Cooper 
86c9c283bdSAlex Richardson static void
87cb5fe245SEnji Cooper test_kevent_timer_del(void)
88cb5fe245SEnji Cooper {
89cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)";
90cb5fe245SEnji Cooper     struct kevent kev;
91cb5fe245SEnji Cooper 
92cb5fe245SEnji Cooper     test_begin(test_id);
93cb5fe245SEnji Cooper 
94cb5fe245SEnji Cooper     EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
95cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
96cb5fe245SEnji Cooper         err(1, "%s", test_id);
97cb5fe245SEnji Cooper 
98cb5fe245SEnji Cooper     test_no_kevents();
99cb5fe245SEnji Cooper 
100cb5fe245SEnji Cooper     success();
101cb5fe245SEnji Cooper }
102cb5fe245SEnji Cooper 
103c9c283bdSAlex Richardson static void
104cb5fe245SEnji Cooper test_kevent_timer_get(void)
105cb5fe245SEnji Cooper {
106cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, wait)";
107cb5fe245SEnji Cooper     struct kevent kev;
108cb5fe245SEnji Cooper 
109cb5fe245SEnji Cooper     test_begin(test_id);
110cb5fe245SEnji Cooper 
111cb5fe245SEnji Cooper     EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
112cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
113cb5fe245SEnji Cooper         err(1, "%s", test_id);
114cb5fe245SEnji Cooper 
115cb5fe245SEnji Cooper     kev.flags |= EV_CLEAR;
116cb5fe245SEnji Cooper     kev.data = 1;
117cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
118cb5fe245SEnji Cooper 
119cb5fe245SEnji Cooper     EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
120cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
121cb5fe245SEnji Cooper         err(1, "%s", test_id);
122cb5fe245SEnji Cooper 
123cb5fe245SEnji Cooper     success();
124cb5fe245SEnji Cooper }
125cb5fe245SEnji Cooper 
126cb5fe245SEnji Cooper static void
127cb5fe245SEnji Cooper test_oneshot(void)
128cb5fe245SEnji Cooper {
129cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)";
130cb5fe245SEnji Cooper     struct kevent kev;
131cb5fe245SEnji Cooper 
132cb5fe245SEnji Cooper     test_begin(test_id);
133cb5fe245SEnji Cooper 
134cb5fe245SEnji Cooper     test_no_kevents();
135cb5fe245SEnji Cooper 
136cb5fe245SEnji Cooper     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL);
137cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
138cb5fe245SEnji Cooper         err(1, "%s", test_id);
139cb5fe245SEnji Cooper 
140cb5fe245SEnji Cooper     /* Retrieve the event */
141cb5fe245SEnji Cooper     kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
142cb5fe245SEnji Cooper     kev.data = 1;
143cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
144cb5fe245SEnji Cooper 
145cb5fe245SEnji Cooper     /* Check if the event occurs again */
146cb5fe245SEnji Cooper     sleep(3);
147cb5fe245SEnji Cooper     test_no_kevents();
148cb5fe245SEnji Cooper 
149cb5fe245SEnji Cooper 
150cb5fe245SEnji Cooper     success();
151cb5fe245SEnji Cooper }
152cb5fe245SEnji Cooper 
153cb5fe245SEnji Cooper static void
154cb5fe245SEnji Cooper test_periodic(void)
155cb5fe245SEnji Cooper {
156cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, periodic)";
157cb5fe245SEnji Cooper     struct kevent kev;
158cb5fe245SEnji Cooper 
159cb5fe245SEnji Cooper     test_begin(test_id);
160cb5fe245SEnji Cooper 
161cb5fe245SEnji Cooper     test_no_kevents();
162cb5fe245SEnji Cooper 
163cb5fe245SEnji Cooper     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL);
164cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
165cb5fe245SEnji Cooper         err(1, "%s", test_id);
166cb5fe245SEnji Cooper 
167cb5fe245SEnji Cooper     /* Retrieve the event */
168cb5fe245SEnji Cooper     kev.flags = EV_ADD | EV_CLEAR;
169cb5fe245SEnji Cooper     kev.data = 1;
170cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
171cb5fe245SEnji Cooper 
172cb5fe245SEnji Cooper     /* Check if the event occurs again */
173cb5fe245SEnji Cooper     sleep(1);
174cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
175cb5fe245SEnji Cooper 
176cb5fe245SEnji Cooper     /* Delete the event */
177cb5fe245SEnji Cooper     kev.flags = EV_DELETE;
178cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
179cb5fe245SEnji Cooper         err(1, "%s", test_id);
180cb5fe245SEnji Cooper 
181cb5fe245SEnji Cooper     success();
182cb5fe245SEnji Cooper }
183cb5fe245SEnji Cooper 
184cb5fe245SEnji Cooper static void
185cb5fe245SEnji Cooper disable_and_enable(void)
186cb5fe245SEnji Cooper {
187cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
188cb5fe245SEnji Cooper     struct kevent kev;
189cb5fe245SEnji Cooper 
190cb5fe245SEnji Cooper     test_begin(test_id);
191cb5fe245SEnji Cooper 
192cb5fe245SEnji Cooper     test_no_kevents();
193cb5fe245SEnji Cooper 
194cb5fe245SEnji Cooper     /* Add the watch and immediately disable it */
195cb5fe245SEnji Cooper     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
196cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
197cb5fe245SEnji Cooper         err(1, "%s", test_id);
198cb5fe245SEnji Cooper     kev.flags = EV_DISABLE;
199cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
200cb5fe245SEnji Cooper         err(1, "%s", test_id);
201cb5fe245SEnji Cooper     test_no_kevents();
202cb5fe245SEnji Cooper 
203cb5fe245SEnji Cooper     /* Re-enable and check again */
204cb5fe245SEnji Cooper     kev.flags = EV_ENABLE;
205cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
206cb5fe245SEnji Cooper         err(1, "%s", test_id);
207cb5fe245SEnji Cooper 
208cb5fe245SEnji Cooper     kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
209cb5fe245SEnji Cooper     kev.data = 1;
210cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
211cb5fe245SEnji Cooper 
212cb5fe245SEnji Cooper     success();
213cb5fe245SEnji Cooper }
214cb5fe245SEnji Cooper 
2152b34e843SKonstantin Belousov static void
2162b34e843SKonstantin Belousov test_abstime(void)
2172b34e843SKonstantin Belousov {
2182b34e843SKonstantin Belousov     const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)";
2192b34e843SKonstantin Belousov     struct kevent kev;
2200fbdc372SKyle Evans     uint64_t end, start, stop;
221c17dd0e8SKyle Evans     const int timeout_sec = 3;
2222b34e843SKonstantin Belousov 
2232b34e843SKonstantin Belousov     test_begin(test_id);
2242b34e843SKonstantin Belousov 
2252b34e843SKonstantin Belousov     test_no_kevents();
2262b34e843SKonstantin Belousov 
227c17dd0e8SKyle Evans     start = now();
228c17dd0e8SKyle Evans     end = start + SEC_TO_US(timeout_sec);
2292b34e843SKonstantin Belousov     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
230c17dd0e8SKyle Evans       NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
2312b34e843SKonstantin Belousov     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
2322b34e843SKonstantin Belousov         err(1, "%s", test_id);
2332b34e843SKonstantin Belousov 
2342b34e843SKonstantin Belousov     /* Retrieve the event */
2352b34e843SKonstantin Belousov     kev.flags = EV_ADD | EV_ONESHOT;
2362b34e843SKonstantin Belousov     kev.data = 1;
2372b34e843SKonstantin Belousov     kev.fflags = 0;
2382b34e843SKonstantin Belousov     kevent_cmp(&kev, kevent_get(kqfd));
2392b34e843SKonstantin Belousov 
240c17dd0e8SKyle Evans     stop = now();
241c17dd0e8SKyle Evans     if (stop < end)
242c17dd0e8SKyle Evans         err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
2432b34e843SKonstantin Belousov     /* Check if the event occurs again */
2442b34e843SKonstantin Belousov     sleep(3);
2452b34e843SKonstantin Belousov     test_no_kevents();
2462b34e843SKonstantin Belousov 
2472b34e843SKonstantin Belousov     success();
2482b34e843SKonstantin Belousov }
2492b34e843SKonstantin Belousov 
25095c05062SDavid Bright static void
251*9c999a25SKyle Evans test_abstime_preboot(void)
252*9c999a25SKyle Evans {
253*9c999a25SKyle Evans     const char *test_id = "kevent(EVFILT_TIMER (PREBOOT), EV_ONESHOT, NOTE_ABSTIME)";
254*9c999a25SKyle Evans     struct kevent kev;
255*9c999a25SKyle Evans     struct timespec btp;
256*9c999a25SKyle Evans     uint64_t end, start, stop;
257*9c999a25SKyle Evans 
258*9c999a25SKyle Evans     test_begin(test_id);
259*9c999a25SKyle Evans 
260*9c999a25SKyle Evans     test_no_kevents();
261*9c999a25SKyle Evans 
262*9c999a25SKyle Evans     /*
263*9c999a25SKyle Evans      * We'll expire it at just before system boot (roughly) with the hope that
264*9c999a25SKyle Evans      * we'll get an ~immediate expiration, just as we do for any value specified
265*9c999a25SKyle Evans      * between system boot and now.
266*9c999a25SKyle Evans      */
267*9c999a25SKyle Evans     start = now();
268*9c999a25SKyle Evans     if (clock_gettime(CLOCK_BOOTTIME, &btp) != 0)
269*9c999a25SKyle Evans       err(1, "%s", test_id);
270*9c999a25SKyle Evans 
271*9c999a25SKyle Evans     end = start - SEC_TO_US(btp.tv_sec + 1);
272*9c999a25SKyle Evans     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
273*9c999a25SKyle Evans       NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
274*9c999a25SKyle Evans     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
275*9c999a25SKyle Evans         err(1, "%s", test_id);
276*9c999a25SKyle Evans 
277*9c999a25SKyle Evans     /* Retrieve the event */
278*9c999a25SKyle Evans     kev.flags = EV_ADD | EV_ONESHOT;
279*9c999a25SKyle Evans     kev.data = 1;
280*9c999a25SKyle Evans     kev.fflags = 0;
281*9c999a25SKyle Evans     kevent_cmp(&kev, kevent_get(kqfd));
282*9c999a25SKyle Evans 
283*9c999a25SKyle Evans     stop = now();
284*9c999a25SKyle Evans     if (stop < end)
285*9c999a25SKyle Evans         err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
286*9c999a25SKyle Evans     /* Check if the event occurs again */
287*9c999a25SKyle Evans     sleep(3);
288*9c999a25SKyle Evans     test_no_kevents();
289*9c999a25SKyle Evans 
290*9c999a25SKyle Evans     success();
291*9c999a25SKyle Evans }
292*9c999a25SKyle Evans 
293*9c999a25SKyle Evans static void
294*9c999a25SKyle Evans test_abstime_postboot(void)
295*9c999a25SKyle Evans {
296*9c999a25SKyle Evans     const char *test_id = "kevent(EVFILT_TIMER (POSTBOOT), EV_ONESHOT, NOTE_ABSTIME)";
297*9c999a25SKyle Evans     struct kevent kev;
298*9c999a25SKyle Evans     uint64_t end, start, stop;
299*9c999a25SKyle Evans     const int timeout_sec = 1;
300*9c999a25SKyle Evans 
301*9c999a25SKyle Evans     test_begin(test_id);
302*9c999a25SKyle Evans 
303*9c999a25SKyle Evans     test_no_kevents();
304*9c999a25SKyle Evans 
305*9c999a25SKyle Evans     /*
306*9c999a25SKyle Evans      * Set a timer for 1 second ago, it should fire immediately rather than
307*9c999a25SKyle Evans      * being rejected.
308*9c999a25SKyle Evans      */
309*9c999a25SKyle Evans     start = now();
310*9c999a25SKyle Evans     end = start - SEC_TO_US(timeout_sec);
311*9c999a25SKyle Evans     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
312*9c999a25SKyle Evans       NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
313*9c999a25SKyle Evans     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
314*9c999a25SKyle Evans         err(1, "%s", test_id);
315*9c999a25SKyle Evans 
316*9c999a25SKyle Evans     /* Retrieve the event */
317*9c999a25SKyle Evans     kev.flags = EV_ADD | EV_ONESHOT;
318*9c999a25SKyle Evans     kev.data = 1;
319*9c999a25SKyle Evans     kev.fflags = 0;
320*9c999a25SKyle Evans     kevent_cmp(&kev, kevent_get(kqfd));
321*9c999a25SKyle Evans 
322*9c999a25SKyle Evans     stop = now();
323*9c999a25SKyle Evans     if (stop < end)
324*9c999a25SKyle Evans         err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
325*9c999a25SKyle Evans     /* Check if the event occurs again */
326*9c999a25SKyle Evans     sleep(3);
327*9c999a25SKyle Evans     test_no_kevents();
328*9c999a25SKyle Evans 
329*9c999a25SKyle Evans     success();
330*9c999a25SKyle Evans }
331*9c999a25SKyle Evans 
332*9c999a25SKyle Evans static void
33395c05062SDavid Bright test_update(void)
33495c05062SDavid Bright {
33595c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)";
33695c05062SDavid Bright     struct kevent kev;
33795c05062SDavid Bright     long elapsed;
3380fbdc372SKyle Evans     uint64_t start;
33995c05062SDavid Bright 
34095c05062SDavid Bright     test_begin(test_id);
34195c05062SDavid Bright 
34295c05062SDavid Bright     test_no_kevents();
34395c05062SDavid Bright 
34495c05062SDavid Bright     /* First set the timer to 1 second */
34595c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
34695c05062SDavid Bright         NOTE_USECONDS, SEC_TO_US(1), (void *)1);
34795c05062SDavid Bright     start = now();
34895c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
34995c05062SDavid Bright         err(1, "%s", test_id);
35095c05062SDavid Bright 
35195c05062SDavid Bright     /* Now reduce the timer to 1 ms */
35295c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
35395c05062SDavid Bright         NOTE_USECONDS, MS_TO_US(1), (void *)2);
35495c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
35595c05062SDavid Bright         err(1, "%s", test_id);
35695c05062SDavid Bright 
35795c05062SDavid Bright     /* Wait for the event */
35895c05062SDavid Bright     kev.flags |= EV_CLEAR;
35995c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
36095c05062SDavid Bright     kev.data = 1;
36195c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
36295c05062SDavid Bright     elapsed = now() - start;
36395c05062SDavid Bright 
36495c05062SDavid Bright     /* Check that the timer expired after at least 1 ms, but less than
36595c05062SDavid Bright      * 1 second. This check is to make sure that the original 1 second
36695c05062SDavid Bright      * timeout was not used.
36795c05062SDavid Bright      */
36895c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
36995c05062SDavid Bright     if (elapsed < MS_TO_US(1))
37095c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
37195c05062SDavid Bright     if (elapsed > SEC_TO_US(1))
37295c05062SDavid Bright         errx(1, "late timer expiration: %ld us", elapsed);
37395c05062SDavid Bright 
37495c05062SDavid Bright     success();
37595c05062SDavid Bright }
37695c05062SDavid Bright 
37795c05062SDavid Bright static void
37895c05062SDavid Bright test_update_equal(void)
37995c05062SDavid Bright {
38095c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)";
38195c05062SDavid Bright     struct kevent kev;
38295c05062SDavid Bright     long elapsed;
3830fbdc372SKyle Evans     uint64_t start;
38495c05062SDavid Bright 
38595c05062SDavid Bright     test_begin(test_id);
38695c05062SDavid Bright 
38795c05062SDavid Bright     test_no_kevents();
38895c05062SDavid Bright 
38995c05062SDavid Bright     /* First set the timer to 1 ms */
39095c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
39195c05062SDavid Bright         NOTE_USECONDS, MS_TO_US(1), NULL);
39295c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
39395c05062SDavid Bright         err(1, "%s", test_id);
39495c05062SDavid Bright 
39595c05062SDavid Bright     /* Sleep for a significant fraction of the timeout. */
39695c05062SDavid Bright     ussleep(600);
39795c05062SDavid Bright 
39895c05062SDavid Bright     /* Now re-add the timer with the same parameters */
39995c05062SDavid Bright     start = now();
40095c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
40195c05062SDavid Bright         err(1, "%s", test_id);
40295c05062SDavid Bright 
40395c05062SDavid Bright     /* Wait for the event */
40495c05062SDavid Bright     kev.flags |= EV_CLEAR;
40595c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
40695c05062SDavid Bright     kev.data = 1;
40795c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
40895c05062SDavid Bright     elapsed = now() - start;
40995c05062SDavid Bright 
41095c05062SDavid Bright     /* Check that the timer expired after at least 1 ms. This check is
41195c05062SDavid Bright      * to make sure that the timer re-started and that the event is
41295c05062SDavid Bright      * not from the original add of the timer.
41395c05062SDavid Bright      */
41495c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
41595c05062SDavid Bright     if (elapsed < MS_TO_US(1))
41695c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
41795c05062SDavid Bright 
41895c05062SDavid Bright     success();
41995c05062SDavid Bright }
42095c05062SDavid Bright 
42195c05062SDavid Bright static void
42295c05062SDavid Bright test_update_expired(void)
42395c05062SDavid Bright {
42495c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)";
42595c05062SDavid Bright     struct kevent kev;
42695c05062SDavid Bright     long elapsed;
4270fbdc372SKyle Evans     uint64_t start;
42895c05062SDavid Bright 
42995c05062SDavid Bright     test_begin(test_id);
43095c05062SDavid Bright 
43195c05062SDavid Bright     test_no_kevents();
43295c05062SDavid Bright 
43395c05062SDavid Bright     /* Set the timer to 1ms */
43495c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
43595c05062SDavid Bright         NOTE_USECONDS, MS_TO_US(1), NULL);
43695c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
43795c05062SDavid Bright         err(1, "%s", test_id);
43895c05062SDavid Bright 
43995c05062SDavid Bright     /* Wait for 2 ms to give the timer plenty of time to expire. */
44095c05062SDavid Bright     mssleep(2);
44195c05062SDavid Bright 
44295c05062SDavid Bright     /* Now re-add the timer */
44395c05062SDavid Bright     start = now();
44495c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
44595c05062SDavid Bright         err(1, "%s", test_id);
44695c05062SDavid Bright 
44795c05062SDavid Bright     /* Wait for the event */
44895c05062SDavid Bright     kev.flags |= EV_CLEAR;
44995c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
45095c05062SDavid Bright     kev.data = 1;
45195c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
45295c05062SDavid Bright     elapsed = now() - start;
45395c05062SDavid Bright 
45495c05062SDavid Bright     /* Check that the timer expired after at least 1 ms.  This check
45595c05062SDavid Bright      * is to make sure that the timer re-started and that the event is
45695c05062SDavid Bright      * not from the original add (and expiration) of the timer.
45795c05062SDavid Bright      */
45895c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
45995c05062SDavid Bright     if (elapsed < MS_TO_US(1))
46095c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
46195c05062SDavid Bright 
46295c05062SDavid Bright     /* Make sure the re-added timer does not fire. In other words,
46395c05062SDavid Bright      * test that the event received above was the only event from the
46495c05062SDavid Bright      * add and re-add of the timer.
46595c05062SDavid Bright      */
46695c05062SDavid Bright     mssleep(2);
46795c05062SDavid Bright     test_no_kevents();
46895c05062SDavid Bright 
46995c05062SDavid Bright     success();
47095c05062SDavid Bright }
47195c05062SDavid Bright 
47295c05062SDavid Bright static void
47395c05062SDavid Bright test_update_periodic(void)
47495c05062SDavid Bright {
47595c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)";
47695c05062SDavid Bright     struct kevent kev;
47795c05062SDavid Bright     long elapsed;
4780fbdc372SKyle Evans     uint64_t start, stop;
47995c05062SDavid Bright 
48095c05062SDavid Bright     test_begin(test_id);
48195c05062SDavid Bright 
48295c05062SDavid Bright     test_no_kevents();
48395c05062SDavid Bright 
48495c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL);
48595c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
48695c05062SDavid Bright         err(1, "%s", test_id);
48795c05062SDavid Bright 
48895c05062SDavid Bright     /* Retrieve the event */
48995c05062SDavid Bright     kev.flags = EV_ADD | EV_CLEAR;
49095c05062SDavid Bright     kev.data = 1;
49195c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
49295c05062SDavid Bright 
49395c05062SDavid Bright     /* Check if the event occurs again */
49495c05062SDavid Bright     sleep(1);
49595c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
49695c05062SDavid Bright 
49795c05062SDavid Bright     /* Re-add with new timeout. */
49895c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL);
49995c05062SDavid Bright     start = now();
50095c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
50195c05062SDavid Bright         err(1, "%s", test_id);
50295c05062SDavid Bright 
50395c05062SDavid Bright     /* Retrieve the event */
50495c05062SDavid Bright     kev.flags = EV_ADD | EV_CLEAR;
50595c05062SDavid Bright     kev.data = 1;
50695c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
50795c05062SDavid Bright 
50895c05062SDavid Bright     stop = now();
50995c05062SDavid Bright     elapsed = stop - start;
51095c05062SDavid Bright 
51195c05062SDavid Bright     /* Check that the timer expired after at least 2 ms.
51295c05062SDavid Bright      */
51395c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
51495c05062SDavid Bright     if (elapsed < MS_TO_US(2))
51595c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
51695c05062SDavid Bright 
51795c05062SDavid Bright     /* Delete the event */
51895c05062SDavid Bright     kev.flags = EV_DELETE;
51995c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
52095c05062SDavid Bright         err(1, "%s", test_id);
52195c05062SDavid Bright 
52295c05062SDavid Bright     success();
52395c05062SDavid Bright }
52495c05062SDavid Bright 
52595c05062SDavid Bright static void
52695c05062SDavid Bright test_update_timing(void)
52795c05062SDavid Bright {
52895c05062SDavid Bright #define	MIN_SLEEP 500
52995c05062SDavid Bright #define	MAX_SLEEP 1500
53095c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)";
53195c05062SDavid Bright     struct kevent kev;
53295c05062SDavid Bright     int iteration;
53395c05062SDavid Bright     int sleeptime;
53495c05062SDavid Bright     long elapsed;
5350fbdc372SKyle Evans     uint64_t start, stop;
53695c05062SDavid Bright 
53795c05062SDavid Bright     test_begin(test_id);
53895c05062SDavid Bright 
53995c05062SDavid Bright     test_no_kevents();
54095c05062SDavid Bright 
54195c05062SDavid Bright     /* Re-try the update tests with a variety of delays between the
54295c05062SDavid Bright      * original timer activation and the update of the timer. The goal
54395c05062SDavid Bright      * is to show that in all cases the only timer event that is
54495c05062SDavid Bright      * received is from the update and not the original timer add.
54595c05062SDavid Bright      */
54695c05062SDavid Bright     for (sleeptime = MIN_SLEEP, iteration = 1;
54795c05062SDavid Bright          sleeptime < MAX_SLEEP;
54895c05062SDavid Bright          ++sleeptime, ++iteration) {
54995c05062SDavid Bright 
55095c05062SDavid Bright         /* First set the timer to 1 ms */
55195c05062SDavid Bright         EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
55295c05062SDavid Bright             NOTE_USECONDS, MS_TO_US(1), NULL);
55395c05062SDavid Bright         if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
55495c05062SDavid Bright             err(1, "%s", test_id);
55595c05062SDavid Bright 
55695c05062SDavid Bright         /* Delay; the delay ranges from less than to greater than the
55795c05062SDavid Bright          * timer period.
55895c05062SDavid Bright          */
55995c05062SDavid Bright         ussleep(sleeptime);
56095c05062SDavid Bright 
56195c05062SDavid Bright         /* Now re-add the timer with the same parameters */
56295c05062SDavid Bright         start = now();
56395c05062SDavid Bright         if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
56495c05062SDavid Bright             err(1, "%s", test_id);
56595c05062SDavid Bright 
56695c05062SDavid Bright         /* Wait for the event */
56795c05062SDavid Bright         kev.flags |= EV_CLEAR;
56895c05062SDavid Bright         kev.fflags &= ~NOTE_USECONDS;
56995c05062SDavid Bright         kev.data = 1;
57095c05062SDavid Bright         kevent_cmp(&kev, kevent_get(kqfd));
57195c05062SDavid Bright         stop = now();
57295c05062SDavid Bright         elapsed = stop - start;
57395c05062SDavid Bright 
57495c05062SDavid Bright         /* Check that the timer expired after at least 1 ms. This
57595c05062SDavid Bright          * check is to make sure that the timer re-started and that
57695c05062SDavid Bright          * the event is not from the original add of the timer.
57795c05062SDavid Bright          */
57895c05062SDavid Bright         if (elapsed < MS_TO_US(1))
57995c05062SDavid Bright             errx(1, "early timer expiration: %ld us", elapsed);
58095c05062SDavid Bright 
58195c05062SDavid Bright         /* Make sure the re-added timer does not fire. In other words,
58295c05062SDavid Bright          * test that the event received above was the only event from
58395c05062SDavid Bright          * the add and re-add of the timer.
58495c05062SDavid Bright          */
58595c05062SDavid Bright         mssleep(2);
58695c05062SDavid Bright         test_no_kevents_quietly();
58795c05062SDavid Bright     }
58895c05062SDavid Bright 
58995c05062SDavid Bright     success();
59095c05062SDavid Bright }
59195c05062SDavid Bright 
592cb5fe245SEnji Cooper void
593c9c283bdSAlex Richardson test_evfilt_timer(void)
594cb5fe245SEnji Cooper {
595cb5fe245SEnji Cooper     kqfd = kqueue();
596cb5fe245SEnji Cooper     test_kevent_timer_add();
597cb5fe245SEnji Cooper     test_kevent_timer_del();
598cb5fe245SEnji Cooper     test_kevent_timer_get();
599cb5fe245SEnji Cooper     test_oneshot();
600cb5fe245SEnji Cooper     test_periodic();
6012b34e843SKonstantin Belousov     test_abstime();
602*9c999a25SKyle Evans     test_abstime_preboot();
603*9c999a25SKyle Evans     test_abstime_postboot();
60495c05062SDavid Bright     test_update();
60595c05062SDavid Bright     test_update_equal();
60695c05062SDavid Bright     test_update_expired();
60795c05062SDavid Bright     test_update_timing();
60895c05062SDavid Bright     test_update_periodic();
609cb5fe245SEnji Cooper     disable_and_enable();
610cb5fe245SEnji Cooper     close(kqfd);
611cb5fe245SEnji Cooper }
612