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