2  * Copyright (c) 2016 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. The rights granted to you under the License 
  10  * may not be used to create, or enable the creation or redistribution of, 
  11  * unlawful or unlicensed copies of an Apple operating system, or to 
  12  * circumvent, violate, or enable the circumvention or violation of, any 
  13  * terms of an Apple operating system software license agreement. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  18  * The Original Code and all software distributed under the License are 
  19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  23  * Please see the License for the specific language governing rights and 
  24  * limitations under the License. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  29 #include <CoreFoundation/CoreFoundation.h> 
  31 #include <mach/mach.h> 
  32 #include <mach/mach_time.h> 
  34 /* These externs can be removed once the prototypes make it to the SDK */ 
  35 extern mach_port_name_t 
mk_timer_create(void); 
  36 extern kern_return_t 
mk_timer_arm(mach_port_name_t name
, uint64_t expire_time
); 
  38 #define MK_TIMER_CRITICAL (1) 
  39 extern kern_return_t    
mk_timer_arm_leeway(mach_port_name_t  name
, 
  40     uint64_t          mk_timer_flags
, 
  41     uint64_t          mk_timer_expire_time
, 
  42     uint64_t          mk_timer_leeway
); 
  44 struct mach_timebase_info tbinfo
; 
  47 mach_port_t timerPort
; 
  49 uint64_t interval_abs 
= 1000000000; 
  51 uint32_t use_leeway 
= 0; 
  52 uint32_t report 
= 1000; 
  54 uint64_t on
, lastfire 
= 0, totaljitter 
= 0, max_jitter 
= 0, min_jitter 
= ~0ULL, jiterations 
= 0, leeway_ns 
= 0, leeway_abs 
= 0; 
  57 void cfmcb(CFMachPortRef port
, void *msg
, CFIndex size
, void *msginfo
) { 
  58         uint64_t ctime 
= mach_absolute_time(); 
  62                 jitter 
= (ctime 
- deadline
); 
  63                 if (jitter 
> max_jitter
) { 
  67                 if (jitter 
< min_jitter
) { 
  71                 totaljitter 
+= jitter
; 
  72                 if ((++jiterations 
% report
) == 0) { 
  73                         printf("max_jitter: %g (ns), min_jitter: %g (ns), average_jitter: %g (ns)\n", max_jitter 
* conversion
, min_jitter 
* conversion
, ((double)totaljitter
/(double)jiterations
) * conversion
); 
  74                         max_jitter 
= 0; min_jitter 
= ~0ULL; jiterations 
= 0; totaljitter 
= 0; 
  78         deadline 
= mach_absolute_time() + interval_abs
; 
  81                 mk_timer_arm_leeway(timerPort
, MK_TIMER_CRITICAL
, deadline
, leeway_abs
); 
  83                 mk_timer_arm(timerPort
, deadline
); 
  87 int main(int argc
, char **argv
) { 
  89                 printf("Usage: mktimer_test <interval_ns> <use leeway trap> <leeway_ns>\n"); 
  93         on 
= strtoul(argv
[1], NULL
, 0); 
  94         use_leeway 
= strtoul(argv
[2], NULL
, 0); 
  96         mach_timebase_info(&tbinfo
); 
  97         conversion 
= ((double)tbinfo
.numer 
/ (double) tbinfo
.denom
); 
  99         leeway_ns 
= strtoul(argv
[3], NULL
, 0); 
 101         leeway_abs 
= leeway_ns 
/ conversion
; 
 102         printf("Interval in ns: %llu, timebase conversion: %g, use leeway syscall: %d, leeway_ns: %llu\n", on
, conversion
, !!use_leeway
, leeway_ns
); 
 104         interval_abs 
= on 
/ conversion
; 
 107         CFMachPortContext context 
= (CFMachPortContext
){ 
 115         timerPort 
= mk_timer_create(); 
 116         CFMachPortRef port 
= CFMachPortCreateWithPort(NULL
, timerPort
, cfmcb
, &context
, NULL
); 
 117         CFRunLoopSourceRef eventSource 
= CFMachPortCreateRunLoopSource(NULL
, port
, -1); 
 118         CFRunLoopAddSource(CFRunLoopGetCurrent(), eventSource
, kCFRunLoopDefaultMode
); 
 119         CFRelease(eventSource
); 
 122                 mk_timer_arm_leeway(timerPort
, MK_TIMER_CRITICAL
, mach_absolute_time() + interval_abs
, leeway_abs
); 
 124                 mk_timer_arm(timerPort
, mach_absolute_time() + interval_abs
);