1cb5fe245SEnji Cooper /*
2cb5fe245SEnji Cooper  * Copyright (c) 2009 Mark Heily <[email protected]>
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
now(void)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
mssleep(int t)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
ussleep(int t)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
test_kevent_timer_add(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
test_kevent_timer_del(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
test_kevent_timer_get(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
test_oneshot(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
test_periodic(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
disable_and_enable(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
test_abstime(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
test_abstime_epoch(void)251*121740e1SKyle Evans test_abstime_epoch(void)
252*121740e1SKyle Evans {
253*121740e1SKyle Evans     const char *test_id = "kevent(EVFILT_TIMER (EPOCH), NOTE_ABSTIME)";
254*121740e1SKyle Evans     struct kevent kev;
255*121740e1SKyle Evans 
256*121740e1SKyle Evans     test_begin(test_id);
257*121740e1SKyle Evans 
258*121740e1SKyle Evans     test_no_kevents();
259*121740e1SKyle Evans 
260*121740e1SKyle Evans     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, NOTE_ABSTIME, 0,
261*121740e1SKyle Evans         NULL);
262*121740e1SKyle Evans     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
263*121740e1SKyle Evans         err(1, "%s", test_id);
264*121740e1SKyle Evans 
265*121740e1SKyle Evans     /* Retrieve the event */
266*121740e1SKyle Evans     kev.flags = EV_ADD;
267*121740e1SKyle Evans     kev.data = 1;
268*121740e1SKyle Evans     kev.fflags = 0;
269*121740e1SKyle Evans     kevent_cmp(&kev, kevent_get(kqfd));
270*121740e1SKyle Evans 
271*121740e1SKyle Evans     /* Delete the event */
272*121740e1SKyle Evans     kev.flags = EV_DELETE;
273*121740e1SKyle Evans     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
274*121740e1SKyle Evans         err(1, "%s", test_id);
275*121740e1SKyle Evans 
276*121740e1SKyle Evans     success();
277*121740e1SKyle Evans }
278*121740e1SKyle Evans 
279*121740e1SKyle Evans static void
test_abstime_preboot(void)280*121740e1SKyle Evans test_abstime_preboot(void)
281*121740e1SKyle Evans {
282*121740e1SKyle Evans     const char *test_id = "kevent(EVFILT_TIMER (PREBOOT), EV_ONESHOT, NOTE_ABSTIME)";
283*121740e1SKyle Evans     struct kevent kev;
284*121740e1SKyle Evans     struct timespec btp;
285*121740e1SKyle Evans     uint64_t end, start, stop;
286*121740e1SKyle Evans 
287*121740e1SKyle Evans     test_begin(test_id);
288*121740e1SKyle Evans 
289*121740e1SKyle Evans     test_no_kevents();
290*121740e1SKyle Evans 
291*121740e1SKyle Evans     /*
292*121740e1SKyle Evans      * We'll expire it at just before system boot (roughly) with the hope that
293*121740e1SKyle Evans      * we'll get an ~immediate expiration, just as we do for any value specified
294*121740e1SKyle Evans      * between system boot and now.
295*121740e1SKyle Evans      */
296*121740e1SKyle Evans     start = now();
297*121740e1SKyle Evans     if (clock_gettime(CLOCK_BOOTTIME, &btp) != 0)
298*121740e1SKyle Evans       err(1, "%s", test_id);
299*121740e1SKyle Evans 
300*121740e1SKyle Evans     end = start - SEC_TO_US(btp.tv_sec + 1);
301*121740e1SKyle Evans     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
302*121740e1SKyle Evans       NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
303*121740e1SKyle Evans     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
304*121740e1SKyle Evans         err(1, "%s", test_id);
305*121740e1SKyle Evans 
306*121740e1SKyle Evans     /* Retrieve the event */
307*121740e1SKyle Evans     kev.flags = EV_ADD | EV_ONESHOT;
308*121740e1SKyle Evans     kev.data = 1;
309*121740e1SKyle Evans     kev.fflags = 0;
310*121740e1SKyle Evans     kevent_cmp(&kev, kevent_get(kqfd));
311*121740e1SKyle Evans 
312*121740e1SKyle Evans     stop = now();
313*121740e1SKyle Evans     if (stop < end)
314*121740e1SKyle Evans         err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
315*121740e1SKyle Evans     /* Check if the event occurs again */
316*121740e1SKyle Evans     sleep(3);
317*121740e1SKyle Evans     test_no_kevents();
318*121740e1SKyle Evans 
319*121740e1SKyle Evans     success();
320*121740e1SKyle Evans }
321*121740e1SKyle Evans 
322*121740e1SKyle Evans static void
test_abstime_postboot(void)323*121740e1SKyle Evans test_abstime_postboot(void)
324*121740e1SKyle Evans {
325*121740e1SKyle Evans     const char *test_id = "kevent(EVFILT_TIMER (POSTBOOT), EV_ONESHOT, NOTE_ABSTIME)";
326*121740e1SKyle Evans     struct kevent kev;
327*121740e1SKyle Evans     uint64_t end, start, stop;
328*121740e1SKyle Evans     const int timeout_sec = 1;
329*121740e1SKyle Evans 
330*121740e1SKyle Evans     test_begin(test_id);
331*121740e1SKyle Evans 
332*121740e1SKyle Evans     test_no_kevents();
333*121740e1SKyle Evans 
334*121740e1SKyle Evans     /*
335*121740e1SKyle Evans      * Set a timer for 1 second ago, it should fire immediately rather than
336*121740e1SKyle Evans      * being rejected.
337*121740e1SKyle Evans      */
338*121740e1SKyle Evans     start = now();
339*121740e1SKyle Evans     end = start - SEC_TO_US(timeout_sec);
340*121740e1SKyle Evans     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
341*121740e1SKyle Evans       NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
342*121740e1SKyle Evans     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
343*121740e1SKyle Evans         err(1, "%s", test_id);
344*121740e1SKyle Evans 
345*121740e1SKyle Evans     /* Retrieve the event */
346*121740e1SKyle Evans     kev.flags = EV_ADD | EV_ONESHOT;
347*121740e1SKyle Evans     kev.data = 1;
348*121740e1SKyle Evans     kev.fflags = 0;
349*121740e1SKyle Evans     kevent_cmp(&kev, kevent_get(kqfd));
350*121740e1SKyle Evans 
351*121740e1SKyle Evans     stop = now();
352*121740e1SKyle Evans     if (stop < end)
353*121740e1SKyle Evans         err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
354*121740e1SKyle Evans     /* Check if the event occurs again */
355*121740e1SKyle Evans     sleep(3);
356*121740e1SKyle Evans     test_no_kevents();
357*121740e1SKyle Evans 
358*121740e1SKyle Evans     success();
359*121740e1SKyle Evans }
360*121740e1SKyle Evans 
361*121740e1SKyle Evans static void
test_update(void)36295c05062SDavid Bright test_update(void)
36395c05062SDavid Bright {
36495c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)";
36595c05062SDavid Bright     struct kevent kev;
36695c05062SDavid Bright     long elapsed;
3670fbdc372SKyle Evans     uint64_t start;
36895c05062SDavid Bright 
36995c05062SDavid Bright     test_begin(test_id);
37095c05062SDavid Bright 
37195c05062SDavid Bright     test_no_kevents();
37295c05062SDavid Bright 
37395c05062SDavid Bright     /* First set the timer to 1 second */
37495c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
37595c05062SDavid Bright         NOTE_USECONDS, SEC_TO_US(1), (void *)1);
37695c05062SDavid Bright     start = now();
37795c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
37895c05062SDavid Bright         err(1, "%s", test_id);
37995c05062SDavid Bright 
38095c05062SDavid Bright     /* Now reduce the timer to 1 ms */
38195c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
38295c05062SDavid Bright         NOTE_USECONDS, MS_TO_US(1), (void *)2);
38395c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
38495c05062SDavid Bright         err(1, "%s", test_id);
38595c05062SDavid Bright 
38695c05062SDavid Bright     /* Wait for the event */
38795c05062SDavid Bright     kev.flags |= EV_CLEAR;
38895c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
38995c05062SDavid Bright     kev.data = 1;
39095c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
39195c05062SDavid Bright     elapsed = now() - start;
39295c05062SDavid Bright 
39395c05062SDavid Bright     /* Check that the timer expired after at least 1 ms, but less than
39495c05062SDavid Bright      * 1 second. This check is to make sure that the original 1 second
39595c05062SDavid Bright      * timeout was not used.
39695c05062SDavid Bright      */
39795c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
39895c05062SDavid Bright     if (elapsed < MS_TO_US(1))
39995c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
40095c05062SDavid Bright     if (elapsed > SEC_TO_US(1))
40195c05062SDavid Bright         errx(1, "late timer expiration: %ld us", elapsed);
40295c05062SDavid Bright 
40395c05062SDavid Bright     success();
40495c05062SDavid Bright }
40595c05062SDavid Bright 
40695c05062SDavid Bright static void
test_update_equal(void)40795c05062SDavid Bright test_update_equal(void)
40895c05062SDavid Bright {
40995c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)";
41095c05062SDavid Bright     struct kevent kev;
41195c05062SDavid Bright     long elapsed;
4120fbdc372SKyle Evans     uint64_t start;
41395c05062SDavid Bright 
41495c05062SDavid Bright     test_begin(test_id);
41595c05062SDavid Bright 
41695c05062SDavid Bright     test_no_kevents();
41795c05062SDavid Bright 
41895c05062SDavid Bright     /* First set the timer to 1 ms */
41995c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
42095c05062SDavid Bright         NOTE_USECONDS, MS_TO_US(1), NULL);
42195c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
42295c05062SDavid Bright         err(1, "%s", test_id);
42395c05062SDavid Bright 
42495c05062SDavid Bright     /* Sleep for a significant fraction of the timeout. */
42595c05062SDavid Bright     ussleep(600);
42695c05062SDavid Bright 
42795c05062SDavid Bright     /* Now re-add the timer with the same parameters */
42895c05062SDavid Bright     start = now();
42995c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
43095c05062SDavid Bright         err(1, "%s", test_id);
43195c05062SDavid Bright 
43295c05062SDavid Bright     /* Wait for the event */
43395c05062SDavid Bright     kev.flags |= EV_CLEAR;
43495c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
43595c05062SDavid Bright     kev.data = 1;
43695c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
43795c05062SDavid Bright     elapsed = now() - start;
43895c05062SDavid Bright 
43995c05062SDavid Bright     /* Check that the timer expired after at least 1 ms. This check is
44095c05062SDavid Bright      * to make sure that the timer re-started and that the event is
44195c05062SDavid Bright      * not from the original add of the timer.
44295c05062SDavid Bright      */
44395c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
44495c05062SDavid Bright     if (elapsed < MS_TO_US(1))
44595c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
44695c05062SDavid Bright 
44795c05062SDavid Bright     success();
44895c05062SDavid Bright }
44995c05062SDavid Bright 
45095c05062SDavid Bright static void
test_update_expired(void)45195c05062SDavid Bright test_update_expired(void)
45295c05062SDavid Bright {
45395c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)";
45495c05062SDavid Bright     struct kevent kev;
45595c05062SDavid Bright     long elapsed;
4560fbdc372SKyle Evans     uint64_t start;
45795c05062SDavid Bright 
45895c05062SDavid Bright     test_begin(test_id);
45995c05062SDavid Bright 
46095c05062SDavid Bright     test_no_kevents();
46195c05062SDavid Bright 
46295c05062SDavid Bright     /* Set the timer to 1ms */
46395c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
46495c05062SDavid Bright         NOTE_USECONDS, MS_TO_US(1), NULL);
46595c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
46695c05062SDavid Bright         err(1, "%s", test_id);
46795c05062SDavid Bright 
46895c05062SDavid Bright     /* Wait for 2 ms to give the timer plenty of time to expire. */
46995c05062SDavid Bright     mssleep(2);
47095c05062SDavid Bright 
47195c05062SDavid Bright     /* Now re-add the timer */
47295c05062SDavid Bright     start = now();
47395c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
47495c05062SDavid Bright         err(1, "%s", test_id);
47595c05062SDavid Bright 
47695c05062SDavid Bright     /* Wait for the event */
47795c05062SDavid Bright     kev.flags |= EV_CLEAR;
47895c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
47995c05062SDavid Bright     kev.data = 1;
48095c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
48195c05062SDavid Bright     elapsed = now() - start;
48295c05062SDavid Bright 
48395c05062SDavid Bright     /* Check that the timer expired after at least 1 ms.  This check
48495c05062SDavid Bright      * is to make sure that the timer re-started and that the event is
48595c05062SDavid Bright      * not from the original add (and expiration) of the timer.
48695c05062SDavid Bright      */
48795c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
48895c05062SDavid Bright     if (elapsed < MS_TO_US(1))
48995c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
49095c05062SDavid Bright 
49195c05062SDavid Bright     /* Make sure the re-added timer does not fire. In other words,
49295c05062SDavid Bright      * test that the event received above was the only event from the
49395c05062SDavid Bright      * add and re-add of the timer.
49495c05062SDavid Bright      */
49595c05062SDavid Bright     mssleep(2);
49695c05062SDavid Bright     test_no_kevents();
49795c05062SDavid Bright 
49895c05062SDavid Bright     success();
49995c05062SDavid Bright }
50095c05062SDavid Bright 
50195c05062SDavid Bright static void
test_update_periodic(void)50295c05062SDavid Bright test_update_periodic(void)
50395c05062SDavid Bright {
50495c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)";
50595c05062SDavid Bright     struct kevent kev;
50695c05062SDavid Bright     long elapsed;
5070fbdc372SKyle Evans     uint64_t start, stop;
50895c05062SDavid Bright 
50995c05062SDavid Bright     test_begin(test_id);
51095c05062SDavid Bright 
51195c05062SDavid Bright     test_no_kevents();
51295c05062SDavid Bright 
51395c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL);
51495c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
51595c05062SDavid Bright         err(1, "%s", test_id);
51695c05062SDavid Bright 
51795c05062SDavid Bright     /* Retrieve the event */
51895c05062SDavid Bright     kev.flags = EV_ADD | EV_CLEAR;
51995c05062SDavid Bright     kev.data = 1;
52095c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
52195c05062SDavid Bright 
52295c05062SDavid Bright     /* Check if the event occurs again */
52395c05062SDavid Bright     sleep(1);
52495c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
52595c05062SDavid Bright 
52695c05062SDavid Bright     /* Re-add with new timeout. */
52795c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL);
52895c05062SDavid Bright     start = now();
52995c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
53095c05062SDavid Bright         err(1, "%s", test_id);
53195c05062SDavid Bright 
53295c05062SDavid Bright     /* Retrieve the event */
53395c05062SDavid Bright     kev.flags = EV_ADD | EV_CLEAR;
53495c05062SDavid Bright     kev.data = 1;
53595c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
53695c05062SDavid Bright 
53795c05062SDavid Bright     stop = now();
53895c05062SDavid Bright     elapsed = stop - start;
53995c05062SDavid Bright 
54095c05062SDavid Bright     /* Check that the timer expired after at least 2 ms.
54195c05062SDavid Bright      */
54295c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
54395c05062SDavid Bright     if (elapsed < MS_TO_US(2))
54495c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
54595c05062SDavid Bright 
54695c05062SDavid Bright     /* Delete the event */
54795c05062SDavid Bright     kev.flags = EV_DELETE;
54895c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
54995c05062SDavid Bright         err(1, "%s", test_id);
55095c05062SDavid Bright 
55195c05062SDavid Bright     success();
55295c05062SDavid Bright }
55395c05062SDavid Bright 
55495c05062SDavid Bright static void
test_update_timing(void)55595c05062SDavid Bright test_update_timing(void)
55695c05062SDavid Bright {
55795c05062SDavid Bright #define	MIN_SLEEP 500
55895c05062SDavid Bright #define	MAX_SLEEP 1500
55995c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)";
56095c05062SDavid Bright     struct kevent kev;
56195c05062SDavid Bright     int iteration;
56295c05062SDavid Bright     int sleeptime;
56395c05062SDavid Bright     long elapsed;
5640fbdc372SKyle Evans     uint64_t start, stop;
56595c05062SDavid Bright 
56695c05062SDavid Bright     test_begin(test_id);
56795c05062SDavid Bright 
56895c05062SDavid Bright     test_no_kevents();
56995c05062SDavid Bright 
57095c05062SDavid Bright     /* Re-try the update tests with a variety of delays between the
57195c05062SDavid Bright      * original timer activation and the update of the timer. The goal
57295c05062SDavid Bright      * is to show that in all cases the only timer event that is
57395c05062SDavid Bright      * received is from the update and not the original timer add.
57495c05062SDavid Bright      */
57595c05062SDavid Bright     for (sleeptime = MIN_SLEEP, iteration = 1;
57695c05062SDavid Bright          sleeptime < MAX_SLEEP;
57795c05062SDavid Bright          ++sleeptime, ++iteration) {
57895c05062SDavid Bright 
57995c05062SDavid Bright         /* First set the timer to 1 ms */
58095c05062SDavid Bright         EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
58195c05062SDavid Bright             NOTE_USECONDS, MS_TO_US(1), NULL);
58295c05062SDavid Bright         if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
58395c05062SDavid Bright             err(1, "%s", test_id);
58495c05062SDavid Bright 
58595c05062SDavid Bright         /* Delay; the delay ranges from less than to greater than the
58695c05062SDavid Bright          * timer period.
58795c05062SDavid Bright          */
58895c05062SDavid Bright         ussleep(sleeptime);
58995c05062SDavid Bright 
59095c05062SDavid Bright         /* Now re-add the timer with the same parameters */
59195c05062SDavid Bright         start = now();
59295c05062SDavid Bright         if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
59395c05062SDavid Bright             err(1, "%s", test_id);
59495c05062SDavid Bright 
59595c05062SDavid Bright         /* Wait for the event */
59695c05062SDavid Bright         kev.flags |= EV_CLEAR;
59795c05062SDavid Bright         kev.fflags &= ~NOTE_USECONDS;
59895c05062SDavid Bright         kev.data = 1;
59995c05062SDavid Bright         kevent_cmp(&kev, kevent_get(kqfd));
60095c05062SDavid Bright         stop = now();
60195c05062SDavid Bright         elapsed = stop - start;
60295c05062SDavid Bright 
60395c05062SDavid Bright         /* Check that the timer expired after at least 1 ms. This
60495c05062SDavid Bright          * check is to make sure that the timer re-started and that
60595c05062SDavid Bright          * the event is not from the original add of the timer.
60695c05062SDavid Bright          */
60795c05062SDavid Bright         if (elapsed < MS_TO_US(1))
60895c05062SDavid Bright             errx(1, "early timer expiration: %ld us", elapsed);
60995c05062SDavid Bright 
61095c05062SDavid Bright         /* Make sure the re-added timer does not fire. In other words,
61195c05062SDavid Bright          * test that the event received above was the only event from
61295c05062SDavid Bright          * the add and re-add of the timer.
61395c05062SDavid Bright          */
61495c05062SDavid Bright         mssleep(2);
61595c05062SDavid Bright         test_no_kevents_quietly();
61695c05062SDavid Bright     }
61795c05062SDavid Bright 
61895c05062SDavid Bright     success();
61995c05062SDavid Bright }
62095c05062SDavid Bright 
621cb5fe245SEnji Cooper void
test_evfilt_timer(void)622c9c283bdSAlex Richardson test_evfilt_timer(void)
623cb5fe245SEnji Cooper {
624cb5fe245SEnji Cooper     kqfd = kqueue();
625cb5fe245SEnji Cooper     test_kevent_timer_add();
626cb5fe245SEnji Cooper     test_kevent_timer_del();
627cb5fe245SEnji Cooper     test_kevent_timer_get();
628cb5fe245SEnji Cooper     test_oneshot();
629cb5fe245SEnji Cooper     test_periodic();
6302b34e843SKonstantin Belousov     test_abstime();
631*121740e1SKyle Evans     test_abstime_epoch();
632*121740e1SKyle Evans     test_abstime_preboot();
633*121740e1SKyle Evans     test_abstime_postboot();
63495c05062SDavid Bright     test_update();
63595c05062SDavid Bright     test_update_equal();
63695c05062SDavid Bright     test_update_expired();
63795c05062SDavid Bright     test_update_timing();
63895c05062SDavid Bright     test_update_periodic();
639cb5fe245SEnji Cooper     disable_and_enable();
640cb5fe245SEnji Cooper     close(kqfd);
641cb5fe245SEnji Cooper }
642