[PD-cvs] pd/portaudio/src/os/unix pa_unix_hostapis.c, NONE, 1.1 pa_unix_util.c, NONE, 1.1 pa_unix_util.h, NONE, 1.1
Miller Puckette
millerpuckette at users.sourceforge.net
Sun Aug 19 01:49:35 CEST 2007
- Previous message: [PD-cvs] pd/portaudio/include pa_asio.h, NONE, 1.1 pa_jack.h, NONE, 1.1 pa_linux_alsa.h, NONE, 1.1 pa_mac_core.h, NONE, 1.1 pa_win_wmme.h, NONE, 1.1 portaudio.h, NONE, 1.1
- Next message: [PD-cvs] pd/portaudio/src/os/mac_osx pa_mac_hostapis.c,NONE,1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /cvsroot/pure-data/pd/portaudio/src/os/unix
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19525/portaudio/src/os/unix
Added Files:
pa_unix_hostapis.c pa_unix_util.c pa_unix_util.h
Log Message:
CVS upload mistakes
--- NEW FILE: pa_unix_util.h ---
/*
* $Id: pa_unix_util.h,v 1.1 2007/08/18 23:49:33 millerpuckette Exp $
* Portable Audio I/O Library
* UNIX platform-specific support functions
*
* Based on the Open Source API proposed by Ross Bencina
* Copyright (c) 1999-2000 Ross Bencina
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests:
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* license above.
*/
/** @file
@ingroup unix_src
*/
#ifndef PA_UNIX_UTIL_H
#define PA_UNIX_UTIL_H
#include "pa_cpuload.h"
#include <assert.h>
#include <pthread.h>
#include <signal.h>
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#define PA_MIN(x,y) ( (x) < (y) ? (x) : (y) )
#define PA_MAX(x,y) ( (x) > (y) ? (x) : (y) )
/* Utilize GCC branch prediction for error tests */
#if defined __GNUC__ && __GNUC__ >= 3
#define UNLIKELY(expr) __builtin_expect( (expr), 0 )
#else
#define UNLIKELY(expr) (expr)
#endif
#define STRINGIZE_HELPER(expr) #expr
#define STRINGIZE(expr) STRINGIZE_HELPER(expr)
#define PA_UNLESS(expr, code) \
do { \
if( UNLIKELY( (expr) == 0 ) ) \
{ \
PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
result = (code); \
goto error; \
} \
} while (0);
static PaError paUtilErr_; /* Used with PA_ENSURE */
/* Check PaError */
#define PA_ENSURE(expr) \
do { \
if( UNLIKELY( (paUtilErr_ = (expr)) < paNoError ) ) \
{ \
PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
result = paUtilErr_; \
goto error; \
} \
} while (0);
#define PA_ASSERT_CALL(expr, success) \
paUtilErr_ = (expr); \
assert( success == paUtilErr_ );
#define PA_ENSURE_SYSTEM(expr, success) \
do { \
if( UNLIKELY( (paUtilErr_ = (expr)) != success ) ) \
{ \
/* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \
if( pthread_equal(pthread_self(), paUnixMainThread) ) \
{ \
PaUtil_SetLastHostErrorInfo( paALSA, paUtilErr_, strerror( paUtilErr_ ) ); \
} \
PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \
result = paUnanticipatedHostError; \
goto error; \
} \
} while( 0 );
typedef struct {
pthread_t callbackThread;
} PaUtilThreading;
PaError PaUtil_InitializeThreading( PaUtilThreading *threading );
void PaUtil_TerminateThreading( PaUtilThreading *threading );
PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data );
PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult );
/* State accessed by utility functions */
/*
void PaUnix_SetRealtimeScheduling( int rt );
void PaUtil_InitializeThreading( PaUtilThreading *th, PaUtilCpuLoadMeasurer *clm );
PaError PaUtil_CreateCallbackThread( PaUtilThreading *th, void *(*CallbackThreadFunc)( void * ), PaStream *s );
PaError PaUtil_KillCallbackThread( PaUtilThreading *th, PaError *exitResult );
void PaUtil_CallbackUpdate( PaUtilThreading *th );
*/
extern pthread_t paUnixMainThread;
typedef struct
{
pthread_mutex_t mtx;
} PaUnixMutex;
PaError PaUnixMutex_Initialize( PaUnixMutex* self );
PaError PaUnixMutex_Terminate( PaUnixMutex* self );
PaError PaUnixMutex_Lock( PaUnixMutex* self );
PaError PaUnixMutex_Unlock( PaUnixMutex* self );
typedef struct
{
pthread_t thread;
int parentWaiting;
int stopRequested;
int locked;
PaUnixMutex mtx;
pthread_cond_t cond;
volatile sig_atomic_t stopRequest;
} PaUnixThread;
/** Initialize global threading state.
*/
PaError PaUnixThreading_Initialize();
/** Perish, passing on eventual error code.
*
* A thin wrapper around pthread_exit, will automatically pass on any error code to the joining thread.
* If the result indicates an error, i.e. it is not equal to paNoError, this function will automatically
* allocate a pointer so the error is passed on with pthread_exit. If the result indicates that all is
* well however, only a NULL pointer will be handed to pthread_exit. Thus, the joining thread should
* check whether a non-NULL result pointer is obtained from pthread_join and make sure to free it.
* @param result: The error code to pass on to the joining thread.
*/
#define PaUnixThreading_EXIT(result) \
do { \
PaError* pres = NULL; \
if( paNoError != (result) ) \
{ \
pres = malloc( sizeof (PaError) ); \
*pres = (result); \
} \
pthread_exit( pres ); \
} while (0);
/** Spawn a thread.
*
* Intended for spawning the callback thread from the main thread. This function can even block (for a certain
* time or indefinitely) untill notified by the callback thread (using PaUnixThread_NotifyParent), which can be
* useful in order to make sure that callback has commenced before returning from Pa_StartStream.
* @param threadFunc: The function to be executed in the child thread.
* @param waitForChild: If not 0, wait for child thread to call PaUnixThread_NotifyParent. Less than 0 means
* wait for ever, greater than 0 wait for the specified time.
* @param rtSched: Enable realtime scheduling?
* @return: If timed out waiting on child, paTimedOut.
*/
PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild,
int rtSched );
/** Terminate thread.
*
* @param wait: If true, request that background thread stop and wait untill it does, else cancel it.
* @param exitResult: If non-null this will upon return contain the exit status of the thread.
*/
PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult );
/** Prepare to notify waiting parent thread.
*
* An internal lock must be held before the parent is notified in PaUnixThread_NotifyParent, call this to
* acquire it beforehand.
* @return: If parent is not waiting, paInternalError.
*/
PaError PaUnixThread_PrepareNotify( PaUnixThread* self );
/** Notify waiting parent thread.
*
* @return: If parent timed out waiting, paTimedOut. If parent was never waiting, paInternalError.
*/
PaError PaUnixThread_NotifyParent( PaUnixThread* self );
/** Has the parent thread requested this thread to stop?
*/
int PaUnixThread_StopRequested( PaUnixThread* self );
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
--- NEW FILE: pa_unix_util.c ---
/*
* $Id: pa_unix_util.c,v 1.1 2007/08/18 23:49:33 millerpuckette Exp $
* Portable Audio I/O Library
* UNIX platform-specific support functions
*
* Based on the Open Source API proposed by Ross Bencina
* Copyright (c) 1999-2000 Ross Bencina
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests:
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* license above.
*/
/** @file
@ingroup unix_src
*/
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <assert.h>
#include <string.h> /* For memset */
#include <math.h>
#include <errno.h>
#include "pa_util.h"
#include "pa_unix_util.h"
#include "pa_debugprint.h"
/*
Track memory allocations to avoid leaks.
*/
#if PA_TRACK_MEMORY
static int numAllocations_ = 0;
#endif
void *PaUtil_AllocateMemory( long size )
{
void *result = malloc( size );
#if PA_TRACK_MEMORY
if( result != NULL ) numAllocations_ += 1;
#endif
return result;
}
void PaUtil_FreeMemory( void *block )
{
if( block != NULL )
{
free( block );
#if PA_TRACK_MEMORY
numAllocations_ -= 1;
#endif
}
}
int PaUtil_CountCurrentlyAllocatedBlocks( void )
{
#if PA_TRACK_MEMORY
return numAllocations_;
#else
return 0;
#endif
}
void Pa_Sleep( long msec )
{
#ifdef HAVE_NANOSLEEP
struct timespec req = {0}, rem = {0};
PaTime time = msec / 1.e3;
req.tv_sec = (time_t)time;
assert(time - req.tv_sec < 1.0);
req.tv_nsec = (long)((time - req.tv_sec) * 1.e9);
nanosleep(&req, &rem);
/* XXX: Try sleeping the remaining time (contained in rem) if interrupted by a signal? */
#else
while( msec > 999 ) /* For OpenBSD and IRIX, argument */
{ /* to usleep must be < 1000000. */
usleep( 999000 );
msec -= 999;
}
usleep( msec * 1000 );
#endif
}
/* *** NOT USED YET: ***
static int usePerformanceCounter_;
static double microsecondsPerTick_;
*/
void PaUtil_InitializeClock( void )
{
/* TODO */
}
PaTime PaUtil_GetTime( void )
{
#ifdef HAVE_CLOCK_GETTIME
struct timespec tp;
clock_gettime(CLOCK_REALTIME, &tp);
return (PaTime)(tp.tv_sec + tp.tv_nsec / 1.e9);
#else
struct timeval tv;
gettimeofday( &tv, NULL );
return (PaTime) tv.tv_usec / 1000000. + tv.tv_sec;
#endif
}
PaError PaUtil_InitializeThreading( PaUtilThreading *threading )
{
(void) paUtilErr_;
return paNoError;
}
void PaUtil_TerminateThreading( PaUtilThreading *threading )
{
}
PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data )
{
pthread_create( &threading->callbackThread, NULL, threadRoutine, data );
return paNoError;
}
PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult )
{
PaError result = paNoError;
void *pret;
if( exitResult )
*exitResult = paNoError;
/* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
if( !wait )
pthread_cancel( threading->callbackThread ); /* XXX: Safe to call this if the thread has exited on its own? */
pthread_join( threading->callbackThread, &pret );
#ifdef PTHREAD_CANCELED
if( pret && PTHREAD_CANCELED != pret )
#else
/* !wait means the thread may have been canceled */
if( pret && wait )
#endif
{
if( exitResult )
*exitResult = *(PaError *) pret;
free( pret );
}
return result;
}
/* Threading */
/* paUnixMainThread
* We have to be a bit careful with defining this global variable,
* as explained below. */
#ifdef __apple__
/* apple/gcc has a "problem" with global vars and dynamic libs.
Initializing it seems to fix the problem.
Described a bit in this thread:
http://gcc.gnu.org/ml/gcc/2005-06/msg00179.html
*/
pthread_t paUnixMainThread = 0;
#else
/*pthreads are opaque. We don't know that asigning it an int value
always makes sense, so we don't initialize it unless we have to.*/
pthread_t paUnixMainThread = 0;
#endif
PaError PaUnixThreading_Initialize()
{
paUnixMainThread = pthread_self();
return paNoError;
}
static PaError BoostPriority( PaUnixThread* self )
{
PaError result = paNoError;
struct sched_param spm = { 0 };
/* Priority should only matter between contending FIFO threads? */
spm.sched_priority = 1;
assert( self );
if( pthread_setschedparam( self->thread, SCHED_FIFO, &spm ) != 0 )
{
PA_UNLESS( errno == EPERM, paInternalError ); /* Lack permission to raise priority */
PA_DEBUG(( "Failed bumping priority\n" ));
result = 0;
}
else
{
result = 1; /* Success */
}
error:
return result;
}
PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild,
int rtSched )
{
PaError result = paNoError;
pthread_attr_t attr;
int started = 0;
memset( self, 0, sizeof (PaUnixThread) );
PaUnixMutex_Initialize( &self->mtx );
PA_ASSERT_CALL( pthread_cond_init( &self->cond, NULL ), 0 );
self->parentWaiting = 0 != waitForChild;
/* Spawn thread */
/* Temporarily disabled since we should test during configuration for presence of required mman.h header */
#if 0
#if defined _POSIX_MEMLOCK && (_POSIX_MEMLOCK != -1)
if( rtSched )
{
if( mlockall( MCL_CURRENT | MCL_FUTURE ) < 0 )
{
int savedErrno = errno; /* In case errno gets overwritten */
assert( savedErrno != EINVAL ); /* Most likely a programmer error */
PA_UNLESS( (savedErrno == EPERM), paInternalError );
PA_DEBUG(( "%s: Failed locking memory\n", __FUNCTION__ ));
}
else
PA_DEBUG(( "%s: Successfully locked memory\n", __FUNCTION__ ));
}
#endif
#endif
PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
/* Priority relative to other processes */
PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );
PA_UNLESS( !pthread_create( &self->thread, &attr, threadFunc, threadArg ), paInternalError );
started = 1;
if( rtSched )
{
#if 0
if( self->useWatchdog )
{
int err;
struct sched_param wdSpm = { 0 };
/* Launch watchdog, watchdog sets callback thread priority */
int prio = PA_MIN( self->rtPrio + 4, sched_get_priority_max( SCHED_FIFO ) );
wdSpm.sched_priority = prio;
PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
PA_UNLESS( !pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ), paInternalError );
PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );
PA_UNLESS( !pthread_attr_setschedpolicy( &attr, SCHED_FIFO ), paInternalError );
PA_UNLESS( !pthread_attr_setschedparam( &attr, &wdSpm ), paInternalError );
if( (err = pthread_create( &self->watchdogThread, &attr, &WatchdogFunc, self )) )
{
PA_UNLESS( err == EPERM, paInternalError );
/* Permission error, go on without realtime privileges */
PA_DEBUG(( "Failed bumping priority\n" ));
}
else
{
int policy;
self->watchdogRunning = 1;
PA_ENSURE_SYSTEM( pthread_getschedparam( self->watchdogThread, &policy, &wdSpm ), 0 );
/* Check if priority is right, policy could potentially differ from SCHED_FIFO (but that's alright) */
if( wdSpm.sched_priority != prio )
{
PA_DEBUG(( "Watchdog priority not set correctly (%d)\n", wdSpm.sched_priority ));
PA_ENSURE( paInternalError );
}
}
}
else
#endif
PA_ENSURE( BoostPriority( self ) );
{
int policy;
struct sched_param spm;
pthread_getschedparam(self->thread, &policy, &spm);
}
}
if( self->parentWaiting )
{
PaTime till;
struct timespec ts;
int res = 0;
PaTime now;
PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) );
/* Wait for stream to be started */
now = PaUtil_GetTime();
till = now + waitForChild;
while( self->parentWaiting && !res )
{
if( waitForChild > 0 )
{
ts.tv_sec = (time_t) floor( till );
ts.tv_nsec = (long) ((till - floor( till )) * 1e9);
res = pthread_cond_timedwait( &self->cond, &self->mtx.mtx, &ts );
}
else
{
res = pthread_cond_wait( &self->cond, &self->mtx.mtx );
}
}
PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) );
PA_UNLESS( !res || ETIMEDOUT == res, paInternalError );
PA_DEBUG(( "%s: Waited for %g seconds for stream to start\n", __FUNCTION__, PaUtil_GetTime() - now ));
if( ETIMEDOUT == res )
{
PA_ENSURE( paTimedOut );
}
}
end:
return result;
error:
if( started )
{
PaUnixThread_Terminate( self, 0, NULL );
}
goto end;
}
PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult )
{
PaError result = paNoError;
void* pret;
if( exitResult )
{
*exitResult = paNoError;
}
#if 0
if( watchdogExitResult )
*watchdogExitResult = paNoError;
if( th->watchdogRunning )
{
pthread_cancel( th->watchdogThread );
PA_ENSURE_SYSTEM( pthread_join( th->watchdogThread, &pret ), 0 );
if( pret && pret != PTHREAD_CANCELED )
{
if( watchdogExitResult )
*watchdogExitResult = *(PaError *) pret;
free( pret );
}
}
#endif
/* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
/* TODO: Make join time out */
self->stopRequested = wait;
if( !wait )
{
PA_DEBUG(( "%s: Canceling thread %d\n", __FUNCTION__, self->thread ));
/* XXX: Safe to call this if the thread has exited on its own? */
pthread_cancel( self->thread );
}
PA_DEBUG(( "%s: Joining thread %d\n", __FUNCTION__, self->thread ));
PA_ENSURE_SYSTEM( pthread_join( self->thread, &pret ), 0 );
if( pret && PTHREAD_CANCELED != pret )
{
if( exitResult )
{
*exitResult = *(PaError*)pret;
}
free( pret );
}
error:
PA_ASSERT_CALL( PaUnixMutex_Terminate( &self->mtx ), paNoError );
PA_ASSERT_CALL( pthread_cond_destroy( &self->cond ), 0 );
return result;
}
PaError PaUnixThread_PrepareNotify( PaUnixThread* self )
{
PaError result = paNoError;
PA_UNLESS( self->parentWaiting, paInternalError );
PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) );
self->locked = 1;
error:
return result;
}
PaError PaUnixThread_NotifyParent( PaUnixThread* self )
{
PaError result = paNoError;
PA_UNLESS( self->parentWaiting, paInternalError );
if( !self->locked )
{
PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) );
self->locked = 1;
}
self->parentWaiting = 0;
pthread_cond_signal( &self->cond );
PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) );
self->locked = 0;
error:
return result;
}
int PaUnixThread_StopRequested( PaUnixThread* self )
{
return self->stopRequested;
}
PaError PaUnixMutex_Initialize( PaUnixMutex* self )
{
PaError result = paNoError;
PA_ASSERT_CALL( pthread_mutex_init( &self->mtx, NULL ), 0 );
return result;
}
PaError PaUnixMutex_Terminate( PaUnixMutex* self )
{
PaError result = paNoError;
PA_ASSERT_CALL( pthread_mutex_destroy( &self->mtx ), 0 );
return result;
}
/** Lock mutex.
*
* We're disabling thread cancellation while the thread is holding a lock, so mutexes are
* properly unlocked at termination time.
*/
PaError PaUnixMutex_Lock( PaUnixMutex* self )
{
PaError result = paNoError;
int oldState;
PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldState ), 0 );
PA_ENSURE_SYSTEM( pthread_mutex_lock( &self->mtx ), 0 );
error:
return result;
}
/** Unlock mutex.
*
* Thread cancellation is enabled again after the mutex is properly unlocked.
*/
PaError PaUnixMutex_Unlock( PaUnixMutex* self )
{
PaError result = paNoError;
int oldState;
PA_ENSURE_SYSTEM( pthread_mutex_unlock( &self->mtx ), 0 );
PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldState ), 0 );
error:
return result;
}
#if 0
static void OnWatchdogExit( void *userData )
{
PaAlsaThreading *th = (PaAlsaThreading *) userData;
struct sched_param spm = { 0 };
assert( th );
PA_ASSERT_CALL( pthread_setschedparam( th->callbackThread, SCHED_OTHER, &spm ), 0 ); /* Lower before exiting */
PA_DEBUG(( "Watchdog exiting\n" ));
}
static void *WatchdogFunc( void *userData )
{
PaError result = paNoError, *pres = NULL;
int err;
PaAlsaThreading *th = (PaAlsaThreading *) userData;
unsigned intervalMsec = 500;
const PaTime maxSeconds = 3.; /* Max seconds between callbacks */
PaTime timeThen = PaUtil_GetTime(), timeNow, timeElapsed, cpuTimeThen, cpuTimeNow, cpuTimeElapsed;
double cpuLoad, avgCpuLoad = 0.;
int throttled = 0;
assert( th );
/* Execute OnWatchdogExit when exiting */
pthread_cleanup_push( &OnWatchdogExit, th );
/* Boost priority of callback thread */
PA_ENSURE( result = BoostPriority( th ) );
if( !result )
{
/* Boost failed, might as well exit */
pthread_exit( NULL );
}
cpuTimeThen = th->callbackCpuTime;
{
int policy;
struct sched_param spm = { 0 };
pthread_getschedparam( pthread_self(), &policy, &spm );
PA_DEBUG(( "%s: Watchdog priority is %d\n", __FUNCTION__, spm.sched_priority ));
}
while( 1 )
{
double lowpassCoeff = 0.9, lowpassCoeff1 = 0.99999 - lowpassCoeff;
/* Test before and after in case whatever underlying sleep call isn't interrupted by pthread_cancel */
pthread_testcancel();
Pa_Sleep( intervalMsec );
pthread_testcancel();
if( PaUtil_GetTime() - th->callbackTime > maxSeconds )
{
PA_DEBUG(( "Watchdog: Terminating callback thread\n" ));
/* Tell thread to terminate */
err = pthread_kill( th->callbackThread, SIGKILL );
pthread_exit( NULL );
}
PA_DEBUG(( "%s: PortAudio reports CPU load: %g\n", __FUNCTION__, PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) ));
/* Check if we should throttle, or unthrottle :P */
cpuTimeNow = th->callbackCpuTime;
cpuTimeElapsed = cpuTimeNow - cpuTimeThen;
cpuTimeThen = cpuTimeNow;
timeNow = PaUtil_GetTime();
timeElapsed = timeNow - timeThen;
timeThen = timeNow;
cpuLoad = cpuTimeElapsed / timeElapsed;
avgCpuLoad = avgCpuLoad * lowpassCoeff + cpuLoad * lowpassCoeff1;
/*
if( throttled )
PA_DEBUG(( "Watchdog: CPU load: %g, %g\n", avgCpuLoad, cpuTimeElapsed ));
*/
if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) > .925 )
{
static int policy;
static struct sched_param spm = { 0 };
static const struct sched_param defaultSpm = { 0 };
PA_DEBUG(( "%s: Throttling audio thread, priority %d\n", __FUNCTION__, spm.sched_priority ));
pthread_getschedparam( th->callbackThread, &policy, &spm );
if( !pthread_setschedparam( th->callbackThread, SCHED_OTHER, &defaultSpm ) )
{
throttled = 1;
}
else
PA_DEBUG(( "Watchdog: Couldn't lower priority of audio thread: %s\n", strerror( errno ) ));
/* Give other processes a go, before raising priority again */
PA_DEBUG(( "%s: Watchdog sleeping for %lu msecs before unthrottling\n", __FUNCTION__, th->throttledSleepTime ));
Pa_Sleep( th->throttledSleepTime );
/* Reset callback priority */
if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 )
{
PA_DEBUG(( "%s: Couldn't raise priority of audio thread: %s\n", __FUNCTION__, strerror( errno ) ));
}
if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) >= .99 )
intervalMsec = 50;
else
intervalMsec = 100;
/*
lowpassCoeff = .97;
lowpassCoeff1 = .99999 - lowpassCoeff;
*/
}
else if( throttled && avgCpuLoad < .8 )
{
intervalMsec = 500;
throttled = 0;
/*
lowpassCoeff = .9;
lowpassCoeff1 = .99999 - lowpassCoeff;
*/
}
}
pthread_cleanup_pop( 1 ); /* Execute cleanup on exit */
error:
/* Shouldn't get here in the normal case */
/* Pass on error code */
pres = malloc( sizeof (PaError) );
*pres = result;
pthread_exit( pres );
}
static void CallbackUpdate( PaAlsaThreading *th )
{
th->callbackTime = PaUtil_GetTime();
th->callbackCpuTime = PaUtil_GetCpuLoad( th->cpuLoadMeasurer );
}
/*
static void *CanaryFunc( void *userData )
{
const unsigned intervalMsec = 1000;
PaUtilThreading *th = (PaUtilThreading *) userData;
while( 1 )
{
th->canaryTime = PaUtil_GetTime();
pthread_testcancel();
Pa_Sleep( intervalMsec );
}
pthread_exit( NULL );
}
*/
#endif
--- NEW FILE: pa_unix_hostapis.c ---
/*
* $Id: pa_unix_hostapis.c,v 1.1 2007/08/18 23:49:33 millerpuckette Exp $
* Portable Audio I/O Library UNIX initialization table
*
* Based on the Open Source API proposed by Ross Bencina
* Copyright (c) 1999-2002 Ross Bencina, Phil Burk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests:
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* license above.
*/
/** @file
@ingroup unix_src
*/
#include "pa_hostapi.h"
PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
/* Added for IRIX, Pieter, oct 2, 2003: */
PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
/* Linux AudioScience HPI */
PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
PaUtilHostApiInitializer *paHostApiInitializers[] =
{
#ifdef PA_USE_OSS
PaOSS_Initialize,
#endif
#ifdef PA_USE_ALSA
PaAlsa_Initialize,
#endif
#ifdef PA_USE_JACK
PaJack_Initialize,
#endif
/* Added for IRIX, Pieter, oct 2, 2003: */
#ifdef PA_USE_SGI
PaSGI_Initialize,
#endif
#ifdef PA_USE_ASIHPI
PaAsiHpi_Initialize,
#endif
0 /* NULL terminated array */
};
int paDefaultHostApiIndex = 0;
- Previous message: [PD-cvs] pd/portaudio/include pa_asio.h, NONE, 1.1 pa_jack.h, NONE, 1.1 pa_linux_alsa.h, NONE, 1.1 pa_mac_core.h, NONE, 1.1 pa_win_wmme.h, NONE, 1.1 portaudio.h, NONE, 1.1
- Next message: [PD-cvs] pd/portaudio/src/os/mac_osx pa_mac_hostapis.c,NONE,1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the Pd-cvs
mailing list