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