xref: /openbsd/regress/sys/kern/kqueue/kqueue-timer.c (revision d89ec533)
1 /*	$OpenBSD: kqueue-timer.c,v 1.4 2021/06/12 13:30:14 visa Exp $	*/
2 /*
3  * Copyright (c) 2015 Bret Stephen Lambert <blambert@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/types.h>
19 #include <sys/time.h>
20 #include <sys/event.h>
21 
22 #include <err.h>
23 #include <errno.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28 
29 #include "main.h"
30 
31 int
32 do_timer(void)
33 {
34 	int kq, n;
35 	struct kevent ev;
36 	struct timespec ts;
37 
38 	ASS((kq = kqueue()) >= 0,
39 	    warn("kqueue"));
40 
41 	memset(&ev, 0, sizeof(ev));
42 	ev.filter = EVFILT_TIMER;
43 	ev.flags = EV_ADD | EV_ENABLE | EV_ONESHOT;
44 	ev.data = 500;			/* 1/2 second in ms */
45 
46 	n = kevent(kq, &ev, 1, NULL, 0, NULL);
47 	ASSX(n != -1);
48 
49 	ts.tv_sec = 2;			/* wait 2s for kqueue timeout */
50 	ts.tv_nsec = 0;
51 
52 	n = kevent(kq, NULL, 0, &ev, 1, &ts);
53 	ASSX(n == 1);
54 
55 	/* Now retry w/o EV_ONESHOT, as EV_CLEAR is implicit */
56 
57 	memset(&ev, 0, sizeof(ev));
58 	ev.filter = EVFILT_TIMER;
59 	ev.flags = EV_ADD | EV_ENABLE;
60 	ev.data = 500;			/* 1/2 second in ms */
61 
62 	n = kevent(kq, &ev, 1, NULL, 0, NULL);
63 	ASSX(n != -1);
64 
65 	ts.tv_sec = 2;			/* wait 2s for kqueue timeout */
66 	ts.tv_nsec = 0;
67 
68 	n = kevent(kq, NULL, 0, &ev, 1, &ts);
69 	ASSX(n == 1);
70 
71 	return (0);
72 }
73 
74 int
75 do_invalid_timer(void)
76 {
77 	int i, kq, n;
78 	struct kevent ev;
79 	struct timespec invalid_ts[3] = { {-1, 0}, {0, -1}, {0, 1000000000L} };
80 
81 	ASS((kq = kqueue()) >= 0,
82 	    warn("kqueue"));
83 
84 	memset(&ev, 0, sizeof(ev));
85 	ev.filter = EVFILT_TIMER;
86 	ev.flags = EV_ADD | EV_ENABLE;
87 	ev.data = 500;			/* 1/2 second in ms */
88 
89 	n = kevent(kq, &ev, 1, NULL, 0, NULL);
90 	ASSX(n != -1);
91 
92 	for (i = 0; i < 3; i++) {
93 		n = kevent(kq, NULL, 0, &ev, 1, &invalid_ts[i]);
94 		ASS(n == -1 && errno == EINVAL,
95 		    warn("kevent: timeout %lld %ld",
96 		    (long long)invalid_ts[i].tv_sec, invalid_ts[i].tv_nsec));
97 	}
98 
99 	return (0);
100 }
101 
102 int
103 do_reset_timer(void)
104 {
105 	int kq, msecs, n;
106 	struct kevent ev;
107 	struct timespec ts, start, end;
108 
109 	ASS((kq = kqueue()) >= 0,
110 	    warn("kqueue"));
111 
112 	clock_gettime(CLOCK_MONOTONIC, &start);
113 
114 	memset(&ev, 0, sizeof(ev));
115 	ev.filter = EVFILT_TIMER;
116 	ev.flags = EV_ADD | EV_ENABLE | EV_ONESHOT;
117 	ev.data = 10;
118 
119 	n = kevent(kq, &ev, 1, NULL, 0, NULL);
120 	ASSX(n != -1);
121 
122 	/* Let the timer expire. */
123 	usleep(100000);
124 
125 	/* Reset the expired timer. */
126 	ev.data = 60000;
127 	n = kevent(kq, &ev, 1, NULL, 0, NULL);
128 	ASSX(n != -1);
129 
130 	/* Check that no event is pending. */
131 	ts.tv_sec = 0;
132 	ts.tv_nsec = 0;
133 	n = kevent(kq, NULL, 0, &ev, 1, &ts);
134 	ASSX(n == 0);
135 
136 	/* Reset again for quick expiry. */
137 	memset(&ev, 0, sizeof(ev));
138 	ev.filter = EVFILT_TIMER;
139 	ev.flags = EV_ADD | EV_ENABLE | EV_ONESHOT;
140 	ev.data = 100;
141 	n = kevent(kq, &ev, 1, NULL, 0, NULL);
142 	ASSX(n != -1);
143 
144 	/* Wait for expiry. */
145 	n = kevent(kq, NULL, 0, &ev, 1, NULL);
146 	ASSX(n == 1);
147 
148 	clock_gettime(CLOCK_MONOTONIC, &end);
149 	timespecsub(&end, &start, &ts);
150 	msecs = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
151 	ASSX(msecs > 200);
152 	ASSX(msecs < 5000);	/* allow wide margin */
153 
154 	return (0);
155 }
156