xref: /freebsd/tests/sys/kqueue/libkqueue/timer.c (revision c9c283bd3045c909671fc9aab250c35fe124ef35)
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  */
3395c05062SDavid Bright static long
3495c05062SDavid Bright now(void)
3595c05062SDavid Bright {
3695c05062SDavid Bright     struct timeval tv;
3795c05062SDavid Bright 
3895c05062SDavid Bright     gettimeofday(&tv, NULL);
3995c05062SDavid Bright     return SEC_TO_US(tv.tv_sec) + tv.tv_usec;
4095c05062SDavid Bright }
4195c05062SDavid Bright 
4295c05062SDavid Bright /* Sleep for a given number of milliseconds. The timeout is assumed to
4395c05062SDavid Bright  * be less than 1 second.
4495c05062SDavid Bright  */
45*c9c283bdSAlex Richardson static void
4695c05062SDavid Bright mssleep(int t)
4795c05062SDavid Bright {
4895c05062SDavid Bright     struct timespec stime = {
4995c05062SDavid Bright         .tv_sec = 0,
5095c05062SDavid Bright         .tv_nsec = US_TO_NS(MS_TO_US(t)),
5195c05062SDavid Bright     };
5295c05062SDavid Bright 
5395c05062SDavid Bright     nanosleep(&stime, NULL);
5495c05062SDavid Bright }
5595c05062SDavid Bright 
5695c05062SDavid Bright /* Sleep for a given number of microseconds. The timeout is assumed to
5795c05062SDavid Bright  * be less than 1 second.
5895c05062SDavid Bright  */
59*c9c283bdSAlex Richardson static void
6095c05062SDavid Bright ussleep(int t)
6195c05062SDavid Bright {
6295c05062SDavid Bright     struct timespec stime = {
6395c05062SDavid Bright         .tv_sec = 0,
6495c05062SDavid Bright         .tv_nsec = US_TO_NS(t),
6595c05062SDavid Bright     };
6695c05062SDavid Bright 
6795c05062SDavid Bright     nanosleep(&stime, NULL);
6895c05062SDavid Bright }
6995c05062SDavid Bright 
70*c9c283bdSAlex Richardson static void
71cb5fe245SEnji Cooper test_kevent_timer_add(void)
72cb5fe245SEnji Cooper {
73cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)";
74cb5fe245SEnji Cooper     struct kevent kev;
75cb5fe245SEnji Cooper 
76cb5fe245SEnji Cooper     test_begin(test_id);
77cb5fe245SEnji Cooper 
78cb5fe245SEnji Cooper     EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
79cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
80cb5fe245SEnji Cooper         err(1, "%s", test_id);
81cb5fe245SEnji Cooper 
82cb5fe245SEnji Cooper     success();
83cb5fe245SEnji Cooper }
84cb5fe245SEnji Cooper 
85*c9c283bdSAlex Richardson static void
86cb5fe245SEnji Cooper test_kevent_timer_del(void)
87cb5fe245SEnji Cooper {
88cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)";
89cb5fe245SEnji Cooper     struct kevent kev;
90cb5fe245SEnji Cooper 
91cb5fe245SEnji Cooper     test_begin(test_id);
92cb5fe245SEnji Cooper 
93cb5fe245SEnji Cooper     EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
94cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
95cb5fe245SEnji Cooper         err(1, "%s", test_id);
96cb5fe245SEnji Cooper 
97cb5fe245SEnji Cooper     test_no_kevents();
98cb5fe245SEnji Cooper 
99cb5fe245SEnji Cooper     success();
100cb5fe245SEnji Cooper }
101cb5fe245SEnji Cooper 
102*c9c283bdSAlex Richardson static void
103cb5fe245SEnji Cooper test_kevent_timer_get(void)
104cb5fe245SEnji Cooper {
105cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, wait)";
106cb5fe245SEnji Cooper     struct kevent kev;
107cb5fe245SEnji Cooper 
108cb5fe245SEnji Cooper     test_begin(test_id);
109cb5fe245SEnji Cooper 
110cb5fe245SEnji Cooper     EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
111cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
112cb5fe245SEnji Cooper         err(1, "%s", test_id);
113cb5fe245SEnji Cooper 
114cb5fe245SEnji Cooper     kev.flags |= EV_CLEAR;
115cb5fe245SEnji Cooper     kev.data = 1;
116cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
117cb5fe245SEnji Cooper 
118cb5fe245SEnji Cooper     EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
119cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
120cb5fe245SEnji Cooper         err(1, "%s", test_id);
121cb5fe245SEnji Cooper 
122cb5fe245SEnji Cooper     success();
123cb5fe245SEnji Cooper }
124cb5fe245SEnji Cooper 
125cb5fe245SEnji Cooper static void
126cb5fe245SEnji Cooper test_oneshot(void)
127cb5fe245SEnji Cooper {
128cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)";
129cb5fe245SEnji Cooper     struct kevent kev;
130cb5fe245SEnji Cooper 
131cb5fe245SEnji Cooper     test_begin(test_id);
132cb5fe245SEnji Cooper 
133cb5fe245SEnji Cooper     test_no_kevents();
134cb5fe245SEnji Cooper 
135cb5fe245SEnji Cooper     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL);
136cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
137cb5fe245SEnji Cooper         err(1, "%s", test_id);
138cb5fe245SEnji Cooper 
139cb5fe245SEnji Cooper     /* Retrieve the event */
140cb5fe245SEnji Cooper     kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
141cb5fe245SEnji Cooper     kev.data = 1;
142cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
143cb5fe245SEnji Cooper 
144cb5fe245SEnji Cooper     /* Check if the event occurs again */
145cb5fe245SEnji Cooper     sleep(3);
146cb5fe245SEnji Cooper     test_no_kevents();
147cb5fe245SEnji Cooper 
148cb5fe245SEnji Cooper 
149cb5fe245SEnji Cooper     success();
150cb5fe245SEnji Cooper }
151cb5fe245SEnji Cooper 
152cb5fe245SEnji Cooper static void
153cb5fe245SEnji Cooper test_periodic(void)
154cb5fe245SEnji Cooper {
155cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, periodic)";
156cb5fe245SEnji Cooper     struct kevent kev;
157cb5fe245SEnji Cooper 
158cb5fe245SEnji Cooper     test_begin(test_id);
159cb5fe245SEnji Cooper 
160cb5fe245SEnji Cooper     test_no_kevents();
161cb5fe245SEnji Cooper 
162cb5fe245SEnji Cooper     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL);
163cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
164cb5fe245SEnji Cooper         err(1, "%s", test_id);
165cb5fe245SEnji Cooper 
166cb5fe245SEnji Cooper     /* Retrieve the event */
167cb5fe245SEnji Cooper     kev.flags = EV_ADD | EV_CLEAR;
168cb5fe245SEnji Cooper     kev.data = 1;
169cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
170cb5fe245SEnji Cooper 
171cb5fe245SEnji Cooper     /* Check if the event occurs again */
172cb5fe245SEnji Cooper     sleep(1);
173cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
174cb5fe245SEnji Cooper 
175cb5fe245SEnji Cooper     /* Delete the event */
176cb5fe245SEnji Cooper     kev.flags = EV_DELETE;
177cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
178cb5fe245SEnji Cooper         err(1, "%s", test_id);
179cb5fe245SEnji Cooper 
180cb5fe245SEnji Cooper     success();
181cb5fe245SEnji Cooper }
182cb5fe245SEnji Cooper 
183cb5fe245SEnji Cooper static void
184cb5fe245SEnji Cooper disable_and_enable(void)
185cb5fe245SEnji Cooper {
186cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
187cb5fe245SEnji Cooper     struct kevent kev;
188cb5fe245SEnji Cooper 
189cb5fe245SEnji Cooper     test_begin(test_id);
190cb5fe245SEnji Cooper 
191cb5fe245SEnji Cooper     test_no_kevents();
192cb5fe245SEnji Cooper 
193cb5fe245SEnji Cooper     /* Add the watch and immediately disable it */
194cb5fe245SEnji Cooper     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
195cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
196cb5fe245SEnji Cooper         err(1, "%s", test_id);
197cb5fe245SEnji Cooper     kev.flags = EV_DISABLE;
198cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
199cb5fe245SEnji Cooper         err(1, "%s", test_id);
200cb5fe245SEnji Cooper     test_no_kevents();
201cb5fe245SEnji Cooper 
202cb5fe245SEnji Cooper     /* Re-enable and check again */
203cb5fe245SEnji Cooper     kev.flags = EV_ENABLE;
204cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
205cb5fe245SEnji Cooper         err(1, "%s", test_id);
206cb5fe245SEnji Cooper 
207cb5fe245SEnji Cooper     kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
208cb5fe245SEnji Cooper     kev.data = 1;
209cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
210cb5fe245SEnji Cooper 
211cb5fe245SEnji Cooper     success();
212cb5fe245SEnji Cooper }
213cb5fe245SEnji Cooper 
2142b34e843SKonstantin Belousov static void
2152b34e843SKonstantin Belousov test_abstime(void)
2162b34e843SKonstantin Belousov {
2172b34e843SKonstantin Belousov     const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)";
2182b34e843SKonstantin Belousov     struct kevent kev;
219c17dd0e8SKyle Evans     long end, start, stop;
220c17dd0e8SKyle Evans     const int timeout_sec = 3;
2212b34e843SKonstantin Belousov 
2222b34e843SKonstantin Belousov     test_begin(test_id);
2232b34e843SKonstantin Belousov 
2242b34e843SKonstantin Belousov     test_no_kevents();
2252b34e843SKonstantin Belousov 
226c17dd0e8SKyle Evans     start = now();
227c17dd0e8SKyle Evans     end = start + SEC_TO_US(timeout_sec);
2282b34e843SKonstantin Belousov     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
229c17dd0e8SKyle Evans       NOTE_ABSTIME | NOTE_USECONDS, end, NULL);
2302b34e843SKonstantin Belousov     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
2312b34e843SKonstantin Belousov         err(1, "%s", test_id);
2322b34e843SKonstantin Belousov 
2332b34e843SKonstantin Belousov     /* Retrieve the event */
2342b34e843SKonstantin Belousov     kev.flags = EV_ADD | EV_ONESHOT;
2352b34e843SKonstantin Belousov     kev.data = 1;
2362b34e843SKonstantin Belousov     kev.fflags = 0;
2372b34e843SKonstantin Belousov     kevent_cmp(&kev, kevent_get(kqfd));
2382b34e843SKonstantin Belousov 
239c17dd0e8SKyle Evans     stop = now();
240c17dd0e8SKyle Evans     if (stop < end)
241c17dd0e8SKyle Evans         err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end);
2422b34e843SKonstantin Belousov     /* Check if the event occurs again */
2432b34e843SKonstantin Belousov     sleep(3);
2442b34e843SKonstantin Belousov     test_no_kevents();
2452b34e843SKonstantin Belousov 
2462b34e843SKonstantin Belousov     success();
2472b34e843SKonstantin Belousov }
2482b34e843SKonstantin Belousov 
24995c05062SDavid Bright static void
25095c05062SDavid Bright test_update(void)
25195c05062SDavid Bright {
25295c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)";
25395c05062SDavid Bright     struct kevent kev;
25495c05062SDavid Bright     long elapsed;
25595c05062SDavid Bright     long start;
25695c05062SDavid Bright 
25795c05062SDavid Bright     test_begin(test_id);
25895c05062SDavid Bright 
25995c05062SDavid Bright     test_no_kevents();
26095c05062SDavid Bright 
26195c05062SDavid Bright     /* First set the timer to 1 second */
26295c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
26395c05062SDavid Bright         NOTE_USECONDS, SEC_TO_US(1), (void *)1);
26495c05062SDavid Bright     start = now();
26595c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
26695c05062SDavid Bright         err(1, "%s", test_id);
26795c05062SDavid Bright 
26895c05062SDavid Bright     /* Now reduce the timer to 1 ms */
26995c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
27095c05062SDavid Bright         NOTE_USECONDS, MS_TO_US(1), (void *)2);
27195c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
27295c05062SDavid Bright         err(1, "%s", test_id);
27395c05062SDavid Bright 
27495c05062SDavid Bright     /* Wait for the event */
27595c05062SDavid Bright     kev.flags |= EV_CLEAR;
27695c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
27795c05062SDavid Bright     kev.data = 1;
27895c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
27995c05062SDavid Bright     elapsed = now() - start;
28095c05062SDavid Bright 
28195c05062SDavid Bright     /* Check that the timer expired after at least 1 ms, but less than
28295c05062SDavid Bright      * 1 second. This check is to make sure that the original 1 second
28395c05062SDavid Bright      * timeout was not used.
28495c05062SDavid Bright      */
28595c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
28695c05062SDavid Bright     if (elapsed < MS_TO_US(1))
28795c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
28895c05062SDavid Bright     if (elapsed > SEC_TO_US(1))
28995c05062SDavid Bright         errx(1, "late timer expiration: %ld us", elapsed);
29095c05062SDavid Bright 
29195c05062SDavid Bright     success();
29295c05062SDavid Bright }
29395c05062SDavid Bright 
29495c05062SDavid Bright static void
29595c05062SDavid Bright test_update_equal(void)
29695c05062SDavid Bright {
29795c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)";
29895c05062SDavid Bright     struct kevent kev;
29995c05062SDavid Bright     long elapsed;
30095c05062SDavid Bright     long start;
30195c05062SDavid Bright 
30295c05062SDavid Bright     test_begin(test_id);
30395c05062SDavid Bright 
30495c05062SDavid Bright     test_no_kevents();
30595c05062SDavid Bright 
30695c05062SDavid Bright     /* First set the timer to 1 ms */
30795c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
30895c05062SDavid Bright         NOTE_USECONDS, MS_TO_US(1), NULL);
30995c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
31095c05062SDavid Bright         err(1, "%s", test_id);
31195c05062SDavid Bright 
31295c05062SDavid Bright     /* Sleep for a significant fraction of the timeout. */
31395c05062SDavid Bright     ussleep(600);
31495c05062SDavid Bright 
31595c05062SDavid Bright     /* Now re-add the timer with the same parameters */
31695c05062SDavid Bright     start = now();
31795c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
31895c05062SDavid Bright         err(1, "%s", test_id);
31995c05062SDavid Bright 
32095c05062SDavid Bright     /* Wait for the event */
32195c05062SDavid Bright     kev.flags |= EV_CLEAR;
32295c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
32395c05062SDavid Bright     kev.data = 1;
32495c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
32595c05062SDavid Bright     elapsed = now() - start;
32695c05062SDavid Bright 
32795c05062SDavid Bright     /* Check that the timer expired after at least 1 ms. This check is
32895c05062SDavid Bright      * to make sure that the timer re-started and that the event is
32995c05062SDavid Bright      * not from the original add of the timer.
33095c05062SDavid Bright      */
33195c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
33295c05062SDavid Bright     if (elapsed < MS_TO_US(1))
33395c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
33495c05062SDavid Bright 
33595c05062SDavid Bright     success();
33695c05062SDavid Bright }
33795c05062SDavid Bright 
33895c05062SDavid Bright static void
33995c05062SDavid Bright test_update_expired(void)
34095c05062SDavid Bright {
34195c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)";
34295c05062SDavid Bright     struct kevent kev;
34395c05062SDavid Bright     long elapsed;
34495c05062SDavid Bright     long start;
34595c05062SDavid Bright 
34695c05062SDavid Bright     test_begin(test_id);
34795c05062SDavid Bright 
34895c05062SDavid Bright     test_no_kevents();
34995c05062SDavid Bright 
35095c05062SDavid Bright     /* Set the timer to 1ms */
35195c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
35295c05062SDavid Bright         NOTE_USECONDS, MS_TO_US(1), NULL);
35395c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
35495c05062SDavid Bright         err(1, "%s", test_id);
35595c05062SDavid Bright 
35695c05062SDavid Bright     /* Wait for 2 ms to give the timer plenty of time to expire. */
35795c05062SDavid Bright     mssleep(2);
35895c05062SDavid Bright 
35995c05062SDavid Bright     /* Now re-add the timer */
36095c05062SDavid Bright     start = now();
36195c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
36295c05062SDavid Bright         err(1, "%s", test_id);
36395c05062SDavid Bright 
36495c05062SDavid Bright     /* Wait for the event */
36595c05062SDavid Bright     kev.flags |= EV_CLEAR;
36695c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
36795c05062SDavid Bright     kev.data = 1;
36895c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
36995c05062SDavid Bright     elapsed = now() - start;
37095c05062SDavid Bright 
37195c05062SDavid Bright     /* Check that the timer expired after at least 1 ms.  This check
37295c05062SDavid Bright      * is to make sure that the timer re-started and that the event is
37395c05062SDavid Bright      * not from the original add (and expiration) of the timer.
37495c05062SDavid Bright      */
37595c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
37695c05062SDavid Bright     if (elapsed < MS_TO_US(1))
37795c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
37895c05062SDavid Bright 
37995c05062SDavid Bright     /* Make sure the re-added timer does not fire. In other words,
38095c05062SDavid Bright      * test that the event received above was the only event from the
38195c05062SDavid Bright      * add and re-add of the timer.
38295c05062SDavid Bright      */
38395c05062SDavid Bright     mssleep(2);
38495c05062SDavid Bright     test_no_kevents();
38595c05062SDavid Bright 
38695c05062SDavid Bright     success();
38795c05062SDavid Bright }
38895c05062SDavid Bright 
38995c05062SDavid Bright static void
39095c05062SDavid Bright test_update_periodic(void)
39195c05062SDavid Bright {
39295c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)";
39395c05062SDavid Bright     struct kevent kev;
39495c05062SDavid Bright     long elapsed;
39595c05062SDavid Bright     long start;
39695c05062SDavid Bright     long stop;
39795c05062SDavid Bright 
39895c05062SDavid Bright     test_begin(test_id);
39995c05062SDavid Bright 
40095c05062SDavid Bright     test_no_kevents();
40195c05062SDavid Bright 
40295c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL);
40395c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
40495c05062SDavid Bright         err(1, "%s", test_id);
40595c05062SDavid Bright 
40695c05062SDavid Bright     /* Retrieve the event */
40795c05062SDavid Bright     kev.flags = EV_ADD | EV_CLEAR;
40895c05062SDavid Bright     kev.data = 1;
40995c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
41095c05062SDavid Bright 
41195c05062SDavid Bright     /* Check if the event occurs again */
41295c05062SDavid Bright     sleep(1);
41395c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
41495c05062SDavid Bright 
41595c05062SDavid Bright     /* Re-add with new timeout. */
41695c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL);
41795c05062SDavid Bright     start = now();
41895c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
41995c05062SDavid Bright         err(1, "%s", test_id);
42095c05062SDavid Bright 
42195c05062SDavid Bright     /* Retrieve the event */
42295c05062SDavid Bright     kev.flags = EV_ADD | EV_CLEAR;
42395c05062SDavid Bright     kev.data = 1;
42495c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
42595c05062SDavid Bright 
42695c05062SDavid Bright     stop = now();
42795c05062SDavid Bright     elapsed = stop - start;
42895c05062SDavid Bright 
42995c05062SDavid Bright     /* Check that the timer expired after at least 2 ms.
43095c05062SDavid Bright      */
43195c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
43295c05062SDavid Bright     if (elapsed < MS_TO_US(2))
43395c05062SDavid Bright         errx(1, "early timer expiration: %ld us", elapsed);
43495c05062SDavid Bright 
43595c05062SDavid Bright     /* Delete the event */
43695c05062SDavid Bright     kev.flags = EV_DELETE;
43795c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
43895c05062SDavid Bright         err(1, "%s", test_id);
43995c05062SDavid Bright 
44095c05062SDavid Bright     success();
44195c05062SDavid Bright }
44295c05062SDavid Bright 
44395c05062SDavid Bright static void
44495c05062SDavid Bright test_update_timing(void)
44595c05062SDavid Bright {
44695c05062SDavid Bright #define	MIN_SLEEP 500
44795c05062SDavid Bright #define	MAX_SLEEP 1500
44895c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)";
44995c05062SDavid Bright     struct kevent kev;
45095c05062SDavid Bright     int iteration;
45195c05062SDavid Bright     int sleeptime;
45295c05062SDavid Bright     long elapsed;
45395c05062SDavid Bright     long start;
45495c05062SDavid Bright     long stop;
45595c05062SDavid Bright 
45695c05062SDavid Bright     test_begin(test_id);
45795c05062SDavid Bright 
45895c05062SDavid Bright     test_no_kevents();
45995c05062SDavid Bright 
46095c05062SDavid Bright     /* Re-try the update tests with a variety of delays between the
46195c05062SDavid Bright      * original timer activation and the update of the timer. The goal
46295c05062SDavid Bright      * is to show that in all cases the only timer event that is
46395c05062SDavid Bright      * received is from the update and not the original timer add.
46495c05062SDavid Bright      */
46595c05062SDavid Bright     for (sleeptime = MIN_SLEEP, iteration = 1;
46695c05062SDavid Bright          sleeptime < MAX_SLEEP;
46795c05062SDavid Bright          ++sleeptime, ++iteration) {
46895c05062SDavid Bright 
46995c05062SDavid Bright         /* First set the timer to 1 ms */
47095c05062SDavid Bright         EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
47195c05062SDavid Bright             NOTE_USECONDS, MS_TO_US(1), NULL);
47295c05062SDavid Bright         if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
47395c05062SDavid Bright             err(1, "%s", test_id);
47495c05062SDavid Bright 
47595c05062SDavid Bright         /* Delay; the delay ranges from less than to greater than the
47695c05062SDavid Bright          * timer period.
47795c05062SDavid Bright          */
47895c05062SDavid Bright         ussleep(sleeptime);
47995c05062SDavid Bright 
48095c05062SDavid Bright         /* Now re-add the timer with the same parameters */
48195c05062SDavid Bright         start = now();
48295c05062SDavid Bright         if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
48395c05062SDavid Bright             err(1, "%s", test_id);
48495c05062SDavid Bright 
48595c05062SDavid Bright         /* Wait for the event */
48695c05062SDavid Bright         kev.flags |= EV_CLEAR;
48795c05062SDavid Bright         kev.fflags &= ~NOTE_USECONDS;
48895c05062SDavid Bright         kev.data = 1;
48995c05062SDavid Bright         kevent_cmp(&kev, kevent_get(kqfd));
49095c05062SDavid Bright         stop = now();
49195c05062SDavid Bright         elapsed = stop - start;
49295c05062SDavid Bright 
49395c05062SDavid Bright         /* Check that the timer expired after at least 1 ms. This
49495c05062SDavid Bright          * check is to make sure that the timer re-started and that
49595c05062SDavid Bright          * the event is not from the original add of the timer.
49695c05062SDavid Bright          */
49795c05062SDavid Bright         if (elapsed < MS_TO_US(1))
49895c05062SDavid Bright             errx(1, "early timer expiration: %ld us", elapsed);
49995c05062SDavid Bright 
50095c05062SDavid Bright         /* Make sure the re-added timer does not fire. In other words,
50195c05062SDavid Bright          * test that the event received above was the only event from
50295c05062SDavid Bright          * the add and re-add of the timer.
50395c05062SDavid Bright          */
50495c05062SDavid Bright         mssleep(2);
50595c05062SDavid Bright         test_no_kevents_quietly();
50695c05062SDavid Bright     }
50795c05062SDavid Bright 
50895c05062SDavid Bright     success();
50995c05062SDavid Bright }
51095c05062SDavid Bright 
511cb5fe245SEnji Cooper void
512*c9c283bdSAlex Richardson test_evfilt_timer(void)
513cb5fe245SEnji Cooper {
514cb5fe245SEnji Cooper     kqfd = kqueue();
515cb5fe245SEnji Cooper     test_kevent_timer_add();
516cb5fe245SEnji Cooper     test_kevent_timer_del();
517cb5fe245SEnji Cooper     test_kevent_timer_get();
518cb5fe245SEnji Cooper     test_oneshot();
519cb5fe245SEnji Cooper     test_periodic();
5202b34e843SKonstantin Belousov     test_abstime();
52195c05062SDavid Bright     test_update();
52295c05062SDavid Bright     test_update_equal();
52395c05062SDavid Bright     test_update_expired();
52495c05062SDavid Bright     test_update_timing();
52595c05062SDavid Bright     test_update_periodic();
526cb5fe245SEnji Cooper     disable_and_enable();
527cb5fe245SEnji Cooper     close(kqfd);
528cb5fe245SEnji Cooper }
529