aboutsummaryrefslogtreecommitdiff
path: root/portmidi/porttime
diff options
context:
space:
mode:
Diffstat (limited to 'portmidi/porttime')
-rwxr-xr-xportmidi/porttime/porttime.c3
-rwxr-xr-xportmidi/porttime/porttime.h103
-rw-r--r--portmidi/porttime/pthaiku.cpp88
-rwxr-xr-xportmidi/porttime/ptlinux.c139
-rwxr-xr-xportmidi/porttime/ptmacosx_cf.c140
-rwxr-xr-xportmidi/porttime/ptmacosx_mach.c204
-rwxr-xr-xportmidi/porttime/ptwinmm.c70
7 files changed, 747 insertions, 0 deletions
diff --git a/portmidi/porttime/porttime.c b/portmidi/porttime/porttime.c
new file mode 100755
index 0000000..71b06f4
--- /dev/null
+++ b/portmidi/porttime/porttime.c
@@ -0,0 +1,3 @@
1/* porttime.c -- portable API for millisecond timer */
2
3/* There is no machine-independent implementation code to put here */
diff --git a/portmidi/porttime/porttime.h b/portmidi/porttime/porttime.h
new file mode 100755
index 0000000..0a61c5c
--- /dev/null
+++ b/portmidi/porttime/porttime.h
@@ -0,0 +1,103 @@
1/** @file porttime.h portable interface to millisecond timer. */
2
3/* CHANGE LOG FOR PORTTIME
4 10-Jun-03 Mark Nelson & RBD
5 boost priority of timer thread in ptlinux.c implementation
6 */
7
8#ifndef PORTMIDI_PORTTIME_H
9#define PORTMIDI_PORTTIME_H
10
11/* Should there be a way to choose the source of time here? */
12
13#ifdef WIN32
14#ifndef INT32_DEFINED
15// rather than having users install a special .h file for windows,
16// just put the required definitions inline here. portmidi.h uses
17// these too, so the definitions are (unfortunately) duplicated there
18typedef int int32_t;
19typedef unsigned int uint32_t;
20#define INT32_DEFINED
21#endif
22#else
23#include <stdint.h> // needed for int32_t
24#endif
25
26#ifdef __cplusplus
27extern "C" {
28#endif
29
30#ifndef PMEXPORT
31#ifdef _WINDLL
32#define PMEXPORT __declspec(dllexport)
33#else
34#define PMEXPORT
35#endif
36#endif
37
38/** @defgroup grp_porttime PortTime: Millisecond Timer
39 @{
40*/
41
42typedef enum {
43 ptNoError = 0, /* success */
44 ptHostError = -10000, /* a system-specific error occurred */
45 ptAlreadyStarted, /* cannot start timer because it is already started */
46 ptAlreadyStopped, /* cannot stop timer because it is already stopped */
47 ptInsufficientMemory /* memory could not be allocated */
48} PtError; /**< @brief @enum PtError PortTime error code; a common return type.
49 * No error is indicated by zero; errors are indicated by < 0.
50 */
51
52/** real time or time offset in milliseconds. */
53typedef int32_t PtTimestamp;
54
55/** a function that gets a current time */
56typedef void (PtCallback)(PtTimestamp timestamp, void *userData);
57
58/** start a real-time clock service.
59
60 @param resolution the timer resolution in ms. The time will advance every
61 \p resolution ms.
62
63 @param callback a function pointer to be called every resolution ms.
64
65 @param userData is passed to \p callback as a parameter.
66
67 @return #ptNoError on success. See #PtError for other values.
68*/
69PMEXPORT PtError Pt_Start(int resolution, PtCallback *callback, void *userData);
70
71/** stop the timer.
72
73 @return #ptNoError on success. See #PtError for other values.
74*/
75PMEXPORT PtError Pt_Stop(void);
76
77/** test if the timer is running.
78
79 @return TRUE or FALSE
80*/
81PMEXPORT int Pt_Started(void);
82
83/** get the current time in ms.
84
85 @return the current time
86*/
87PMEXPORT PtTimestamp Pt_Time(void);
88
89/** pauses the current thread, allowing other threads to run.
90
91 @param duration the length of the pause in ms. The true duration
92 of the pause may be rounded to the nearest or next clock tick
93 as determined by resolution in #Pt_Start().
94*/
95PMEXPORT void Pt_Sleep(int32_t duration);
96
97/** @} */
98
99#ifdef __cplusplus
100}
101#endif
102
103#endif // PORTMIDI_PORTTIME_H
diff --git a/portmidi/porttime/pthaiku.cpp b/portmidi/porttime/pthaiku.cpp
new file mode 100644
index 0000000..9d8de14
--- /dev/null
+++ b/portmidi/porttime/pthaiku.cpp
@@ -0,0 +1,88 @@
1// pthaiku.cpp - portable timer implementation for Haiku
2
3#include "porttime.h"
4#include <Looper.h>
5#include <MessageRunner.h>
6#include <OS.h>
7
8namespace {
9 const uint32 timerMessage = 'PTTM';
10
11 struct TimerLooper : BLooper {
12 TimerLooper() : BLooper() {
13 }
14
15
16 virtual void MessageReceived(BMessage *message)
17 {
18 PtCallback *callback;
19 void *userData;
20 if (message->what == timerMessage && message->FindPointer("callback", (void**)&callback) == B_OK && message->FindPointer("userData", &userData) == B_OK) {
21 (*callback)(Pt_Time(), userData);
22 }
23 BLooper::MessageReceived(message);
24 }
25 };
26
27 bool time_started_flag = false;
28 bigtime_t time_offset;
29 TimerLooper *timerLooper;
30 BMessageRunner *timerRunner;
31}
32
33extern "C" {
34 PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
35 {
36 if (time_started_flag) return ptAlreadyStarted;
37 time_offset = system_time();
38 if (callback) {
39 timerLooper = new TimerLooper;
40 timerLooper->Run();
41 BMessenger target(timerLooper);
42 BMessage message(timerMessage);
43 message.AddPointer("callback", (void*)callback);
44 message.AddPointer("userData", userData);
45 bigtime_t interval = resolution * 1000;
46 timerRunner = new BMessageRunner(target, &message, interval);
47 if(timerRunner->InitCheck() != B_OK) {
48 delete timerRunner;
49 timerRunner = NULL;
50 timerLooper->PostMessage(B_QUIT_REQUESTED);
51 timerLooper = NULL;
52 return ptHostError;
53 }
54 }
55 time_started_flag = true;
56 return ptNoError;
57 }
58
59
60 PtError Pt_Stop()
61 {
62 if (!time_started_flag) return ptAlreadyStopped;
63 time_started_flag = false;
64 delete timerRunner;
65 timerRunner = NULL;
66 timerLooper->PostMessage(B_QUIT_REQUESTED);
67 timerLooper = NULL;
68 return ptNoError;
69 }
70
71
72 int Pt_Started()
73 {
74 return time_started_flag;
75 }
76
77
78 PtTimestamp Pt_Time()
79 {
80 return (system_time() - time_offset) / 1000;
81 }
82
83
84 void Pt_Sleep(int32_t duration)
85 {
86 snooze(duration * 1000);
87 }
88}
diff --git a/portmidi/porttime/ptlinux.c b/portmidi/porttime/ptlinux.c
new file mode 100755
index 0000000..c4af5c1
--- /dev/null
+++ b/portmidi/porttime/ptlinux.c
@@ -0,0 +1,139 @@
1/* ptlinux.c -- portable timer implementation for linux */
2
3
4/* IMPLEMENTATION NOTES (by Mark Nelson):
5
6Unlike Windows, Linux has no system call to request a periodic callback,
7so if Pt_Start() receives a callback parameter, it must create a thread
8that wakes up periodically and calls the provided callback function.
9If running as superuser, use setpriority() to renice thread to -20.
10One could also set the timer thread to a real-time priority (SCHED_FIFO
11and SCHED_RR), but this is dangerous for This is necessary because
12if the callback hangs it'll never return. A more serious reason
13is that the current scheduler implementation busy-waits instead
14of sleeping when realtime threads request a sleep of <=2ms (as a way
15to get around the 10ms granularity), which means the thread would never
16let anyone else on the CPU.
17
18CHANGE LOG
19
2018-Jul-03 Roger Dannenberg -- Simplified code to set priority of timer
21 thread. Simplified implementation notes.
22
23*/
24/* stdlib, stdio, unistd, and sys/types were added because they appeared
25 * in a Gentoo patch, but I'm not sure why they are needed. -RBD
26 */
27#include <stdlib.h>
28#include <stdio.h>
29#include <unistd.h>
30#include <sys/types.h>
31#include "porttime.h"
32#include "time.h"
33#include "sys/resource.h"
34#include "pthread.h"
35
36#define TRUE 1
37#define FALSE 0
38
39#ifndef CLOCK_MONOTONIC_RAW
40#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
41#endif
42
43static int time_started_flag = FALSE;
44static struct timespec time_offset = {0, 0};
45static pthread_t pt_thread_pid;
46static int pt_thread_created = FALSE;
47
48/* note that this is static data -- we only need one copy */
49typedef struct {
50 int id;
51 int resolution;
52 PtCallback *callback;
53 void *userData;
54} pt_callback_parameters;
55
56static int pt_callback_proc_id = 0;
57
58static void *Pt_CallbackProc(void *p)
59{
60 pt_callback_parameters *parameters = (pt_callback_parameters *) p;
61 int mytime = 1;
62 /* to kill a process, just increment the pt_callback_proc_id */
63 /* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id,
64 parameters->id); */
65 if (geteuid() == 0) setpriority(PRIO_PROCESS, 0, -20);
66 while (pt_callback_proc_id == parameters->id) {
67 /* wait for a multiple of resolution ms */
68 struct timeval timeout;
69 int delay = mytime++ * parameters->resolution - Pt_Time();
70 if (delay < 0) delay = 0;
71 timeout.tv_sec = 0;
72 timeout.tv_usec = delay * 1000;
73 select(0, NULL, NULL, NULL, &timeout);
74 (*(parameters->callback))(Pt_Time(), parameters->userData);
75 }
76 /* printf("Pt_CallbackProc exiting\n"); */
77 // free(parameters);
78 return NULL;
79}
80
81
82PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
83{
84 if (time_started_flag) return ptNoError;
85 /* need this set before process runs: */
86 clock_gettime(CLOCK_MONOTONIC_RAW, &time_offset);
87 if (callback) {
88 int res;
89 pt_callback_parameters *parms = (pt_callback_parameters *)
90 malloc(sizeof(pt_callback_parameters));
91 if (!parms) return ptInsufficientMemory;
92 parms->id = pt_callback_proc_id;
93 parms->resolution = resolution;
94 parms->callback = callback;
95 parms->userData = userData;
96 res = pthread_create(&pt_thread_pid, NULL,
97 Pt_CallbackProc, parms);
98 if (res != 0) return ptHostError;
99 pt_thread_created = TRUE;
100 }
101 time_started_flag = TRUE;
102 return ptNoError;
103}
104
105
106PtError Pt_Stop()
107{
108 /* printf("Pt_Stop called\n"); */
109 pt_callback_proc_id++;
110 if (pt_thread_created) {
111 pthread_join(pt_thread_pid, NULL);
112 pt_thread_created = FALSE;
113 }
114 time_started_flag = FALSE;
115 return ptNoError;
116}
117
118
119int Pt_Started()
120{
121 return time_started_flag;
122}
123
124
125PtTimestamp Pt_Time()
126{
127 long seconds, ms;
128 struct timespec now;
129 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
130 seconds = now.tv_sec - time_offset.tv_sec;
131 ms = (now.tv_nsec - time_offset.tv_nsec) / 1000000; /* round down */
132 return seconds * 1000 + ms;
133}
134
135
136void Pt_Sleep(int32_t duration)
137{
138 usleep(duration * 1000);
139}
diff --git a/portmidi/porttime/ptmacosx_cf.c b/portmidi/porttime/ptmacosx_cf.c
new file mode 100755
index 0000000..a174c86
--- /dev/null
+++ b/portmidi/porttime/ptmacosx_cf.c
@@ -0,0 +1,140 @@
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
18static int time_started_flag = FALSE;
19static CFAbsoluteTime startTime = 0.0;
20static CFRunLoopRef timerRunLoop;
21
22typedef struct {
23 int resolution;
24 PtCallback *callback;
25 void *userData;
26} PtThreadParams;
27
28
29void Pt_CFTimerCallback(CFRunLoopTimerRef timer, void *info)
30{
31 PtThreadParams *params = (PtThreadParams*)info;
32 (*params->callback)(Pt_Time(), params->userData);
33}
34
35static 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
89PtError 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
114PtError Pt_Stop()
115{
116 printf("Pt_Stop called\n");
117
118 CFRunLoopStop(timerRunLoop);
119 time_started_flag = FALSE;
120 return ptNoError;
121}
122
123
124int Pt_Started()
125{
126 return time_started_flag;
127}
128
129
130PtTimestamp Pt_Time()
131{
132 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
133 return (PtTimestamp) ((now - startTime) * 1000.0);
134}
135
136
137void Pt_Sleep(int32_t duration)
138{
139 usleep(duration * 1000);
140}
diff --git a/portmidi/porttime/ptmacosx_mach.c b/portmidi/porttime/ptmacosx_mach.c
new file mode 100755
index 0000000..1390af8
--- /dev/null
+++ b/portmidi/porttime/ptmacosx_mach.c
@@ -0,0 +1,204 @@
1/* ptmacosx.c -- portable timer implementation for mac os x */
2
3#include <stdlib.h>
4#include <stdio.h>
5#include <CoreAudio/HostTime.h>
6
7#import <mach/mach.h>
8#import <mach/mach_error.h>
9#import <mach/mach_time.h>
10#import <mach/clock.h>
11#include <unistd.h>
12#include <AvailabilityMacros.h>
13
14#include "porttime.h"
15#include "sys/time.h"
16#include "pthread.h"
17
18#ifndef NSEC_PER_MSEC
19#define NSEC_PER_MSEC 1000000
20#endif
21#define THREAD_IMPORTANCE 63
22
23// QOS headers are available as of macOS 10.10
24#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
25#include "sys/qos.h"
26#define HAVE_APPLE_QOS 1
27#else
28#undef HAVE_APPLE_QOS
29#endif
30
31static int time_started_flag = FALSE;
32static UInt64 start_time;
33static pthread_t pt_thread_pid;
34
35/* note that this is static data -- we only need one copy */
36typedef struct {
37 int id;
38 int resolution;
39 PtCallback *callback;
40 void *userData;
41} pt_callback_parameters;
42
43static int pt_callback_proc_id = 0;
44
45static void *Pt_CallbackProc(void *p)
46{
47 pt_callback_parameters *parameters = (pt_callback_parameters *) p;
48 int mytime = 1;
49
50 kern_return_t error;
51 thread_extended_policy_data_t extendedPolicy;
52 thread_precedence_policy_data_t precedencePolicy;
53
54 extendedPolicy.timeshare = 0;
55 error = thread_policy_set(mach_thread_self(), THREAD_EXTENDED_POLICY,
56 (thread_policy_t)&extendedPolicy,
57 THREAD_EXTENDED_POLICY_COUNT);
58 if (error != KERN_SUCCESS) {
59 mach_error("Couldn't set thread timeshare policy", error);
60 }
61
62 precedencePolicy.importance = THREAD_IMPORTANCE;
63 error = thread_policy_set(mach_thread_self(), THREAD_PRECEDENCE_POLICY,
64 (thread_policy_t)&precedencePolicy,
65 THREAD_PRECEDENCE_POLICY_COUNT);
66 if (error != KERN_SUCCESS) {
67 mach_error("Couldn't set thread precedence policy", error);
68 }
69
70 // Most important, set real-time constraints.
71
72 // Define the guaranteed and max fraction of time for the audio thread.
73 // These "duty cycle" values can range from 0 to 1. A value of 0.5
74 // means the scheduler would give half the time to the thread.
75 // These values have empirically been found to yield good behavior.
76 // Good means that audio performance is high and other threads won't starve.
77 const double kGuaranteedAudioDutyCycle = 0.75;
78 const double kMaxAudioDutyCycle = 0.85;
79
80 // Define constants determining how much time the audio thread can
81 // use in a given time quantum. All times are in milliseconds.
82
83 // About 128 frames @44.1KHz
84 const double kTimeQuantum = 2.9;
85
86 // Time guaranteed each quantum.
87 const double kAudioTimeNeeded = kGuaranteedAudioDutyCycle * kTimeQuantum;
88
89 // Maximum time each quantum.
90 const double kMaxTimeAllowed = kMaxAudioDutyCycle * kTimeQuantum;
91
92 // Get the conversion factor from milliseconds to absolute time
93 // which is what the time-constraints call needs.
94 mach_timebase_info_data_t tb_info;
95 mach_timebase_info(&tb_info);
96 double ms_to_abs_time =
97 ((double)tb_info.denom / (double)tb_info.numer) * 1000000;
98
99 thread_time_constraint_policy_data_t time_constraints;
100 time_constraints.period = (uint32_t)(kTimeQuantum * ms_to_abs_time);
101 time_constraints.computation = (uint32_t)(kAudioTimeNeeded * ms_to_abs_time);
102 time_constraints.constraint = (uint32_t)(kMaxTimeAllowed * ms_to_abs_time);
103 time_constraints.preemptible = 0;
104
105 error = thread_policy_set(mach_thread_self(),
106 THREAD_TIME_CONSTRAINT_POLICY,
107 (thread_policy_t)&time_constraints,
108 THREAD_TIME_CONSTRAINT_POLICY_COUNT);
109 if (error != KERN_SUCCESS) {
110 mach_error("Couldn't set thread precedence policy", error);
111 }
112
113 /* to kill a process, just increment the pt_callback_proc_id */
114 /* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id,
115 parameters->id); */
116 while (pt_callback_proc_id == parameters->id) {
117 /* wait for a multiple of resolution ms */
118 UInt64 wait_time;
119 int delay = mytime++ * parameters->resolution - Pt_Time();
120 PtTimestamp timestamp;
121 if (delay < 0) delay = 0;
122 wait_time = AudioConvertNanosToHostTime((UInt64)delay * NSEC_PER_MSEC);
123 wait_time += AudioGetCurrentHostTime();
124 mach_wait_until(wait_time);
125 timestamp = Pt_Time();
126 (*(parameters->callback))(timestamp, parameters->userData);
127 }
128 free(parameters);
129 return NULL;
130}
131
132
133PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
134{
135 if (time_started_flag) return ptAlreadyStarted;
136 start_time = AudioGetCurrentHostTime();
137
138 if (callback) {
139 int res;
140 pt_callback_parameters *parms;
141
142 parms = (pt_callback_parameters *) malloc(sizeof(pt_callback_parameters));
143 if (!parms) return ptInsufficientMemory;
144 parms->id = pt_callback_proc_id;
145 parms->resolution = resolution;
146 parms->callback = callback;
147 parms->userData = userData;
148
149#ifdef HAVE_APPLE_QOS
150 pthread_attr_t qosAttribute;
151 pthread_attr_init(&qosAttribute);
152 pthread_attr_set_qos_class_np(&qosAttribute,
153 QOS_CLASS_USER_INTERACTIVE, 0);
154
155 res = pthread_create(&pt_thread_pid, &qosAttribute, Pt_CallbackProc,
156 parms);
157#else
158 res = pthread_create(&pt_thread_pid, NULL, Pt_CallbackProc, parms);
159#endif
160
161 struct sched_param sp;
162 memset(&sp, 0, sizeof(struct sched_param));
163 sp.sched_priority = sched_get_priority_max(SCHED_RR);
164 if (pthread_setschedparam(pthread_self(), SCHED_RR, &sp) == -1) {
165 return ptHostError;
166 }
167
168 if (res != 0) return ptHostError;
169 }
170
171 time_started_flag = TRUE;
172 return ptNoError;
173}
174
175
176PtError Pt_Stop(void)
177{
178 /* printf("Pt_Stop called\n"); */
179 pt_callback_proc_id++;
180 pthread_join(pt_thread_pid, NULL);
181 time_started_flag = FALSE;
182 return ptNoError;
183}
184
185
186int Pt_Started(void)
187{
188 return time_started_flag;
189}
190
191
192PtTimestamp Pt_Time(void)
193{
194 UInt64 clock_time, nsec_time;
195 clock_time = AudioGetCurrentHostTime() - start_time;
196 nsec_time = AudioConvertHostTimeToNanos(clock_time);
197 return (PtTimestamp)(nsec_time / NSEC_PER_MSEC);
198}
199
200
201void Pt_Sleep(int32_t duration)
202{
203 usleep(duration * 1000);
204}
diff --git a/portmidi/porttime/ptwinmm.c b/portmidi/porttime/ptwinmm.c
new file mode 100755
index 0000000..5204659
--- /dev/null
+++ b/portmidi/porttime/ptwinmm.c
@@ -0,0 +1,70 @@
1/* ptwinmm.c -- portable timer implementation for win32 */
2
3
4#include "porttime.h"
5#include "windows.h"
6#include "time.h"
7
8
9TIMECAPS caps;
10
11static long time_offset = 0;
12static int time_started_flag = FALSE;
13static long time_resolution;
14static MMRESULT timer_id;
15static PtCallback *time_callback;
16
17void CALLBACK winmm_time_callback(UINT uID, UINT uMsg, DWORD_PTR dwUser,
18 DWORD_PTR dw1, DWORD_PTR dw2)
19{
20 (*time_callback)(Pt_Time(), (void *) dwUser);
21}
22
23
24PMEXPORT PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
25{
26 if (time_started_flag) return ptAlreadyStarted;
27 timeBeginPeriod(resolution);
28 time_resolution = resolution;
29 time_offset = timeGetTime();
30 time_started_flag = TRUE;
31 time_callback = callback;
32 if (callback) {
33 timer_id = timeSetEvent(resolution, 1, winmm_time_callback,
34 (DWORD_PTR) userData, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
35 if (!timer_id) return ptHostError;
36 }
37 return ptNoError;
38}
39
40
41PMEXPORT PtError Pt_Stop()
42{
43 if (!time_started_flag) return ptAlreadyStopped;
44 if (time_callback && timer_id) {
45 timeKillEvent(timer_id);
46 time_callback = NULL;
47 timer_id = 0;
48 }
49 time_started_flag = FALSE;
50 timeEndPeriod(time_resolution);
51 return ptNoError;
52}
53
54
55PMEXPORT int Pt_Started()
56{
57 return time_started_flag;
58}
59
60
61PMEXPORT PtTimestamp Pt_Time()
62{
63 return timeGetTime() - time_offset;
64}
65
66
67PMEXPORT void Pt_Sleep(int32_t duration)
68{
69 Sleep(duration);
70}