10 #include <mach/task.h>
12 #include <TargetConditionals.h>
13 #include <darwintest.h>
16 #define NOTE_MACHTIME 0x00000100
19 static mach_timebase_info_data_t timebase_info
;
21 static uint64_t nanos_to_abs(uint64_t nanos
) { return nanos
* timebase_info
.denom
/ timebase_info
.numer
; }
22 static uint64_t abs_to_nanos(uint64_t abs
) { return abs
* timebase_info
.numer
/ timebase_info
.denom
; }
24 static int kq
, passed
, failed
;
26 static struct timespec failure_timeout
= { .tv_sec
= 10, .tv_nsec
= 0 };
29 * Wait for given kevent, which should return in 'expected' usecs.
32 do_simple_kevent(struct kevent64_s
*kev
, uint64_t expected
)
35 int64_t elapsed_usecs
;
37 struct timespec timeout
;
38 struct timeval before
, after
;
40 /* time out after 1 sec extra delay */
41 timeout
.tv_sec
= (expected
/ USEC_PER_SEC
) + 1;
42 timeout
.tv_nsec
= (expected
% USEC_PER_SEC
) * 1000;
46 /* measure time for the kevent */
47 gettimeofday(&before
, NULL
);
48 ret
= kevent64(kq
, kev
, 1, kev
, 1, 0, &timeout
);
49 gettimeofday(&after
, NULL
);
51 if (ret
< 1 || (kev
->flags
& EV_ERROR
)) {
52 T_LOG("%s() failure: kevent returned %d, error %d\n", __func__
, ret
,
53 (ret
== -1 ? errno
: (int) kev
->data
));
60 elapsed_usecs
= (after
.tv_sec
- before
.tv_sec
) * (int64_t)USEC_PER_SEC
+
61 (after
.tv_usec
- before
.tv_usec
);
62 delta_usecs
= (uint64_t)llabs(elapsed_usecs
- ((int64_t)expected
));
64 /* failure if we're 30% off, or 50 mics late */
65 if (delta_usecs
> (30 * expected
/ 100.0) && delta_usecs
> 50) {
66 T_LOG("\tfailure: expected %lld usec, measured %lld usec.\n",
67 expected
, elapsed_usecs
);
70 T_LOG("\tsuccess, measured %lld usec.\n", elapsed_usecs
);
76 test_absolute_kevent(int time
, int scale
)
79 struct kevent64_s kev
;
80 uint64_t nowus
, expected
, timescale
= 0;
84 gettimeofday(&tv
, NULL
);
85 nowus
= (uint64_t)tv
.tv_sec
* USEC_PER_SEC
+ (uint64_t)tv
.tv_usec
;
91 T_LOG("Testing %d MATUs absolute timer...\n", time
);
94 T_LOG("Testing %d sec absolute timer...\n", time
);
95 timescale
= USEC_PER_SEC
;
98 T_LOG("Testing %d usec absolute timer...\n", time
);
102 T_LOG("Testing %d msec absolute timer...\n", time
);
106 T_FAIL("Failure: scale 0x%x not recognized.\n", scale
);
112 if (scale
== NOTE_MACHTIME
) {
113 expected
= abs_to_nanos((uint64_t)time
) / NSEC_PER_USEC
;
114 deadline
= (int64_t)mach_absolute_time() + time
;
116 expected
= (uint64_t)time
* timescale
;
117 deadline
= (int64_t)(nowus
/ timescale
) + time
;
120 /* deadlines in the past should fire immediately */
124 EV_SET64(&kev
, 1, EVFILT_TIMER
, EV_ADD
,
125 NOTE_ABSOLUTE
| scale
, deadline
, 0,0,0);
126 ret
= do_simple_kevent(&kev
, expected
);
130 T_PASS("%s time:%d, scale:0x%x", __func__
, time
, scale
);
133 T_FAIL("%s time:%d, scale:0x%x", __func__
, time
, scale
);
138 test_oneshot_kevent(int time
, int scale
)
141 uint64_t expected
= 0;
142 struct kevent64_s kev
;
148 T_LOG("Testing %d MATUs interval timer...\n", time
);
149 expected
= abs_to_nanos((uint64_t)time
) / NSEC_PER_USEC
;
152 T_LOG("Testing %d sec interval timer...\n", time
);
153 expected
= (uint64_t)time
* USEC_PER_SEC
;
156 T_LOG("Testing %d usec interval timer...\n", time
);
157 expected
= (uint64_t)time
;
160 T_LOG("Testing %d nsec interval timer...\n", time
);
161 expected
= (uint64_t)time
/ 1000;
164 T_LOG("Testing %d msec interval timer...\n", time
);
165 expected
= (uint64_t)time
* 1000;
168 T_FAIL("Failure: scale 0x%x not recognized.\n", scale
);
174 /* deadlines in the past should fire immediately */
178 EV_SET64(&kev
, 2, EVFILT_TIMER
, EV_ADD
| EV_ONESHOT
, scale
, time
,
180 ret
= do_simple_kevent(&kev
, expected
);
184 T_PASS("%s time:%d, scale:0x%x", __func__
, time
, scale
);
187 T_FAIL("%s time:%d, scale:0x%x", __func__
, time
, scale
);
191 /* Test that the timer goes ding multiple times */
193 test_interval_kevent(int usec
)
195 struct kevent64_s kev
;
200 uint64_t test_duration_us
= USEC_PER_SEC
; /* 1 second */
201 uint64_t expected_pops
;
204 expected_pops
= 1; /* TODO: test 'and only once' */
206 expected_pops
= test_duration_us
/ (uint64_t)usec
;
208 T_LOG("Testing interval kevent at %d usec intervals (%lld pops/second)...\n",
209 usec
, expected_pops
);
211 EV_SET64(&kev
, 3, EVFILT_TIMER
, EV_ADD
, NOTE_USECONDS
, usec
, 0, 0, 0);
212 ret
= kevent64(kq
, &kev
, 1, NULL
, 0, 0, NULL
);
213 if (ret
!= 0 || (kev
.flags
& EV_ERROR
)) {
214 T_FAIL("%s() setup failure: kevent64 returned %d\n", __func__
, ret
);
221 struct timeval before
, after
;
222 uint64_t elapsed_usecs
;
224 gettimeofday(&before
, NULL
);
228 for (uint32_t i
= 0; i
< expected_pops
; i
++) {
229 ret
= kevent64(kq
, NULL
, 0, &kev
, 1, 0, &failure_timeout
);
231 T_FAIL("%s() failure: kevent64 returned %d\n", __func__
, ret
);
236 //T_LOG("\t ding: %lld\n", kev.data);
238 pops
+= (uint64_t)kev
.data
;
239 gettimeofday(&after
, NULL
);
240 elapsed_usecs
= (uint64_t)((after
.tv_sec
- before
.tv_sec
) * (int64_t)USEC_PER_SEC
+
241 (after
.tv_usec
- before
.tv_usec
));
243 if (elapsed_usecs
> test_duration_us
)
247 /* check how many times the timer fired: within 5%? */
248 if (pops
> expected_pops
+ (expected_pops
/ 20) ||
249 pops
< expected_pops
- (expected_pops
/ 20)) {
250 T_FAIL("%s() usec:%d (saw %lld of %lld expected pops)", __func__
, usec
, pops
, expected_pops
);
253 T_PASS("%s() usec:%d (saw %lld pops)", __func__
, usec
, pops
);
257 EV_SET64(&kev
, 3, EVFILT_TIMER
, EV_DELETE
, 0, 0, 0, 0, 0);
258 ret
= kevent64(kq
, &kev
, 1, NULL
, 0, 0, NULL
);
260 T_LOG("\tfailed to stop repeating timer: %d\n", ret
);
264 /* Test that the repeating timer repeats even while not polling in kqueue */
266 test_repeating_kevent(int usec
)
268 struct kevent64_s kev
;
273 uint64_t test_duration_us
= USEC_PER_SEC
; /* 1 second */
275 uint64_t expected_pops
= test_duration_us
/ (uint64_t)usec
;
276 T_LOG("Testing repeating kevent at %d usec intervals (%lld pops/second)...\n",
277 usec
, expected_pops
);
279 EV_SET64(&kev
, 4, EVFILT_TIMER
, EV_ADD
, NOTE_USECONDS
, usec
, 0, 0, 0);
280 ret
= kevent64(kq
, &kev
, 1, NULL
, 0, 0, NULL
);
282 T_FAIL("%s() setup failure: kevent64 returned %d\n", __func__
, ret
);
287 usleep((useconds_t
)test_duration_us
);
289 ret
= kevent64(kq
, NULL
, 0, &kev
, 1, 0, &failure_timeout
);
290 if (ret
!= 1 || (kev
.flags
& EV_ERROR
)) {
291 T_FAIL("%s() setup failure: kevent64 returned %d\n", __func__
, ret
);
298 uint64_t pops
= (uint64_t) kev
.data
;
300 /* check how many times the timer fired: within 5%? */
301 if (pops
> expected_pops
+ (expected_pops
/ 20) ||
302 pops
< expected_pops
- (expected_pops
/ 20)) {
303 T_FAIL("%s() usec:%d (saw %lld of %lld expected pops)", __func__
, usec
, pops
, expected_pops
);
306 T_PASS("%s() usec:%d (saw %lld pops)", __func__
, usec
, pops
);
310 EV_SET64(&kev
, 4, EVFILT_TIMER
, EV_DELETE
, 0, 0, 0, 0, 0);
311 ret
= kevent64(kq
, &kev
, 1, NULL
, 0, 0, NULL
);
313 T_LOG("\tfailed to stop repeating timer: %d\n", ret
);
319 test_updated_kevent(int first
, int second
)
321 struct kevent64_s kev
;
324 T_LOG("Testing update from %d to %d msecs...\n", first
, second
);
328 EV_SET64(&kev
, 4, EVFILT_TIMER
, EV_ADD
|EV_ONESHOT
, 0, first
, 0, 0, 0);
329 ret
= kevent64(kq
, &kev
, 1, NULL
, 0, 0, NULL
);
331 T_FAIL("%s() failure: initial kevent returned %d\n", __func__
, ret
);
338 EV_SET64(&kev
, 4, EVFILT_TIMER
, EV_ONESHOT
, 0, second
, 0, 0, 0);
340 uint64_t expected_us
= (uint64_t)second
* 1000;
345 ret
= do_simple_kevent(&kev
, expected_us
);
349 T_PASS("%s() %d, %d", __func__
, first
, second
);
352 T_FAIL("%s() %d, %d", __func__
, first
, second
);
357 disable_timer_coalescing(void)
359 struct task_qos_policy qosinfo
;
364 qosinfo
.task_latency_qos_tier
= LATENCY_QOS_TIER_0
;
365 qosinfo
.task_throughput_qos_tier
= THROUGHPUT_QOS_TIER_0
;
367 kr
= task_policy_set(mach_task_self(), TASK_OVERRIDE_QOS_POLICY
, (task_policy_t
)&qosinfo
,
368 TASK_QOS_POLICY_COUNT
);
369 if (kr
!= KERN_SUCCESS
) {
370 T_FAIL("task_policy_set(... TASK_OVERRIDE_QOS_POLICY ...) failed: %d (%s)", kr
, mach_error_string(kr
));
376 T_DECL(kqueue_timer_tests
,
377 "Tests assorted kqueue operations for timer-related events")
380 * Since we're trying to test timers here, disable timer coalescing
381 * to improve the accuracy of timer fires for this process.
383 disable_timer_coalescing();
385 mach_timebase_info(&timebase_info
);
392 test_absolute_kevent(100, 0);
393 test_absolute_kevent(200, 0);
394 test_absolute_kevent(300, 0);
395 test_absolute_kevent(1000, 0);
397 test_absolute_kevent(500, NOTE_USECONDS
);
399 test_absolute_kevent(100, NOTE_USECONDS
);
401 test_absolute_kevent(2, NOTE_SECONDS
);
403 test_absolute_kevent(-1000, 0);
406 test_absolute_kevent((int)nanos_to_abs(10 * NSEC_PER_MSEC
), NOTE_MACHTIME
);
408 test_oneshot_kevent(1, NOTE_SECONDS
);
410 test_oneshot_kevent(10, 0);
412 test_oneshot_kevent(200, NOTE_USECONDS
);
414 test_oneshot_kevent(300000, NOTE_NSECONDS
);
416 test_oneshot_kevent(-1, NOTE_SECONDS
);
419 test_oneshot_kevent((int)nanos_to_abs(10 * NSEC_PER_MSEC
), NOTE_MACHTIME
);
421 test_interval_kevent(250 * 1000);
423 test_interval_kevent(5 * 1000);
425 test_interval_kevent(200);
427 test_interval_kevent(50);
429 test_interval_kevent(-1000);
431 test_repeating_kevent(10000); /* 10ms */
433 test_updated_kevent(1000, 2000);
434 test_updated_kevent(2000, 1000);
435 test_updated_kevent(1000, -1);