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 int kqfd;
30cb5fe245SEnji Cooper 
3195c05062SDavid Bright /* Get the current time with microsecond precision. Used for
3295c05062SDavid Bright  * sub-second timing to make some timer tests run faster.
3395c05062SDavid Bright  */
3495c05062SDavid Bright static long
now(void)3595c05062SDavid Bright now(void)
3695c05062SDavid Bright {
3795c05062SDavid Bright     struct timeval tv;
3895c05062SDavid Bright 
3995c05062SDavid Bright     gettimeofday(&tv, NULL);
4095c05062SDavid Bright     return SEC_TO_US(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  */
4695c05062SDavid Bright 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  */
6095c05062SDavid Bright 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 
71cb5fe245SEnji Cooper 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 
86cb5fe245SEnji Cooper 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 
103cb5fe245SEnji Cooper 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;
220*d0a17901SDavid Bright     time_t start;
221*d0a17901SDavid Bright     time_t stop;
2222b34e843SKonstantin Belousov     const int timeout = 3;
2232b34e843SKonstantin Belousov 
2242b34e843SKonstantin Belousov     test_begin(test_id);
2252b34e843SKonstantin Belousov 
2262b34e843SKonstantin Belousov     test_no_kevents();
2272b34e843SKonstantin Belousov 
228*d0a17901SDavid Bright     start = time(NULL);
2292b34e843SKonstantin Belousov     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
230*d0a17901SDavid Bright       NOTE_ABSTIME | NOTE_SECONDS, start + timeout, 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));
239*d0a17901SDavid Bright     stop = time(NULL);
240*d0a17901SDavid Bright     if (stop < start + timeout)
241*d0a17901SDavid Bright         err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)(start + timeout));
2422b34e843SKonstantin Belousov 
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_update(void)25195c05062SDavid Bright test_update(void)
25295c05062SDavid Bright {
25395c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)";
25495c05062SDavid Bright     struct kevent kev;
25595c05062SDavid Bright     long elapsed;
25695c05062SDavid Bright     long start;
25795c05062SDavid Bright 
25895c05062SDavid Bright     test_begin(test_id);
25995c05062SDavid Bright 
26095c05062SDavid Bright     test_no_kevents();
26195c05062SDavid Bright 
26295c05062SDavid Bright     /* First set the timer to 1 second */
26395c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
26495c05062SDavid Bright         NOTE_USECONDS, SEC_TO_US(1), (void *)1);
26595c05062SDavid Bright     start = now();
26695c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
26795c05062SDavid Bright         err(1, "%s", test_id);
26895c05062SDavid Bright 
26995c05062SDavid Bright     /* Now reduce the timer to 1 ms */
27095c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
27195c05062SDavid Bright         NOTE_USECONDS, MS_TO_US(1), (void *)2);
27295c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
27395c05062SDavid Bright         err(1, "%s", test_id);
27495c05062SDavid Bright 
27595c05062SDavid Bright     /* Wait for the event */
27695c05062SDavid Bright     kev.flags |= EV_CLEAR;
27795c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
27895c05062SDavid Bright     kev.data = 1;
27995c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
28095c05062SDavid Bright     elapsed = now() - start;
28195c05062SDavid Bright 
28295c05062SDavid Bright     /* Check that the timer expired after at least 1 ms, but less than
28395c05062SDavid Bright      * 1 second. This check is to make sure that the original 1 second
28495c05062SDavid Bright      * timeout was not used.
28595c05062SDavid Bright      */
28695c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
28795c05062SDavid Bright     if (elapsed < MS_TO_US(1))
28895c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
28995c05062SDavid Bright     if (elapsed > SEC_TO_US(1))
29095c05062SDavid Bright         errx(1, "late timer expiration: %ld us", elapsed);
29195c05062SDavid Bright 
29295c05062SDavid Bright     success();
29395c05062SDavid Bright }
29495c05062SDavid Bright 
29595c05062SDavid Bright static void
test_update_equal(void)29695c05062SDavid Bright test_update_equal(void)
29795c05062SDavid Bright {
29895c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)";
29995c05062SDavid Bright     struct kevent kev;
30095c05062SDavid Bright     long elapsed;
30195c05062SDavid Bright     long start;
30295c05062SDavid Bright 
30395c05062SDavid Bright     test_begin(test_id);
30495c05062SDavid Bright 
30595c05062SDavid Bright     test_no_kevents();
30695c05062SDavid Bright 
30795c05062SDavid Bright     /* First set the timer to 1 ms */
30895c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
30995c05062SDavid Bright         NOTE_USECONDS, MS_TO_US(1), NULL);
31095c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
31195c05062SDavid Bright         err(1, "%s", test_id);
31295c05062SDavid Bright 
31395c05062SDavid Bright     /* Sleep for a significant fraction of the timeout. */
31495c05062SDavid Bright     ussleep(600);
31595c05062SDavid Bright 
31695c05062SDavid Bright     /* Now re-add the timer with the same parameters */
31795c05062SDavid Bright     start = now();
31895c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
31995c05062SDavid Bright         err(1, "%s", test_id);
32095c05062SDavid Bright 
32195c05062SDavid Bright     /* Wait for the event */
32295c05062SDavid Bright     kev.flags |= EV_CLEAR;
32395c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
32495c05062SDavid Bright     kev.data = 1;
32595c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
32695c05062SDavid Bright     elapsed = now() - start;
32795c05062SDavid Bright 
32895c05062SDavid Bright     /* Check that the timer expired after at least 1 ms. This check is
32995c05062SDavid Bright      * to make sure that the timer re-started and that the event is
33095c05062SDavid Bright      * not from the original add of the timer.
33195c05062SDavid Bright      */
33295c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
33395c05062SDavid Bright     if (elapsed < MS_TO_US(1))
33495c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
33595c05062SDavid Bright 
33695c05062SDavid Bright     success();
33795c05062SDavid Bright }
33895c05062SDavid Bright 
33995c05062SDavid Bright static void
test_update_expired(void)34095c05062SDavid Bright test_update_expired(void)
34195c05062SDavid Bright {
34295c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)";
34395c05062SDavid Bright     struct kevent kev;
34495c05062SDavid Bright     long elapsed;
34595c05062SDavid Bright     long start;
34695c05062SDavid Bright 
34795c05062SDavid Bright     test_begin(test_id);
34895c05062SDavid Bright 
34995c05062SDavid Bright     test_no_kevents();
35095c05062SDavid Bright 
35195c05062SDavid Bright     /* Set the timer to 1ms */
35295c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
35395c05062SDavid Bright         NOTE_USECONDS, MS_TO_US(1), NULL);
35495c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
35595c05062SDavid Bright         err(1, "%s", test_id);
35695c05062SDavid Bright 
35795c05062SDavid Bright     /* Wait for 2 ms to give the timer plenty of time to expire. */
35895c05062SDavid Bright     mssleep(2);
35995c05062SDavid Bright 
36095c05062SDavid Bright     /* Now re-add the timer */
36195c05062SDavid Bright     start = now();
36295c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
36395c05062SDavid Bright         err(1, "%s", test_id);
36495c05062SDavid Bright 
36595c05062SDavid Bright     /* Wait for the event */
36695c05062SDavid Bright     kev.flags |= EV_CLEAR;
36795c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
36895c05062SDavid Bright     kev.data = 1;
36995c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
37095c05062SDavid Bright     elapsed = now() - start;
37195c05062SDavid Bright 
37295c05062SDavid Bright     /* Check that the timer expired after at least 1 ms.  This check
37395c05062SDavid Bright      * is to make sure that the timer re-started and that the event is
37495c05062SDavid Bright      * not from the original add (and expiration) of the timer.
37595c05062SDavid Bright      */
37695c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
37795c05062SDavid Bright     if (elapsed < MS_TO_US(1))
37895c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
37995c05062SDavid Bright 
38095c05062SDavid Bright     /* Make sure the re-added timer does not fire. In other words,
38195c05062SDavid Bright      * test that the event received above was the only event from the
38295c05062SDavid Bright      * add and re-add of the timer.
38395c05062SDavid Bright      */
38495c05062SDavid Bright     mssleep(2);
38595c05062SDavid Bright     test_no_kevents();
38695c05062SDavid Bright 
38795c05062SDavid Bright     success();
38895c05062SDavid Bright }
38995c05062SDavid Bright 
39095c05062SDavid Bright static void
test_update_periodic(void)39195c05062SDavid Bright test_update_periodic(void)
39295c05062SDavid Bright {
39395c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)";
39495c05062SDavid Bright     struct kevent kev;
39595c05062SDavid Bright     long elapsed;
39695c05062SDavid Bright     long start;
39795c05062SDavid Bright     long stop;
39895c05062SDavid Bright 
39995c05062SDavid Bright     test_begin(test_id);
40095c05062SDavid Bright 
40195c05062SDavid Bright     test_no_kevents();
40295c05062SDavid Bright 
40395c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL);
40495c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
40595c05062SDavid Bright         err(1, "%s", test_id);
40695c05062SDavid Bright 
40795c05062SDavid Bright     /* Retrieve the event */
40895c05062SDavid Bright     kev.flags = EV_ADD | EV_CLEAR;
40995c05062SDavid Bright     kev.data = 1;
41095c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
41195c05062SDavid Bright 
41295c05062SDavid Bright     /* Check if the event occurs again */
41395c05062SDavid Bright     sleep(1);
41495c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
41595c05062SDavid Bright 
41695c05062SDavid Bright     /* Re-add with new timeout. */
41795c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL);
41895c05062SDavid Bright     start = now();
41995c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
42095c05062SDavid Bright         err(1, "%s", test_id);
42195c05062SDavid Bright 
42295c05062SDavid Bright     /* Retrieve the event */
42395c05062SDavid Bright     kev.flags = EV_ADD | EV_CLEAR;
42495c05062SDavid Bright     kev.data = 1;
42595c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
42695c05062SDavid Bright 
42795c05062SDavid Bright     stop = now();
42895c05062SDavid Bright     elapsed = stop - start;
42995c05062SDavid Bright 
43095c05062SDavid Bright     /* Check that the timer expired after at least 2 ms.
43195c05062SDavid Bright      */
43295c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
43395c05062SDavid Bright     if (elapsed < MS_TO_US(2))
43495c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
43595c05062SDavid Bright 
43695c05062SDavid Bright     /* Delete the event */
43795c05062SDavid Bright     kev.flags = EV_DELETE;
43895c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
43995c05062SDavid Bright         err(1, "%s", test_id);
44095c05062SDavid Bright 
44195c05062SDavid Bright     success();
44295c05062SDavid Bright }
44395c05062SDavid Bright 
44495c05062SDavid Bright static void
test_update_timing(void)44595c05062SDavid Bright test_update_timing(void)
44695c05062SDavid Bright {
44795c05062SDavid Bright #define	MIN_SLEEP 500
44895c05062SDavid Bright #define	MAX_SLEEP 1500
44995c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)";
45095c05062SDavid Bright     struct kevent kev;
45195c05062SDavid Bright     int iteration;
45295c05062SDavid Bright     int sleeptime;
45395c05062SDavid Bright     long elapsed;
45495c05062SDavid Bright     long start;
45595c05062SDavid Bright     long stop;
45695c05062SDavid Bright 
45795c05062SDavid Bright     test_begin(test_id);
45895c05062SDavid Bright 
45995c05062SDavid Bright     test_no_kevents();
46095c05062SDavid Bright 
46195c05062SDavid Bright     /* Re-try the update tests with a variety of delays between the
46295c05062SDavid Bright      * original timer activation and the update of the timer. The goal
46395c05062SDavid Bright      * is to show that in all cases the only timer event that is
46495c05062SDavid Bright      * received is from the update and not the original timer add.
46595c05062SDavid Bright      */
46695c05062SDavid Bright     for (sleeptime = MIN_SLEEP, iteration = 1;
46795c05062SDavid Bright          sleeptime < MAX_SLEEP;
46895c05062SDavid Bright          ++sleeptime, ++iteration) {
46995c05062SDavid Bright 
47095c05062SDavid Bright         /* First set the timer to 1 ms */
47195c05062SDavid Bright         EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
47295c05062SDavid Bright             NOTE_USECONDS, MS_TO_US(1), NULL);
47395c05062SDavid Bright         if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
47495c05062SDavid Bright             err(1, "%s", test_id);
47595c05062SDavid Bright 
47695c05062SDavid Bright         /* Delay; the delay ranges from less than to greater than the
47795c05062SDavid Bright          * timer period.
47895c05062SDavid Bright          */
47995c05062SDavid Bright         ussleep(sleeptime);
48095c05062SDavid Bright 
48195c05062SDavid Bright         /* Now re-add the timer with the same parameters */
48295c05062SDavid Bright         start = now();
48395c05062SDavid Bright         if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
48495c05062SDavid Bright             err(1, "%s", test_id);
48595c05062SDavid Bright 
48695c05062SDavid Bright         /* Wait for the event */
48795c05062SDavid Bright         kev.flags |= EV_CLEAR;
48895c05062SDavid Bright         kev.fflags &= ~NOTE_USECONDS;
48995c05062SDavid Bright         kev.data = 1;
49095c05062SDavid Bright         kevent_cmp(&kev, kevent_get(kqfd));
49195c05062SDavid Bright         stop = now();
49295c05062SDavid Bright         elapsed = stop - start;
49395c05062SDavid Bright 
49495c05062SDavid Bright         /* Check that the timer expired after at least 1 ms. This
49595c05062SDavid Bright          * check is to make sure that the timer re-started and that
49695c05062SDavid Bright          * the event is not from the original add of the timer.
49795c05062SDavid Bright          */
49895c05062SDavid Bright         if (elapsed < MS_TO_US(1))
49995c05062SDavid Bright             errx(1, "early timer expiration: %ld us", elapsed);
50095c05062SDavid Bright 
50195c05062SDavid Bright         /* Make sure the re-added timer does not fire. In other words,
50295c05062SDavid Bright          * test that the event received above was the only event from
50395c05062SDavid Bright          * the add and re-add of the timer.
50495c05062SDavid Bright          */
50595c05062SDavid Bright         mssleep(2);
50695c05062SDavid Bright         test_no_kevents_quietly();
50795c05062SDavid Bright     }
50895c05062SDavid Bright 
50995c05062SDavid Bright     success();
51095c05062SDavid Bright }
51195c05062SDavid Bright 
512cb5fe245SEnji Cooper void
test_evfilt_timer()513cb5fe245SEnji Cooper test_evfilt_timer()
514cb5fe245SEnji Cooper {
515cb5fe245SEnji Cooper     kqfd = kqueue();
516cb5fe245SEnji Cooper     test_kevent_timer_add();
517cb5fe245SEnji Cooper     test_kevent_timer_del();
518cb5fe245SEnji Cooper     test_kevent_timer_get();
519cb5fe245SEnji Cooper     test_oneshot();
520cb5fe245SEnji Cooper     test_periodic();
5212b34e843SKonstantin Belousov     test_abstime();
52295c05062SDavid Bright     test_update();
52395c05062SDavid Bright     test_update_equal();
52495c05062SDavid Bright     test_update_expired();
52595c05062SDavid Bright     test_update_timing();
52695c05062SDavid Bright     test_update_periodic();
527cb5fe245SEnji Cooper     disable_and_enable();
528cb5fe245SEnji Cooper     close(kqfd);
529cb5fe245SEnji Cooper }
530