ptmacosx_cf.c (3669B)
1 /* ptmacosx.c -- portable timer implementation for mac os x */ 2 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include <pthread.h> 6 #include <CoreFoundation/CoreFoundation.h> 7 8 #import <mach/mach.h> 9 #import <mach/mach_error.h> 10 #import <mach/mach_time.h> 11 #import <mach/clock.h> 12 13 #include "porttime.h" 14 15 #define THREAD_IMPORTANCE 30 16 #define LONG_TIME 1000000000.0 17 18 static int time_started_flag = FALSE; 19 static CFAbsoluteTime startTime = 0.0; 20 static CFRunLoopRef timerRunLoop; 21 22 typedef struct { 23 int resolution; 24 PtCallback *callback; 25 void *userData; 26 } PtThreadParams; 27 28 29 void Pt_CFTimerCallback(CFRunLoopTimerRef timer, void *info) 30 { 31 PtThreadParams *params = (PtThreadParams*)info; 32 (*params->callback)(Pt_Time(), params->userData); 33 } 34 35 static void* Pt_Thread(void *p) 36 { 37 CFTimeInterval timerInterval; 38 CFRunLoopTimerContext timerContext; 39 CFRunLoopTimerRef timer; 40 PtThreadParams *params = (PtThreadParams*)p; 41 //CFTimeInterval timeout; 42 43 /* raise the thread's priority */ 44 kern_return_t error; 45 thread_extended_policy_data_t extendedPolicy; 46 thread_precedence_policy_data_t precedencePolicy; 47 48 extendedPolicy.timeshare = 0; 49 error = thread_policy_set(mach_thread_self(), THREAD_EXTENDED_POLICY, 50 (thread_policy_t)&extendedPolicy, 51 THREAD_EXTENDED_POLICY_COUNT); 52 if (error != KERN_SUCCESS) { 53 mach_error("Couldn't set thread timeshare policy", error); 54 } 55 56 precedencePolicy.importance = THREAD_IMPORTANCE; 57 error = thread_policy_set(mach_thread_self(), THREAD_PRECEDENCE_POLICY, 58 (thread_policy_t)&precedencePolicy, 59 THREAD_PRECEDENCE_POLICY_COUNT); 60 if (error != KERN_SUCCESS) { 61 mach_error("Couldn't set thread precedence policy", error); 62 } 63 64 /* set up the timer context */ 65 timerContext.version = 0; 66 timerContext.info = params; 67 timerContext.retain = NULL; 68 timerContext.release = NULL; 69 timerContext.copyDescription = NULL; 70 71 /* create a new timer */ 72 timerInterval = (double)params->resolution / 1000.0; 73 timer = CFRunLoopTimerCreate(NULL, startTime+timerInterval, timerInterval, 74 0, 0, Pt_CFTimerCallback, &timerContext); 75 76 timerRunLoop = CFRunLoopGetCurrent(); 77 CFRunLoopAddTimer(timerRunLoop, timer, CFSTR("PtTimeMode")); 78 79 /* run until we're told to stop by Pt_Stop() */ 80 CFRunLoopRunInMode(CFSTR("PtTimeMode"), LONG_TIME, false); 81 82 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer, CFSTR("PtTimeMode")); 83 CFRelease(timer); 84 free(params); 85 86 return NULL; 87 } 88 89 PtError Pt_Start(int resolution, PtCallback *callback, void *userData) 90 { 91 PtThreadParams *params = (PtThreadParams*)malloc(sizeof(PtThreadParams)); 92 pthread_t pthread_id; 93 94 printf("Pt_Start() called\n"); 95 96 // /* make sure we're not already playing */ 97 if (time_started_flag) return ptAlreadyStarted; 98 startTime = CFAbsoluteTimeGetCurrent(); 99 100 if (callback) { 101 102 params->resolution = resolution; 103 params->callback = callback; 104 params->userData = userData; 105 106 pthread_create(&pthread_id, NULL, Pt_Thread, params); 107 } 108 109 time_started_flag = TRUE; 110 return ptNoError; 111 } 112 113 114 PtError Pt_Stop() 115 { 116 printf("Pt_Stop called\n"); 117 118 CFRunLoopStop(timerRunLoop); 119 time_started_flag = FALSE; 120 return ptNoError; 121 } 122 123 124 int Pt_Started() 125 { 126 return time_started_flag; 127 } 128 129 130 PtTimestamp Pt_Time() 131 { 132 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); 133 return (PtTimestamp) ((now - startTime) * 1000.0); 134 } 135 136 137 void Pt_Sleep(int32_t duration) 138 { 139 usleep(duration * 1000); 140 }