]> git.saurik.com Git - apple/xnu.git/blame - tools/tests/kqueue_tests/kqueue_timer_tests.c
xnu-3248.30.4.tar.gz
[apple/xnu.git] / tools / tests / kqueue_tests / kqueue_timer_tests.c
CommitLineData
b0d623f7
A
1#include <sys/types.h>
2#include <sys/event.h>
3#include <sys/time.h>
4#include <assert.h>
5#include <errno.h>
6#include <stdio.h>
7#include <stdlib.h>
39236c6e 8#include <unistd.h>
b0d623f7
A
9
10int kq, passed, failed;
11
12/*
13 * Wait for given kevent, which should return in 'expected' usecs.
14 */
15int
16do_simple_kevent(struct kevent64_s *kev, uint64_t expected)
17{
18 int ret;
19 uint64_t elapsed_usecs, delta_usecs;
20 struct timespec timeout;
21 struct timeval before, after;
22
23 /* time out after 1 sec extra delay */
24 timeout.tv_sec = (expected / (1000 * 1000)) + 1;
25 timeout.tv_nsec = (expected % (1000 * 1000)) * 1000;
26
27 /* measure time for the kevent */
28 gettimeofday(&before, NULL);
29 ret = kevent64(kq, kev, 1, kev, 1, 0, &timeout);
30 gettimeofday(&after, NULL);
31
32 if (ret < 1 || (kev->flags & EV_ERROR)) {
33 printf("\tfailure: kevent returned %d, error %d\n", ret,
34 (ret == -1 ? errno : (int) kev->data));
35 return 0;
36 }
37
38 /* did it work? */
39 elapsed_usecs = (after.tv_sec - before.tv_sec) * (1000 * 1000) +
40 (after.tv_usec - before.tv_usec);
41 delta_usecs = abs(elapsed_usecs - (expected));
42
43 /* failure if we're 30% off, or 50 mics late */
44 if (delta_usecs > (30 * expected / 100.0) && delta_usecs > 50) {
45 printf("\tfailure: expected %lld usec, measured %lld usec.\n",
46 expected, elapsed_usecs);
47 return 0;
48 } else {
49 printf("\tsuccess.\n");
50 return 1;
51 }
52}
53
54void
55test_absolute_kevent(int time, int scale)
56{
57 struct timeval tv;
58 struct kevent64_s kev;
59 uint64_t nowus, expected, deadline;
60 int ret;
61 int timescale = 0;
62
63 gettimeofday(&tv, NULL);
64 nowus = tv.tv_sec * (1000 * 1000LL) + tv.tv_usec;
65
66 switch (scale) {
67 case NOTE_SECONDS:
68 printf("Testing %d sec absolute timer...\n", time);
69 timescale = 1000 * 1000;
70 break;
71 case NOTE_USECONDS:
72 printf("Testing %d usec absolute timer...\n", time);
73 timescale = 1;
74 break;
75 case 0:
76 printf("Testing %d msec absolute timer...\n", time);
77 timescale = 1000;
78 break;
79 default:
80 printf("Failure: scale 0x%x not recognized.\n", scale);
81 return;
82 }
83
84 expected = time * timescale;
85 deadline = nowus / timescale + time;
86
87 /* deadlines in the past should fire immediately */
88 if (time < 0)
89 expected = 0;
90
91 EV_SET64(&kev, 1, EVFILT_TIMER, EV_ADD,
92 NOTE_ABSOLUTE | scale, deadline, 0,0,0);
93 ret = do_simple_kevent(&kev, expected);
94
95 if (ret)
96 passed++;
97 else
98 failed++;
99}
100
101void
102test_oneshot_kevent(int time, int scale)
103{
104 int ret;
105 uint64_t expected = 0;
106 struct kevent64_s kev;
107
108 switch (scale) {
109 case NOTE_SECONDS:
110 printf("Testing %d sec interval timer...\n", time);
111 expected = time * (1000 * 1000);
112 break;
113 case NOTE_USECONDS:
114 printf("Testing %d usec interval timer...\n", time);
115 expected = time;
116 break;
117 case NOTE_NSECONDS:
118 printf("Testing %d nsec interval timer...\n", time);
119 expected = time / 1000;
120 break;
121 case 0:
122 printf("Testing %d msec interval timer...\n", time);
123 expected = time * 1000;
124 break;
125 default:
126 printf("Failure: scale 0x%x not recognized.\n", scale);
127 return;
128 }
129
130 /* deadlines in the past should fire immediately */
131 if (time < 0)
132 expected = 0;
133
134 EV_SET64(&kev, 2, EVFILT_TIMER, EV_ADD | EV_ONESHOT, scale, time,
135 0, 0, 0);
136 ret = do_simple_kevent(&kev, expected);
137
138 if (ret)
139 passed++;
140 else
141 failed++;
142
143}
144
145void
146test_repeating_kevent(int usec)
147{
148 struct kevent64_s kev;
149 int expected_pops, ret;
150
151 expected_pops = 1000 * 1000 / usec;
152 printf("Testing repeating kevent for %d pops in a second...\n",
153 expected_pops);
154
155 EV_SET64(&kev, 3, EVFILT_TIMER, EV_ADD, NOTE_USECONDS, usec, 0, 0, 0);
156 ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL);
157 if (ret != 0) {
158 printf("\tfailure: kevent64 returned %d\n", ret);
159 failed++;
160 return;
161 }
162
163 /* sleep 1 second */
164 usleep(1000 * 1000);
165 ret = kevent64(kq, NULL, 0, &kev, 1, 0, NULL);
166 if (ret != 1 || (kev.flags & EV_ERROR)) {
167 printf("\tfailure: kevent64 returned %d\n", ret);
168 failed++;
169 return;
170 }
171
172 /* check how many times the timer fired: within 5%? */
173 if (kev.data > expected_pops + (expected_pops / 20) ||
174 kev.data < expected_pops - (expected_pops / 20)) {
175 printf("\tfailure: saw %lld pops.\n", kev.data);
176 failed++;
177 } else {
178 printf("\tsuccess: saw %lld pops.\n", kev.data);
179 passed++;
180 }
181
182 EV_SET64(&kev, 3, EVFILT_TIMER, EV_DELETE, 0, 0, 0, 0, 0);
183 ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL);
184 if (ret != 0) {
185 printf("\tfailed to stop repeating timer: %d\n", ret);
186 }
187}
188
39236c6e 189void
b0d623f7
A
190test_updated_kevent(int first, int second)
191{
192 struct kevent64_s kev;
193 int ret;
194
195 printf("Testing update from %d to %d msecs...\n", first, second);
196
197 EV_SET64(&kev, 4, EVFILT_TIMER, EV_ADD|EV_ONESHOT, 0, first, 0, 0, 0);
198 ret = kevent64(kq, &kev, 1, NULL, 0, 0, NULL);
199 if (ret != 0) {
200 printf("\tfailure: initial kevent returned %d\n", ret);
201 failed++;
202 return;
203 }
204
205 EV_SET64(&kev, 4, EVFILT_TIMER, EV_ONESHOT, 0, second, 0, 0, 0);
206 if (second < 0)
207 second = 0;
208 ret = do_simple_kevent(&kev, second * 1000);
209 if (ret)
210 passed++;
211 else
212 failed++;
213}
214
215int
216main(void)
217{
218 struct timeval tv;
219 struct kevent64_s kev;
220 uint64_t nowms, deadline;
221
222 kq = kqueue();
223 assert(kq > 0);
224 passed = 0;
225 failed = 0;
226
227 test_absolute_kevent(100, 0);
228 test_absolute_kevent(200, 0);
229 test_absolute_kevent(300, 0);
230 test_absolute_kevent(1000, 0);
231 test_absolute_kevent(500, NOTE_USECONDS);
232 test_absolute_kevent(100, NOTE_USECONDS);
233 test_absolute_kevent(5, NOTE_SECONDS);
234 test_absolute_kevent(-1000, 0);
235
236 test_oneshot_kevent(1, NOTE_SECONDS);
237 test_oneshot_kevent(10, 0);
238 test_oneshot_kevent(200, NOTE_USECONDS);
239 test_oneshot_kevent(300000, NOTE_NSECONDS);
240 test_oneshot_kevent(-1, NOTE_SECONDS);
241
242 test_repeating_kevent(100 * 1000);
243 test_repeating_kevent(5 * 1000);
244 test_repeating_kevent(200);
245 test_repeating_kevent(50);
246 test_repeating_kevent(10);
247
248 test_updated_kevent(1000, 2000);
249 test_updated_kevent(2000, 1000);
250 test_updated_kevent(1000, -1);
251
252 printf("\nFinished: %d tests passed, %d failed.\n", passed, failed);
253
254 exit(EXIT_SUCCESS);
255}