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
;
22 nanos_to_abs(uint64_t nanos
)
24 return nanos
* timebase_info
.denom
/ timebase_info
.numer
;
27 abs_to_nanos(uint64_t abs
)
29 return abs
* timebase_info
.numer
/ timebase_info
.denom
;
32 static int kq
, passed
, failed
;
34 static struct timespec failure_timeout
= { .tv_sec
= 10, .tv_nsec
= 0 };
37 * Wait for given kevent, which should return in 'expected' usecs.
40 do_simple_kevent(struct kevent64_s
*kev
, uint64_t expected
)
43 int64_t elapsed_usecs
;
45 struct timespec timeout
;
46 struct timeval before
, after
;
48 /* time out after 1 sec extra delay */
49 timeout
.tv_sec
= (expected
/ USEC_PER_SEC
) + 1;
50 timeout
.tv_nsec
= (expected
% USEC_PER_SEC
) * 1000;
54 /* measure time for the kevent */
55 gettimeofday(&before
, NULL
);
56 ret
= kevent64(kq
, kev
, 1, kev
, 1, 0, &timeout
);
57 gettimeofday(&after
, NULL
);
59 if (ret
< 1 || (kev
->flags
& EV_ERROR
)) {
60 T_LOG("%s() failure: kevent returned %d, error %d\n", __func__
, ret
,
61 (ret
== -1 ? errno
: (int) kev
->data
));
68 elapsed_usecs
= (after
.tv_sec
- before
.tv_sec
) * (int64_t)USEC_PER_SEC
+
69 (after
.tv_usec
- before
.tv_usec
);
70 delta_usecs
= (uint64_t)llabs(elapsed_usecs
- ((int64_t)expected
));
72 /* failure if we're 30% off, or 50 mics late */
73 if (delta_usecs
> (30 * expected
/ 100.0) && delta_usecs
> 50) {
74 T_LOG("\tfailure: expected %lld usec, measured %lld usec.\n",
75 expected
, elapsed_usecs
);
78 T_LOG("\tsuccess, measured %lld usec.\n", elapsed_usecs
);
84 test_absolute_kevent(int time
, int scale
)
87 struct kevent64_s kev
;
88 uint64_t nowus
, expected
, timescale
= 0;
92 gettimeofday(&tv
, NULL
);
93 nowus
= (uint64_t)tv
.tv_sec
* USEC_PER_SEC
+ (uint64_t)tv
.tv_usec
;
99 T_LOG("Testing %d MATUs absolute timer...\n", time
);
102 T_LOG("Testing %d sec absolute timer...\n", time
);
103 timescale
= USEC_PER_SEC
;
106 T_LOG("Testing %d usec absolute timer...\n", time
);
110 T_LOG("Testing %d msec absolute timer...\n", time
);
114 T_FAIL("Failure: scale 0x%x not recognized.\n", scale
);
120 if (scale
== NOTE_MACHTIME
) {
121 expected
= abs_to_nanos((uint64_t)time
) / NSEC_PER_USEC
;
122 deadline
= (int64_t)mach_absolute_time() + time
;
124 expected
= (uint64_t)time
* timescale
;
125 deadline
= (int64_t)(nowus
/ timescale
) + time
;
128 /* deadlines in the past should fire immediately */
133 EV_SET64(&kev
, 1, EVFILT_TIMER
, EV_ADD
,
134 NOTE_ABSOLUTE
| scale
, deadline
, 0, 0, 0);
135 ret
= do_simple_kevent(&kev
, expected
);
139 T_PASS("%s time:%d, scale:0x%x", __func__
, time
, scale
);
142 T_FAIL("%s time:%d, scale:0x%x", __func__
, time
, scale
);
147 test_oneshot_kevent(int time
, int scale
)
150 uint64_t expected
= 0;
151 struct kevent64_s kev
;
157 T_LOG("Testing %d MATUs interval timer...\n", time
);
158 expected
= abs_to_nanos((uint64_t)time
) / NSEC_PER_USEC
;
161 T_LOG("Testing %d sec interval timer...\n", time
);
162 expected
= (uint64_t)time
* USEC_PER_SEC
;
165 T_LOG("Testing %d usec interval timer...\n", time
);
166 expected
= (uint64_t)time
;
169 T_LOG("Testing %d nsec interval timer...\n", time
);
170 expected
= (uint64_t)time
/ 1000;
173 T_LOG("Testing %d msec interval timer...\n", time
);
174 expected
= (uint64_t)time
* 1000;
177 T_FAIL("Failure: scale 0x%x not recognized.\n", scale
);
183 /* deadlines in the past should fire immediately */
188 EV_SET64(&kev
, 2, EVFILT_TIMER
, EV_ADD
| EV_ONESHOT
, scale
, time
,
190 ret
= do_simple_kevent(&kev
, expected
);
194 T_PASS("%s time:%d, scale:0x%x", __func__
, time
, scale
);
197 T_FAIL("%s time:%d, scale:0x%x", __func__
, time
, scale
);
201 /* Test that the timer goes ding multiple times */
203 test_interval_kevent(int usec
)
205 struct kevent64_s kev
;
210 uint64_t test_duration_us
= USEC_PER_SEC
; /* 1 second */
211 uint64_t expected_pops
;
214 expected_pops
= 1; /* TODO: test 'and only once' */
216 expected_pops
= test_duration_us
/ (uint64_t)usec
;
219 T_LOG("Testing interval kevent at %d usec intervals (%lld pops/second)...\n",
220 usec
, expected_pops
);
222 EV_SET64(&kev
, 3, EVFILT_TIMER
, EV_ADD
, NOTE_USECONDS
, usec
, 0, 0, 0);
223 ret
= kevent64(kq
, &kev
, 1, NULL
, 0, 0, NULL
);
224 if (ret
!= 0 || (kev
.flags
& EV_ERROR
)) {
225 T_FAIL("%s() setup failure: kevent64 returned %d\n", __func__
, ret
);
232 struct timeval before
, after
;
233 uint64_t elapsed_usecs
;
235 gettimeofday(&before
, NULL
);
239 for (uint32_t i
= 0; i
< expected_pops
; i
++) {
240 ret
= kevent64(kq
, NULL
, 0, &kev
, 1, 0, &failure_timeout
);
242 T_FAIL("%s() failure: kevent64 returned %d\n", __func__
, ret
);
247 //T_LOG("\t ding: %lld\n", kev.data);
249 pops
+= (uint64_t)kev
.data
;
250 gettimeofday(&after
, NULL
);
251 elapsed_usecs
= (uint64_t)((after
.tv_sec
- before
.tv_sec
) * (int64_t)USEC_PER_SEC
+
252 (after
.tv_usec
- before
.tv_usec
));
254 if (elapsed_usecs
> test_duration_us
) {
259 /* check how many times the timer fired: within 5%? */
260 if (pops
> expected_pops
+ (expected_pops
/ 20) ||
261 pops
< expected_pops
- (expected_pops
/ 20)) {
262 T_FAIL("%s() usec:%d (saw %lld of %lld expected pops)", __func__
, usec
, pops
, expected_pops
);
265 T_PASS("%s() usec:%d (saw %lld pops)", __func__
, usec
, pops
);
269 EV_SET64(&kev
, 3, EVFILT_TIMER
, EV_DELETE
, 0, 0, 0, 0, 0);
270 ret
= kevent64(kq
, &kev
, 1, NULL
, 0, 0, NULL
);
272 T_LOG("\tfailed to stop repeating timer: %d\n", ret
);
276 /* Test that the repeating timer repeats even while not polling in kqueue */
278 test_repeating_kevent(int usec
)
280 struct kevent64_s kev
;
285 uint64_t test_duration_us
= USEC_PER_SEC
; /* 1 second */
287 uint64_t expected_pops
= test_duration_us
/ (uint64_t)usec
;
288 T_LOG("Testing repeating kevent at %d usec intervals (%lld pops/second)...\n",
289 usec
, expected_pops
);
291 EV_SET64(&kev
, 4, EVFILT_TIMER
, EV_ADD
, NOTE_USECONDS
, usec
, 0, 0, 0);
292 ret
= kevent64(kq
, &kev
, 1, NULL
, 0, 0, NULL
);
294 T_FAIL("%s() setup failure: kevent64 returned %d\n", __func__
, ret
);
299 usleep((useconds_t
)test_duration_us
);
301 ret
= kevent64(kq
, NULL
, 0, &kev
, 1, 0, &failure_timeout
);
302 if (ret
!= 1 || (kev
.flags
& EV_ERROR
)) {
303 T_FAIL("%s() setup failure: kevent64 returned %d\n", __func__
, ret
);
310 uint64_t pops
= (uint64_t) kev
.data
;
312 /* check how many times the timer fired: within 5%? */
313 if (pops
> expected_pops
+ (expected_pops
/ 20) ||
314 pops
< expected_pops
- (expected_pops
/ 20)) {
315 T_FAIL("%s() usec:%d (saw %lld of %lld expected pops)", __func__
, usec
, pops
, expected_pops
);
318 T_PASS("%s() usec:%d (saw %lld pops)", __func__
, usec
, pops
);
322 EV_SET64(&kev
, 4, EVFILT_TIMER
, EV_DELETE
, 0, 0, 0, 0, 0);
323 ret
= kevent64(kq
, &kev
, 1, NULL
, 0, 0, NULL
);
325 T_LOG("\tfailed to stop repeating timer: %d\n", ret
);
331 test_updated_kevent(int first
, int second
)
333 struct kevent64_s kev
;
336 T_LOG("Testing update from %d to %d msecs...\n", first
, second
);
340 EV_SET64(&kev
, 4, EVFILT_TIMER
, EV_ADD
| EV_ONESHOT
, 0, first
, 0, 0, 0);
341 ret
= kevent64(kq
, &kev
, 1, NULL
, 0, 0, NULL
);
343 T_FAIL("%s() failure: initial kevent returned %d\n", __func__
, ret
);
350 EV_SET64(&kev
, 4, EVFILT_TIMER
, EV_ONESHOT
, 0, second
, 0, 0, 0);
352 uint64_t expected_us
= (uint64_t)second
* 1000;
358 ret
= do_simple_kevent(&kev
, expected_us
);
362 T_PASS("%s() %d, %d", __func__
, first
, second
);
365 T_FAIL("%s() %d, %d", __func__
, first
, second
);
370 disable_timer_coalescing(void)
372 struct task_qos_policy qosinfo
;
377 qosinfo
.task_latency_qos_tier
= LATENCY_QOS_TIER_0
;
378 qosinfo
.task_throughput_qos_tier
= THROUGHPUT_QOS_TIER_0
;
380 kr
= task_policy_set(mach_task_self(), TASK_OVERRIDE_QOS_POLICY
, (task_policy_t
)&qosinfo
,
381 TASK_QOS_POLICY_COUNT
);
382 if (kr
!= KERN_SUCCESS
) {
383 T_FAIL("task_policy_set(... TASK_OVERRIDE_QOS_POLICY ...) failed: %d (%s)", kr
, mach_error_string(kr
));
389 T_DECL(kqueue_timer_tests
,
390 "Tests assorted kqueue operations for timer-related events")
393 * Since we're trying to test timers here, disable timer coalescing
394 * to improve the accuracy of timer fires for this process.
396 disable_timer_coalescing();
398 mach_timebase_info(&timebase_info
);
405 test_absolute_kevent(100, 0);
406 test_absolute_kevent(200, 0);
407 test_absolute_kevent(300, 0);
408 test_absolute_kevent(1000, 0);
410 test_absolute_kevent(500, NOTE_USECONDS
);
412 test_absolute_kevent(100, NOTE_USECONDS
);
414 test_absolute_kevent(2, NOTE_SECONDS
);
416 test_absolute_kevent(-1000, 0);
419 test_absolute_kevent((int)nanos_to_abs(10 * NSEC_PER_MSEC
), NOTE_MACHTIME
);
421 test_oneshot_kevent(1, NOTE_SECONDS
);
423 test_oneshot_kevent(10, 0);
425 test_oneshot_kevent(200, NOTE_USECONDS
);
427 test_oneshot_kevent(300000, NOTE_NSECONDS
);
429 test_oneshot_kevent(-1, NOTE_SECONDS
);
432 test_oneshot_kevent((int)nanos_to_abs(10 * NSEC_PER_MSEC
), NOTE_MACHTIME
);
434 test_interval_kevent(250 * 1000);
436 test_interval_kevent(5 * 1000);
438 test_interval_kevent(200);
440 test_interval_kevent(50);
442 test_interval_kevent(-1000);
444 test_repeating_kevent(10000); /* 10ms */
446 test_updated_kevent(1000, 2000);
447 test_updated_kevent(2000, 1000);
448 test_updated_kevent(1000, -1);