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