xref: /freebsd/tests/sys/kqueue/libkqueue/timer.c (revision 95c05062ec15cf323488d4c5e1986f5866bf7464)
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 
22*95c05062SDavid Bright #define	MILLION 1000000
23*95c05062SDavid Bright #define	THOUSAND 1000
24*95c05062SDavid Bright #define	SEC_TO_MS(t) ((t) * THOUSAND)	/* Convert seconds to milliseconds. */
25*95c05062SDavid Bright #define	SEC_TO_US(t) ((t) * MILLION)	/* Convert seconds to microseconds. */
26*95c05062SDavid Bright #define	MS_TO_US(t)  ((t) * THOUSAND)	/* Convert milliseconds to microseconds. */
27*95c05062SDavid Bright #define	US_TO_NS(t)  ((t) * THOUSAND)	/* Convert microseconds to nanoseconds. */
28*95c05062SDavid Bright 
29cb5fe245SEnji Cooper int kqfd;
30cb5fe245SEnji Cooper 
31*95c05062SDavid Bright /* Get the current time with microsecond precision. Used for
32*95c05062SDavid Bright  * sub-second timing to make some timer tests run faster.
33*95c05062SDavid Bright  */
34*95c05062SDavid Bright static long
35*95c05062SDavid Bright now(void)
36*95c05062SDavid Bright {
37*95c05062SDavid Bright 
38*95c05062SDavid Bright 	struct timeval tv;
39*95c05062SDavid Bright 
40*95c05062SDavid Bright 	gettimeofday(&tv, NULL);
41*95c05062SDavid Bright 	return SEC_TO_US(tv.tv_sec) + tv.tv_usec;
42*95c05062SDavid Bright }
43*95c05062SDavid Bright 
44*95c05062SDavid Bright /* Sleep for a given number of milliseconds. The timeout is assumed to
45*95c05062SDavid Bright  * be less than 1 second.
46*95c05062SDavid Bright  */
47*95c05062SDavid Bright void
48*95c05062SDavid Bright mssleep(int t)
49*95c05062SDavid Bright {
50*95c05062SDavid Bright 
51*95c05062SDavid Bright 	struct timespec stime = {
52*95c05062SDavid Bright 	    .tv_sec = 0,
53*95c05062SDavid Bright 	    .tv_nsec = US_TO_NS(MS_TO_US(t)),
54*95c05062SDavid Bright 	};
55*95c05062SDavid Bright 
56*95c05062SDavid Bright 	nanosleep(&stime, NULL);
57*95c05062SDavid Bright }
58*95c05062SDavid Bright 
59*95c05062SDavid Bright /* Sleep for a given number of microseconds. The timeout is assumed to
60*95c05062SDavid Bright  * be less than 1 second.
61*95c05062SDavid Bright  */
62*95c05062SDavid Bright void
63*95c05062SDavid Bright ussleep(int t)
64*95c05062SDavid Bright {
65*95c05062SDavid Bright 
66*95c05062SDavid Bright 	struct timespec stime = {
67*95c05062SDavid Bright 	    .tv_sec = 0,
68*95c05062SDavid Bright 	    .tv_nsec = US_TO_NS(t),
69*95c05062SDavid Bright 	};
70*95c05062SDavid Bright 
71*95c05062SDavid Bright 	nanosleep(&stime, NULL);
72*95c05062SDavid Bright }
73*95c05062SDavid Bright 
74cb5fe245SEnji Cooper void
75cb5fe245SEnji Cooper test_kevent_timer_add(void)
76cb5fe245SEnji Cooper {
77cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)";
78cb5fe245SEnji Cooper     struct kevent kev;
79cb5fe245SEnji Cooper 
80cb5fe245SEnji Cooper     test_begin(test_id);
81cb5fe245SEnji Cooper 
82cb5fe245SEnji Cooper     EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
83cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
84cb5fe245SEnji Cooper         err(1, "%s", test_id);
85cb5fe245SEnji Cooper 
86cb5fe245SEnji Cooper     success();
87cb5fe245SEnji Cooper }
88cb5fe245SEnji Cooper 
89cb5fe245SEnji Cooper void
90cb5fe245SEnji Cooper test_kevent_timer_del(void)
91cb5fe245SEnji Cooper {
92cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)";
93cb5fe245SEnji Cooper     struct kevent kev;
94cb5fe245SEnji Cooper 
95cb5fe245SEnji Cooper     test_begin(test_id);
96cb5fe245SEnji Cooper 
97cb5fe245SEnji Cooper     EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
98cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
99cb5fe245SEnji Cooper         err(1, "%s", test_id);
100cb5fe245SEnji Cooper 
101cb5fe245SEnji Cooper     test_no_kevents();
102cb5fe245SEnji Cooper 
103cb5fe245SEnji Cooper     success();
104cb5fe245SEnji Cooper }
105cb5fe245SEnji Cooper 
106cb5fe245SEnji Cooper void
107cb5fe245SEnji Cooper test_kevent_timer_get(void)
108cb5fe245SEnji Cooper {
109cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, wait)";
110cb5fe245SEnji Cooper     struct kevent kev;
111cb5fe245SEnji Cooper 
112cb5fe245SEnji Cooper     test_begin(test_id);
113cb5fe245SEnji Cooper 
114cb5fe245SEnji Cooper     EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
115cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
116cb5fe245SEnji Cooper         err(1, "%s", test_id);
117cb5fe245SEnji Cooper 
118cb5fe245SEnji Cooper     kev.flags |= EV_CLEAR;
119cb5fe245SEnji Cooper     kev.data = 1;
120cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
121cb5fe245SEnji Cooper 
122cb5fe245SEnji Cooper     EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
123cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
124cb5fe245SEnji Cooper         err(1, "%s", test_id);
125cb5fe245SEnji Cooper 
126cb5fe245SEnji Cooper     success();
127cb5fe245SEnji Cooper }
128cb5fe245SEnji Cooper 
129cb5fe245SEnji Cooper static void
130cb5fe245SEnji Cooper test_oneshot(void)
131cb5fe245SEnji Cooper {
132cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)";
133cb5fe245SEnji Cooper     struct kevent kev;
134cb5fe245SEnji Cooper 
135cb5fe245SEnji Cooper     test_begin(test_id);
136cb5fe245SEnji Cooper 
137cb5fe245SEnji Cooper     test_no_kevents();
138cb5fe245SEnji Cooper 
139cb5fe245SEnji Cooper     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL);
140cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
141cb5fe245SEnji Cooper         err(1, "%s", test_id);
142cb5fe245SEnji Cooper 
143cb5fe245SEnji Cooper     /* Retrieve the event */
144cb5fe245SEnji Cooper     kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
145cb5fe245SEnji Cooper     kev.data = 1;
146cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
147cb5fe245SEnji Cooper 
148cb5fe245SEnji Cooper     /* Check if the event occurs again */
149cb5fe245SEnji Cooper     sleep(3);
150cb5fe245SEnji Cooper     test_no_kevents();
151cb5fe245SEnji Cooper 
152cb5fe245SEnji Cooper 
153cb5fe245SEnji Cooper     success();
154cb5fe245SEnji Cooper }
155cb5fe245SEnji Cooper 
156cb5fe245SEnji Cooper static void
157cb5fe245SEnji Cooper test_periodic(void)
158cb5fe245SEnji Cooper {
159cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, periodic)";
160cb5fe245SEnji Cooper     struct kevent kev;
161cb5fe245SEnji Cooper 
162cb5fe245SEnji Cooper     test_begin(test_id);
163cb5fe245SEnji Cooper 
164cb5fe245SEnji Cooper     test_no_kevents();
165cb5fe245SEnji Cooper 
166cb5fe245SEnji Cooper     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL);
167cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
168cb5fe245SEnji Cooper         err(1, "%s", test_id);
169cb5fe245SEnji Cooper 
170cb5fe245SEnji Cooper     /* Retrieve the event */
171cb5fe245SEnji Cooper     kev.flags = EV_ADD | EV_CLEAR;
172cb5fe245SEnji Cooper     kev.data = 1;
173cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
174cb5fe245SEnji Cooper 
175cb5fe245SEnji Cooper     /* Check if the event occurs again */
176cb5fe245SEnji Cooper     sleep(1);
177cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
178cb5fe245SEnji Cooper 
179cb5fe245SEnji Cooper     /* Delete the event */
180cb5fe245SEnji Cooper     kev.flags = EV_DELETE;
181cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
182cb5fe245SEnji Cooper         err(1, "%s", test_id);
183cb5fe245SEnji Cooper 
184cb5fe245SEnji Cooper     success();
185cb5fe245SEnji Cooper }
186cb5fe245SEnji Cooper 
187cb5fe245SEnji Cooper static void
188cb5fe245SEnji Cooper disable_and_enable(void)
189cb5fe245SEnji Cooper {
190cb5fe245SEnji Cooper     const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
191cb5fe245SEnji Cooper     struct kevent kev;
192cb5fe245SEnji Cooper 
193cb5fe245SEnji Cooper     test_begin(test_id);
194cb5fe245SEnji Cooper 
195cb5fe245SEnji Cooper     test_no_kevents();
196cb5fe245SEnji Cooper 
197cb5fe245SEnji Cooper     /* Add the watch and immediately disable it */
198cb5fe245SEnji Cooper     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL);
199cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
200cb5fe245SEnji Cooper         err(1, "%s", test_id);
201cb5fe245SEnji Cooper     kev.flags = EV_DISABLE;
202cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
203cb5fe245SEnji Cooper         err(1, "%s", test_id);
204cb5fe245SEnji Cooper     test_no_kevents();
205cb5fe245SEnji Cooper 
206cb5fe245SEnji Cooper     /* Re-enable and check again */
207cb5fe245SEnji Cooper     kev.flags = EV_ENABLE;
208cb5fe245SEnji Cooper     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
209cb5fe245SEnji Cooper         err(1, "%s", test_id);
210cb5fe245SEnji Cooper 
211cb5fe245SEnji Cooper     kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
212cb5fe245SEnji Cooper     kev.data = 1;
213cb5fe245SEnji Cooper     kevent_cmp(&kev, kevent_get(kqfd));
214cb5fe245SEnji Cooper 
215cb5fe245SEnji Cooper     success();
216cb5fe245SEnji Cooper }
217cb5fe245SEnji Cooper 
2182b34e843SKonstantin Belousov static void
2192b34e843SKonstantin Belousov test_abstime(void)
2202b34e843SKonstantin Belousov {
2212b34e843SKonstantin Belousov     const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)";
2222b34e843SKonstantin Belousov     struct kevent kev;
2232b34e843SKonstantin Belousov     time_t when;
2242b34e843SKonstantin Belousov     const int timeout = 3;
2252b34e843SKonstantin Belousov 
2262b34e843SKonstantin Belousov     test_begin(test_id);
2272b34e843SKonstantin Belousov 
2282b34e843SKonstantin Belousov     test_no_kevents();
2292b34e843SKonstantin Belousov 
2302b34e843SKonstantin Belousov     when = time(NULL);
2312b34e843SKonstantin Belousov     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
2322b34e843SKonstantin Belousov       NOTE_ABSTIME | NOTE_SECONDS, when + timeout, NULL);
2332b34e843SKonstantin Belousov     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
2342b34e843SKonstantin Belousov         err(1, "%s", test_id);
2352b34e843SKonstantin Belousov 
2362b34e843SKonstantin Belousov     /* Retrieve the event */
2372b34e843SKonstantin Belousov     kev.flags = EV_ADD | EV_ONESHOT;
2382b34e843SKonstantin Belousov     kev.data = 1;
2392b34e843SKonstantin Belousov     kev.fflags = 0;
2402b34e843SKonstantin Belousov     kevent_cmp(&kev, kevent_get(kqfd));
2412b34e843SKonstantin Belousov     if (time(NULL) < when + timeout)
242*95c05062SDavid Bright 	err(1, "too early %jd %jd", time(NULL), when + timeout);
2432b34e843SKonstantin Belousov 
2442b34e843SKonstantin Belousov     /* Check if the event occurs again */
2452b34e843SKonstantin Belousov     sleep(3);
2462b34e843SKonstantin Belousov     test_no_kevents();
2472b34e843SKonstantin Belousov 
2482b34e843SKonstantin Belousov     success();
2492b34e843SKonstantin Belousov }
2502b34e843SKonstantin Belousov 
251*95c05062SDavid Bright static void
252*95c05062SDavid Bright test_update(void)
253*95c05062SDavid Bright {
254*95c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)";
255*95c05062SDavid Bright     struct kevent kev;
256*95c05062SDavid Bright     long elapsed;
257*95c05062SDavid Bright     long start;
258*95c05062SDavid Bright 
259*95c05062SDavid Bright     test_begin(test_id);
260*95c05062SDavid Bright 
261*95c05062SDavid Bright     test_no_kevents();
262*95c05062SDavid Bright 
263*95c05062SDavid Bright     /* First set the timer to 1 second */
264*95c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
265*95c05062SDavid Bright 	NOTE_USECONDS, SEC_TO_US(1), (void *)1);
266*95c05062SDavid Bright     start = now();
267*95c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
268*95c05062SDavid Bright 	err(1, "%s", test_id);
269*95c05062SDavid Bright 
270*95c05062SDavid Bright     /* Now reduce the timer to 1 ms */
271*95c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
272*95c05062SDavid Bright 	NOTE_USECONDS, MS_TO_US(1), (void *)2);
273*95c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
274*95c05062SDavid Bright 	err(1, "%s", test_id);
275*95c05062SDavid Bright 
276*95c05062SDavid Bright     /* Wait for the event */
277*95c05062SDavid Bright     kev.flags |= EV_CLEAR;
278*95c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
279*95c05062SDavid Bright     kev.data = 1;
280*95c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
281*95c05062SDavid Bright     elapsed = now() - start;
282*95c05062SDavid Bright 
283*95c05062SDavid Bright     /* Check that the timer expired after at least 1 ms, but less than
284*95c05062SDavid Bright      * 1 second. This check is to make sure that the original 1 second
285*95c05062SDavid Bright      * timeout was not used.
286*95c05062SDavid Bright      */
287*95c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
288*95c05062SDavid Bright     if (elapsed < MS_TO_US(1))
289*95c05062SDavid Bright 	errx(1, "early timer expiration: %ld us", elapsed);
290*95c05062SDavid Bright     if (elapsed > SEC_TO_US(1))
291*95c05062SDavid Bright 	errx(1, "late timer expiration: %ld us", elapsed);
292*95c05062SDavid Bright 
293*95c05062SDavid Bright     success();
294*95c05062SDavid Bright }
295*95c05062SDavid Bright 
296*95c05062SDavid Bright static void
297*95c05062SDavid Bright test_update_equal(void)
298*95c05062SDavid Bright {
299*95c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)";
300*95c05062SDavid Bright     struct kevent kev;
301*95c05062SDavid Bright     long elapsed;
302*95c05062SDavid Bright     long start;
303*95c05062SDavid Bright 
304*95c05062SDavid Bright     test_begin(test_id);
305*95c05062SDavid Bright 
306*95c05062SDavid Bright     test_no_kevents();
307*95c05062SDavid Bright 
308*95c05062SDavid Bright     /* First set the timer to 1 ms */
309*95c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
310*95c05062SDavid Bright 	NOTE_USECONDS, MS_TO_US(1), NULL);
311*95c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
312*95c05062SDavid Bright 	err(1, "%s", test_id);
313*95c05062SDavid Bright 
314*95c05062SDavid Bright     /* Sleep for a significant fraction of the timeout. */
315*95c05062SDavid Bright     ussleep(600);
316*95c05062SDavid Bright 
317*95c05062SDavid Bright     /* Now re-add the timer with the same parameters */
318*95c05062SDavid Bright     start = now();
319*95c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
320*95c05062SDavid Bright 	err(1, "%s", test_id);
321*95c05062SDavid Bright 
322*95c05062SDavid Bright     /* Wait for the event */
323*95c05062SDavid Bright     kev.flags |= EV_CLEAR;
324*95c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
325*95c05062SDavid Bright     kev.data = 1;
326*95c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
327*95c05062SDavid Bright     elapsed = now() - start;
328*95c05062SDavid Bright 
329*95c05062SDavid Bright     /* Check that the timer expired after at least 1 ms. This check is
330*95c05062SDavid Bright      * to make sure that the timer re-started and that the event is
331*95c05062SDavid Bright      * not from the original add of the timer.
332*95c05062SDavid Bright      */
333*95c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
334*95c05062SDavid Bright     if (elapsed < MS_TO_US(1))
335*95c05062SDavid Bright 	errx(1, "early timer expiration: %ld us", elapsed);
336*95c05062SDavid Bright 
337*95c05062SDavid Bright     success();
338*95c05062SDavid Bright }
339*95c05062SDavid Bright 
340*95c05062SDavid Bright static void
341*95c05062SDavid Bright test_update_expired(void)
342*95c05062SDavid Bright {
343*95c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)";
344*95c05062SDavid Bright     struct kevent kev;
345*95c05062SDavid Bright     long elapsed;
346*95c05062SDavid Bright     long start;
347*95c05062SDavid Bright 
348*95c05062SDavid Bright     test_begin(test_id);
349*95c05062SDavid Bright 
350*95c05062SDavid Bright     test_no_kevents();
351*95c05062SDavid Bright 
352*95c05062SDavid Bright     /* Set the timer to 1ms */
353*95c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
354*95c05062SDavid Bright 	NOTE_USECONDS, MS_TO_US(1), NULL);
355*95c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
356*95c05062SDavid Bright 	err(1, "%s", test_id);
357*95c05062SDavid Bright 
358*95c05062SDavid Bright     /* Wait for 2 ms to give the timer plenty of time to expire. */
359*95c05062SDavid Bright     mssleep(2);
360*95c05062SDavid Bright 
361*95c05062SDavid Bright     /* Now re-add the timer */
362*95c05062SDavid Bright     start = now();
363*95c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
364*95c05062SDavid Bright 	err(1, "%s", test_id);
365*95c05062SDavid Bright 
366*95c05062SDavid Bright     /* Wait for the event */
367*95c05062SDavid Bright     kev.flags |= EV_CLEAR;
368*95c05062SDavid Bright     kev.fflags &= ~NOTE_USECONDS;
369*95c05062SDavid Bright     kev.data = 1;
370*95c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
371*95c05062SDavid Bright     elapsed = now() - start;
372*95c05062SDavid Bright 
373*95c05062SDavid Bright     /* Check that the timer expired after at least 1 ms.  This check
374*95c05062SDavid Bright      * is to make sure that the timer re-started and that the event is
375*95c05062SDavid Bright      * not from the original add (and expiration) of the timer.
376*95c05062SDavid Bright      */
377*95c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
378*95c05062SDavid Bright     if (elapsed < MS_TO_US(1))
379*95c05062SDavid Bright 	errx(1, "early timer expiration: %ld us", elapsed);
380*95c05062SDavid Bright 
381*95c05062SDavid Bright     /* Make sure the re-added timer does not fire. In other words,
382*95c05062SDavid Bright      * test that the event received above was the only event from the
383*95c05062SDavid Bright      * add and re-add of the timer.
384*95c05062SDavid Bright      */
385*95c05062SDavid Bright     mssleep(2);
386*95c05062SDavid Bright     test_no_kevents();
387*95c05062SDavid Bright 
388*95c05062SDavid Bright     success();
389*95c05062SDavid Bright }
390*95c05062SDavid Bright 
391*95c05062SDavid Bright static void
392*95c05062SDavid Bright test_update_periodic(void)
393*95c05062SDavid Bright {
394*95c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)";
395*95c05062SDavid Bright     struct kevent kev;
396*95c05062SDavid Bright     long elapsed;
397*95c05062SDavid Bright     long start;
398*95c05062SDavid Bright     long stop;
399*95c05062SDavid Bright 
400*95c05062SDavid Bright     test_begin(test_id);
401*95c05062SDavid Bright 
402*95c05062SDavid Bright     test_no_kevents();
403*95c05062SDavid Bright 
404*95c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL);
405*95c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
406*95c05062SDavid Bright 	err(1, "%s", test_id);
407*95c05062SDavid Bright 
408*95c05062SDavid Bright     /* Retrieve the event */
409*95c05062SDavid Bright     kev.flags = EV_ADD | EV_CLEAR;
410*95c05062SDavid Bright     kev.data = 1;
411*95c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
412*95c05062SDavid Bright 
413*95c05062SDavid Bright     /* Check if the event occurs again */
414*95c05062SDavid Bright     sleep(1);
415*95c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
416*95c05062SDavid Bright 
417*95c05062SDavid Bright     /* Re-add with new timeout. */
418*95c05062SDavid Bright     EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL);
419*95c05062SDavid Bright     start = now();
420*95c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
421*95c05062SDavid Bright 	err(1, "%s", test_id);
422*95c05062SDavid Bright 
423*95c05062SDavid Bright     /* Retrieve the event */
424*95c05062SDavid Bright     kev.flags = EV_ADD | EV_CLEAR;
425*95c05062SDavid Bright     kev.data = 1;
426*95c05062SDavid Bright     kevent_cmp(&kev, kevent_get(kqfd));
427*95c05062SDavid Bright 
428*95c05062SDavid Bright     stop = now();
429*95c05062SDavid Bright     elapsed = stop - start;
430*95c05062SDavid Bright 
431*95c05062SDavid Bright     /* Check that the timer expired after at least 2 ms.
432*95c05062SDavid Bright      */
433*95c05062SDavid Bright     printf("timer expired after %ld us\n", elapsed);
434*95c05062SDavid Bright     if (elapsed < MS_TO_US(2))
435*95c05062SDavid Bright 	errx(1, "early timer expiration: %ld us", elapsed);
436*95c05062SDavid Bright 
437*95c05062SDavid Bright     /* Delete the event */
438*95c05062SDavid Bright     kev.flags = EV_DELETE;
439*95c05062SDavid Bright     if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
440*95c05062SDavid Bright 	err(1, "%s", test_id);
441*95c05062SDavid Bright 
442*95c05062SDavid Bright     success();
443*95c05062SDavid Bright }
444*95c05062SDavid Bright 
445*95c05062SDavid Bright static void
446*95c05062SDavid Bright test_update_timing(void)
447*95c05062SDavid Bright {
448*95c05062SDavid Bright #define	MIN_SLEEP 500
449*95c05062SDavid Bright #define	MAX_SLEEP 1500
450*95c05062SDavid Bright     const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)";
451*95c05062SDavid Bright     struct kevent kev;
452*95c05062SDavid Bright     int iteration;
453*95c05062SDavid Bright     int sleeptime;
454*95c05062SDavid Bright     long elapsed;
455*95c05062SDavid Bright     long start;
456*95c05062SDavid Bright     long stop;
457*95c05062SDavid Bright 
458*95c05062SDavid Bright     test_begin(test_id);
459*95c05062SDavid Bright 
460*95c05062SDavid Bright     test_no_kevents();
461*95c05062SDavid Bright 
462*95c05062SDavid Bright     /* Re-try the update tests with a variety of delays between the
463*95c05062SDavid Bright      * original timer activation and the update of the timer. The goal
464*95c05062SDavid Bright      * is to show that in all cases the only timer event that is
465*95c05062SDavid Bright      * received is from the update and not the original timer add.
466*95c05062SDavid Bright      */
467*95c05062SDavid Bright     for (sleeptime = MIN_SLEEP, iteration = 1;
468*95c05062SDavid Bright 	 sleeptime < MAX_SLEEP;
469*95c05062SDavid Bright 	 ++sleeptime, ++iteration) {
470*95c05062SDavid Bright 
471*95c05062SDavid Bright 	/* First set the timer to 1 ms */
472*95c05062SDavid Bright 	EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT,
473*95c05062SDavid Bright 	    NOTE_USECONDS, MS_TO_US(1), NULL);
474*95c05062SDavid Bright 	if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
475*95c05062SDavid Bright 	    err(1, "%s", test_id);
476*95c05062SDavid Bright 
477*95c05062SDavid Bright 	/* Delay; the delay ranges from less than to greater than the
478*95c05062SDavid Bright 	 * timer period.
479*95c05062SDavid Bright 	 */
480*95c05062SDavid Bright 	ussleep(sleeptime);
481*95c05062SDavid Bright 
482*95c05062SDavid Bright 	/* Now re-add the timer with the same parameters */
483*95c05062SDavid Bright 	start = now();
484*95c05062SDavid Bright 	if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
485*95c05062SDavid Bright 	    err(1, "%s", test_id);
486*95c05062SDavid Bright 
487*95c05062SDavid Bright 	/* Wait for the event */
488*95c05062SDavid Bright 	kev.flags |= EV_CLEAR;
489*95c05062SDavid Bright 	kev.fflags &= ~NOTE_USECONDS;
490*95c05062SDavid Bright 	kev.data = 1;
491*95c05062SDavid Bright 	kevent_cmp(&kev, kevent_get(kqfd));
492*95c05062SDavid Bright 	stop = now();
493*95c05062SDavid Bright 	elapsed = stop - start;
494*95c05062SDavid Bright 
495*95c05062SDavid Bright 	/* Check that the timer expired after at least 1 ms. This
496*95c05062SDavid Bright 	 * check is to make sure that the timer re-started and that
497*95c05062SDavid Bright 	 * the event is not from the original add of the timer.
498*95c05062SDavid Bright 	 */
499*95c05062SDavid Bright 	if (elapsed < MS_TO_US(1))
500*95c05062SDavid Bright 	    errx(1, "early timer expiration: %ld us", elapsed);
501*95c05062SDavid Bright 
502*95c05062SDavid Bright 	/* Make sure the re-added timer does not fire. In other words,
503*95c05062SDavid Bright 	 * test that the event received above was the only event from
504*95c05062SDavid Bright 	 * the add and re-add of the timer.
505*95c05062SDavid Bright 	 */
506*95c05062SDavid Bright 	mssleep(2);
507*95c05062SDavid Bright 	test_no_kevents_quietly();
508*95c05062SDavid Bright     }
509*95c05062SDavid Bright 
510*95c05062SDavid Bright     success();
511*95c05062SDavid Bright }
512*95c05062SDavid Bright 
513cb5fe245SEnji Cooper void
514cb5fe245SEnji Cooper test_evfilt_timer()
515cb5fe245SEnji Cooper {
516cb5fe245SEnji Cooper 	kqfd = kqueue();
517cb5fe245SEnji Cooper 	test_kevent_timer_add();
518cb5fe245SEnji Cooper 	test_kevent_timer_del();
519cb5fe245SEnji Cooper 	test_kevent_timer_get();
520cb5fe245SEnji Cooper 	test_oneshot();
521cb5fe245SEnji Cooper 	test_periodic();
5222b34e843SKonstantin Belousov 	test_abstime();
523*95c05062SDavid Bright 	test_update();
524*95c05062SDavid Bright 	test_update_equal();
525*95c05062SDavid Bright 	test_update_expired();
526*95c05062SDavid Bright 	test_update_timing();
527*95c05062SDavid Bright 	test_update_periodic();
528cb5fe245SEnji Cooper 	disable_and_enable();
529cb5fe245SEnji Cooper 	close(kqfd);
530cb5fe245SEnji Cooper }
531