Update of /cvsroot/pure-data/pd/portmidi/porttime In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7035/porttime
Added Files: porttime.c porttime.dsp porttime.h ptlinux.c ptmacosx_cf.c ptmacosx_mach.c ptwinmm.c Log Message: checking in missing files on behalf of Miller (cleared it with him first). The files are from portmidi17nov04.zip
--- NEW FILE: porttime.dsp --- # Microsoft Developer Studio Project File - Name="porttime" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=porttime - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "porttime.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "porttime.mak" CFG="porttime - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "porttime - Win32 Release" (based on "Win32 (x86) Static Library") !MESSAGE "porttime - Win32 Debug" (based on "Win32 (x86) Static Library") !MESSAGE
# Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe
!IF "$(CFG)" == "porttime - Win32 Release"
# PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "porttime - Win32 Debug"
# PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_LIB" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "USE_DLL_FOR_CLEANUP" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LIB32=link.exe -lib # ADD BASE LIB32 /nologo # ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "porttime - Win32 Release" # Name "porttime - Win32 Debug" # Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File
SOURCE=.\porttime.c # End Source File # Begin Source File
SOURCE=.\ptwinmm.c # End Source File # End Group # Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File
SOURCE=.\porttime.h # End Source File # End Group # End Target # End Project
--- NEW FILE: porttime.h --- /* porttime.h -- portable interface to millisecond timer */
/* CHANGE LOG FOR PORTTIME 10-Jun-03 Mark Nelson & RBD boost priority of timer thread in ptlinux.c implementation */
/* Should there be a way to choose the source of time here? */
#ifdef __cplusplus extern "C" { #endif
typedef enum { ptNoError = 0, ptHostError = -10000, ptAlreadyStarted, ptAlreadyStopped, ptInsufficientMemory } PtError;
typedef long PtTimestamp;
typedef void (PtCallback)( PtTimestamp timestamp, void *userData );
PtError Pt_Start(int resolution, PtCallback *callback, void *userData); PtError Pt_Stop(); int Pt_Started(); PtTimestamp Pt_Time();
#ifdef __cplusplus } #endif
--- NEW FILE: porttime.c --- /* porttime.c -- portable API for millisecond timer */
/* There is no machine-independent implementation code to put here */
--- NEW FILE: ptwinmm.c --- /* ptwinmm.c -- portable timer implementation for win32 */
#include "porttime.h" #include "windows.h" #include "time.h"
TIMECAPS caps;
static long time_offset = 0; static int time_started_flag = FALSE; static long time_resolution; static MMRESULT timer_id; static PtCallback *time_callback;
void CALLBACK winmm_time_callback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { (*time_callback)(Pt_Time(), (void *) dwUser); }
PtError Pt_Start(int resolution, PtCallback *callback, void *userData) { if (time_started_flag) return ptAlreadyStarted; timeBeginPeriod(resolution); time_resolution = resolution; time_offset = timeGetTime(); time_started_flag = TRUE; time_callback = callback; if (callback) { timer_id = timeSetEvent(resolution, 1, winmm_time_callback, (DWORD) userData, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); if (!timer_id) return ptHostError; } return ptNoError; }
PtError Pt_Stop() { if (!time_started_flag) return ptAlreadyStopped; if (time_callback && timer_id) { timeKillEvent(timer_id); time_callback = NULL; timer_id = 0; } time_started_flag = FALSE; timeEndPeriod(time_resolution); return ptNoError; }
int Pt_Started() { return time_started_flag; }
PtTimestamp Pt_Time() { return timeGetTime() - time_offset; }
--- NEW FILE: ptmacosx_mach.c --- /* ptmacosx.c -- portable timer implementation for mac os x */
#include <stdlib.h> #include <stdio.h> #include <CoreAudio/HostTime.h>
#import <mach/mach.h> #import <mach/mach_error.h> #import <mach/mach_time.h> #import <mach/clock.h>
#include "porttime.h" #include "sys/time.h" #include "pthread.h"
#define NSEC_PER_MSEC 1000000 #define THREAD_IMPORTANCE 30
static int time_started_flag = FALSE; static UInt64 start_time; static pthread_t pt_thread_pid;
/* note that this is static data -- we only need one copy */ typedef struct { int id; int resolution; PtCallback *callback; void *userData; } pt_callback_parameters;
static int pt_callback_proc_id = 0;
static void *Pt_CallbackProc(void *p) { pt_callback_parameters *parameters = (pt_callback_parameters *) p; int mytime = 1;
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); }
/* to kill a process, just increment the pt_callback_proc_id */ printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id, parameters->id); while (pt_callback_proc_id == parameters->id) { /* wait for a multiple of resolution ms */ UInt64 wait_time; int delay = mytime++ * parameters->resolution - Pt_Time(); if (delay < 0) delay = 0; wait_time = AudioConvertNanosToHostTime((UInt64)delay * NSEC_PER_MSEC); wait_time += AudioGetCurrentHostTime(); error = mach_wait_until(wait_time); (*(parameters->callback))(Pt_Time(), parameters->userData); } printf("Pt_CallbackProc exiting\n"); free(parameters); return NULL; }
PtError Pt_Start(int resolution, PtCallback *callback, void *userData) { if (time_started_flag) return ptAlreadyStarted; start_time = AudioGetCurrentHostTime();
if (callback) { int res; pt_callback_parameters *parms;
parms = (pt_callback_parameters *) malloc(sizeof(pt_callback_parameters)); if (!parms) return ptInsufficientMemory; parms->id = pt_callback_proc_id; parms->resolution = resolution; parms->callback = callback; parms->userData = userData; res = pthread_create(&pt_thread_pid, NULL, Pt_CallbackProc, parms); if (res != 0) return ptHostError; }
time_started_flag = TRUE; return ptNoError; }
PtError Pt_Stop() { printf("Pt_Stop called\n"); pt_callback_proc_id++; time_started_flag = FALSE; return ptNoError; }
int Pt_Started() { return time_started_flag; }
PtTimestamp Pt_Time() { UInt64 clock_time, nsec_time; clock_time = AudioGetCurrentHostTime() - start_time; nsec_time = AudioConvertHostTimeToNanos(clock_time); return (PtTimestamp)(nsec_time / NSEC_PER_MSEC); }
--- NEW FILE: ptmacosx_cf.c --- /* 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); }
--- NEW FILE: ptlinux.c --- /* ptlinux.c -- portable timer implementation for linux */
/* IMPLEMENTATION NOTES (by Mark Nelson):
Unlike Windows, Linux has no system call to request a periodic callback, so if Pt_Start() receives a callback parameter, it must create a thread that wakes up periodically and calls the provided callback function. If running as superuser, use setpriority() to renice thread to -20. One could also set the timer thread to a real-time priority (SCHED_FIFO and SCHED_RR), but this is dangerous for This is necessary because if the callback hangs it'll never return. A more serious reason is that the current scheduler implementation busy-waits instead of sleeping when realtime threads request a sleep of <=2ms (as a way to get around the 10ms granularity), which means the thread would never let anyone else on the CPU.
CHANGE LOG
18-Jul-03 Roger Dannenberg -- Simplified code to set priority of timer thread. Simplified implementation notes.
*/
#include "porttime.h" #include "sys/time.h" #include "sys/resource.h" #include "sys/timeb.h" #include "pthread.h"
#define TRUE 1 #define FALSE 0
static int time_started_flag = FALSE; static struct timeb time_offset = {0, 0, 0, 0}; static pthread_t pt_thread_pid;
/* note that this is static data -- we only need one copy */ typedef struct { int id; int resolution; PtCallback *callback; void *userData; } pt_callback_parameters;
static int pt_callback_proc_id = 0;
static void *Pt_CallbackProc(void *p) { pt_callback_parameters *parameters = (pt_callback_parameters *) p; int mytime = 1; /* to kill a process, just increment the pt_callback_proc_id */ /* printf("pt_callback_proc_id %d, id %d\n", pt_callback_proc_id, parameters->id); */ if (geteuid() == 0) setpriority(PRIO_PROCESS, 0, -20); while (pt_callback_proc_id == parameters->id) { /* wait for a multiple of resolution ms */ struct timeval timeout; int delay = mytime++ * parameters->resolution - Pt_Time(); if (delay < 0) delay = 0; timeout.tv_sec = 0; timeout.tv_usec = delay * 1000; select(0, NULL, NULL, NULL, &timeout); (*(parameters->callback))(Pt_Time(), parameters->userData); } printf("Pt_CallbackProc exiting\n"); // free(parameters); return NULL; }
PtError Pt_Start(int resolution, PtCallback *callback, void *userData) { if (time_started_flag) return ptNoError; ftime(&time_offset); /* need this set before process runs */ if (callback) { int res; pt_callback_parameters *parms = (pt_callback_parameters *) malloc(sizeof(pt_callback_parameters)); if (!parms) return ptInsufficientMemory; parms->id = pt_callback_proc_id; parms->resolution = resolution; parms->callback = callback; parms->userData = userData; res = pthread_create(&pt_thread_pid, NULL, Pt_CallbackProc, parms); if (res != 0) return ptHostError; } time_started_flag = TRUE; return ptNoError; }
PtError Pt_Stop() { printf("Pt_Stop called\n"); pt_callback_proc_id++; time_started_flag = FALSE; return ptNoError; }
int Pt_Started() { return time_started_flag; }
PtTimestamp Pt_Time() { long seconds, milliseconds; struct timeb now; ftime(&now); seconds = now.time - time_offset.time; milliseconds = now.millitm - time_offset.millitm; return seconds * 1000 + milliseconds; }