1 /*
2 * $Id$
3 * Portable Audio I/O Library
4 * UNIX platform-specific support functions
5 *
6 * Based on the Open Source API proposed by Ross Bencina
7 * Copyright (c) 1999-2000 Ross Bencina
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining
10 * a copy of this software and associated documentation files
11 * (the "Software"), to deal in the Software without restriction,
12 * including without limitation the rights to use, copy, modify, merge,
13 * publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so,
15 * subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
24 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
25 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29 /*
30 * The text above constitutes the entire PortAudio license; however,
31 * the PortAudio community also makes the following non-binding requests:
32 *
33 * Any person wishing to distribute modifications to the Software is
34 * requested to send the modifications to the original developer so that
35 * they can be incorporated into the canonical version. It is also
36 * requested that these non-binding requests be included along with the
37 * license above.
38 */
39
40 /** @file
41 @ingroup unix_src
42 */
43
44 #include <pthread.h>
45 #include <unistd.h>
46 #include <stdlib.h>
47 #include <time.h>
48 #include <sys/time.h>
49 #include <assert.h>
50 #include <string.h> /* For memset */
51 #include <math.h>
52 #include <errno.h>
53
54 #if defined(__APPLE__) && !defined(HAVE_MACH_ABSOLUTE_TIME)
55 #define HAVE_MACH_ABSOLUTE_TIME
56 #endif
57 #ifdef HAVE_MACH_ABSOLUTE_TIME
58 #include <mach/mach_time.h>
59 #endif
60
61 #include "pa_util.h"
62 #include "pa_unix_util.h"
63 #include "pa_debugprint.h"
64
65 /*
66 Track memory allocations to avoid leaks.
67 */
68
69 #if PA_TRACK_MEMORY
70 static int numAllocations_ = 0;
71 #endif
72
73
PaUtil_AllocateMemory(long size)74 void *PaUtil_AllocateMemory( long size )
75 {
76 void *result = malloc( size );
77
78 #if PA_TRACK_MEMORY
79 if( result != NULL ) numAllocations_ += 1;
80 #endif
81 return result;
82 }
83
84
PaUtil_FreeMemory(void * block)85 void PaUtil_FreeMemory( void *block )
86 {
87 if( block != NULL )
88 {
89 free( block );
90 #if PA_TRACK_MEMORY
91 numAllocations_ -= 1;
92 #endif
93
94 }
95 }
96
97
PaUtil_CountCurrentlyAllocatedBlocks(void)98 int PaUtil_CountCurrentlyAllocatedBlocks( void )
99 {
100 #if PA_TRACK_MEMORY
101 return numAllocations_;
102 #else
103 return 0;
104 #endif
105 }
106
107
Pa_Sleep(long msec)108 void Pa_Sleep( long msec )
109 {
110 #ifdef HAVE_NANOSLEEP
111 struct timespec req = {0}, rem = {0};
112 PaTime time = msec / 1.e3;
113 req.tv_sec = (time_t)time;
114 assert(time - req.tv_sec < 1.0);
115 req.tv_nsec = (long)((time - req.tv_sec) * 1.e9);
116 nanosleep(&req, &rem);
117 /* XXX: Try sleeping the remaining time (contained in rem) if interrupted by a signal? */
118 #else
119 while( msec > 999 ) /* For OpenBSD and IRIX, argument */
120 { /* to usleep must be < 1000000. */
121 usleep( 999000 );
122 msec -= 999;
123 }
124 usleep( msec * 1000 );
125 #endif
126 }
127
128 #ifdef HAVE_MACH_ABSOLUTE_TIME
129 /*
130 Discussion on the CoreAudio mailing list suggests that calling
131 gettimeofday (or anything else in the BSD layer) is not real-time
132 safe, so we use mach_absolute_time on OSX. This implementation is
133 based on these two links:
134
135 Technical Q&A QA1398 - Mach Absolute Time Units
136 http://developer.apple.com/mac/library/qa/qa2004/qa1398.html
137
138 Tutorial: Performance and Time.
139 http://www.macresearch.org/tutorial_performance_and_time
140 */
141
142 /* Scaler to convert the result of mach_absolute_time to seconds */
143 static double machSecondsConversionScaler_ = 0.0;
144 #endif
145
PaUtil_InitializeClock(void)146 void PaUtil_InitializeClock( void )
147 {
148 #ifdef HAVE_MACH_ABSOLUTE_TIME
149 mach_timebase_info_data_t info;
150 kern_return_t err = mach_timebase_info( &info );
151 if( err == 0 )
152 machSecondsConversionScaler_ = 1e-9 * (double) info.numer / (double) info.denom;
153 #endif
154 }
155
156
PaUtil_GetTime(void)157 PaTime PaUtil_GetTime( void )
158 {
159 #ifdef HAVE_MACH_ABSOLUTE_TIME
160 return mach_absolute_time() * machSecondsConversionScaler_;
161 #elif defined(HAVE_CLOCK_GETTIME)
162 struct timespec tp;
163 clock_gettime(CLOCK_REALTIME, &tp);
164 return (PaTime)(tp.tv_sec + tp.tv_nsec * 1e-9);
165 #else
166 struct timeval tv;
167 gettimeofday( &tv, NULL );
168 return (PaTime) tv.tv_usec * 1e-6 + tv.tv_sec;
169 #endif
170 }
171
PaUtil_InitializeThreading(PaUtilThreading * threading)172 PaError PaUtil_InitializeThreading( PaUtilThreading *threading )
173 {
174 (void) paUtilErr_;
175 return paNoError;
176 }
177
PaUtil_TerminateThreading(PaUtilThreading * threading)178 void PaUtil_TerminateThreading( PaUtilThreading *threading )
179 {
180 }
181
PaUtil_StartThreading(PaUtilThreading * threading,void * (* threadRoutine)(void *),void * data)182 PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data )
183 {
184 pthread_create( &threading->callbackThread, NULL, threadRoutine, data );
185 return paNoError;
186 }
187
PaUtil_CancelThreading(PaUtilThreading * threading,int wait,PaError * exitResult)188 PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult )
189 {
190 PaError result = paNoError;
191 void *pret;
192
193 if( exitResult )
194 *exitResult = paNoError;
195
196 /* If pthread_cancel is not supported (Android platform) whole this function can lead to indefinite waiting if
197 working thread (callbackThread) has'n received any stop signals from outside, please keep
198 this in mind when considering using PaUtil_CancelThreading
199 */
200 #ifdef PTHREAD_CANCELED
201 /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
202 if( !wait )
203 pthread_cancel( threading->callbackThread ); /* XXX: Safe to call this if the thread has exited on its own? */
204 #endif
205 pthread_join( threading->callbackThread, &pret );
206
207 #ifdef PTHREAD_CANCELED
208 if( pret && PTHREAD_CANCELED != pret )
209 #else
210 /* !wait means the thread may have been canceled */
211 if( pret && wait )
212 #endif
213 {
214 if( exitResult )
215 *exitResult = *(PaError *) pret;
216 free( pret );
217 }
218
219 return result;
220 }
221
222 /* Threading */
223 /* paUnixMainThread
224 * We have to be a bit careful with defining this global variable,
225 * as explained below. */
226 #ifdef __APPLE__
227 /* apple/gcc has a "problem" with global vars and dynamic libs.
228 Initializing it seems to fix the problem.
229 Described a bit in this thread:
230 http://gcc.gnu.org/ml/gcc/2005-06/msg00179.html
231 */
232 pthread_t paUnixMainThread = 0;
233 #else
234 /*pthreads are opaque. We don't know that asigning it an int value
235 always makes sense, so we don't initialize it unless we have to.*/
236 pthread_t paUnixMainThread = 0;
237 #endif
238
PaUnixThreading_Initialize()239 PaError PaUnixThreading_Initialize()
240 {
241 paUnixMainThread = pthread_self();
242 return paNoError;
243 }
244
BoostPriority(PaUnixThread * self)245 static PaError BoostPriority( PaUnixThread* self )
246 {
247 PaError result = paNoError;
248 struct sched_param spm = { 0 };
249 /* Priority should only matter between contending FIFO threads? */
250 spm.sched_priority = 1;
251
252 assert( self );
253
254 if( pthread_setschedparam( self->thread, SCHED_FIFO, &spm ) != 0 )
255 {
256 PA_UNLESS( errno == EPERM, paInternalError ); /* Lack permission to raise priority */
257 PA_DEBUG(( "Failed bumping priority\n" ));
258 result = 0;
259 }
260 else
261 {
262 result = 1; /* Success */
263 }
264 error:
265 return result;
266 }
267
PaUnixThread_New(PaUnixThread * self,void * (* threadFunc)(void *),void * threadArg,PaTime waitForChild,int rtSched)268 PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild,
269 int rtSched )
270 {
271 PaError result = paNoError;
272 pthread_attr_t attr;
273 int started = 0;
274
275 memset( self, 0, sizeof (PaUnixThread) );
276 PaUnixMutex_Initialize( &self->mtx );
277 PA_ASSERT_CALL( pthread_cond_init( &self->cond, NULL ), 0 );
278
279 self->parentWaiting = 0 != waitForChild;
280
281 /* Spawn thread */
282
283 /* Temporarily disabled since we should test during configuration for presence of required mman.h header */
284 #if 0
285 #if defined _POSIX_MEMLOCK && (_POSIX_MEMLOCK != -1)
286 if( rtSched )
287 {
288 if( mlockall( MCL_CURRENT | MCL_FUTURE ) < 0 )
289 {
290 int savedErrno = errno; /* In case errno gets overwritten */
291 assert( savedErrno != EINVAL ); /* Most likely a programmer error */
292 PA_UNLESS( (savedErrno == EPERM), paInternalError );
293 PA_DEBUG(( "%s: Failed locking memory\n", __FUNCTION__ ));
294 }
295 else
296 PA_DEBUG(( "%s: Successfully locked memory\n", __FUNCTION__ ));
297 }
298 #endif
299 #endif
300
301 PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
302 /* Priority relative to other processes */
303 PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );
304
305 PA_UNLESS( !pthread_create( &self->thread, &attr, threadFunc, threadArg ), paInternalError );
306 started = 1;
307
308 if( rtSched )
309 {
310 #if 0
311 if( self->useWatchdog )
312 {
313 int err;
314 struct sched_param wdSpm = { 0 };
315 /* Launch watchdog, watchdog sets callback thread priority */
316 int prio = PA_MIN( self->rtPrio + 4, sched_get_priority_max( SCHED_FIFO ) );
317 wdSpm.sched_priority = prio;
318
319 PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
320 PA_UNLESS( !pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ), paInternalError );
321 PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );
322 PA_UNLESS( !pthread_attr_setschedpolicy( &attr, SCHED_FIFO ), paInternalError );
323 PA_UNLESS( !pthread_attr_setschedparam( &attr, &wdSpm ), paInternalError );
324 if( (err = pthread_create( &self->watchdogThread, &attr, &WatchdogFunc, self )) )
325 {
326 PA_UNLESS( err == EPERM, paInternalError );
327 /* Permission error, go on without realtime privileges */
328 PA_DEBUG(( "Failed bumping priority\n" ));
329 }
330 else
331 {
332 int policy;
333 self->watchdogRunning = 1;
334 PA_ENSURE_SYSTEM( pthread_getschedparam( self->watchdogThread, &policy, &wdSpm ), 0 );
335 /* Check if priority is right, policy could potentially differ from SCHED_FIFO (but that's alright) */
336 if( wdSpm.sched_priority != prio )
337 {
338 PA_DEBUG(( "Watchdog priority not set correctly (%d)\n", wdSpm.sched_priority ));
339 PA_ENSURE( paInternalError );
340 }
341 }
342 }
343 else
344 #endif
345 PA_ENSURE( BoostPriority( self ) );
346
347 {
348 int policy;
349 struct sched_param spm;
350 pthread_getschedparam(self->thread, &policy, &spm);
351 }
352 }
353
354 if( self->parentWaiting )
355 {
356 PaTime till;
357 struct timespec ts;
358 int res = 0;
359 PaTime now;
360
361 PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) );
362
363 /* Wait for stream to be started */
364 now = PaUtil_GetTime();
365 till = now + waitForChild;
366
367 while( self->parentWaiting && !res )
368 {
369 if( waitForChild > 0 )
370 {
371 ts.tv_sec = (time_t) floor( till );
372 ts.tv_nsec = (long) ((till - floor( till )) * 1e9);
373 res = pthread_cond_timedwait( &self->cond, &self->mtx.mtx, &ts );
374 }
375 else
376 {
377 res = pthread_cond_wait( &self->cond, &self->mtx.mtx );
378 }
379 }
380
381 PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) );
382
383 PA_UNLESS( !res || ETIMEDOUT == res, paInternalError );
384 PA_DEBUG(( "%s: Waited for %g seconds for stream to start\n", __FUNCTION__, PaUtil_GetTime() - now ));
385 if( ETIMEDOUT == res )
386 {
387 PA_ENSURE( paTimedOut );
388 }
389 }
390
391 end:
392 return result;
393 error:
394 if( started )
395 {
396 PaUnixThread_Terminate( self, 0, NULL );
397 }
398
399 goto end;
400 }
401
PaUnixThread_Terminate(PaUnixThread * self,int wait,PaError * exitResult)402 PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult )
403 {
404 PaError result = paNoError;
405 void* pret;
406
407 if( exitResult )
408 {
409 *exitResult = paNoError;
410 }
411 #if 0
412 if( watchdogExitResult )
413 *watchdogExitResult = paNoError;
414
415 if( th->watchdogRunning )
416 {
417 pthread_cancel( th->watchdogThread );
418 PA_ENSURE_SYSTEM( pthread_join( th->watchdogThread, &pret ), 0 );
419
420 if( pret && pret != PTHREAD_CANCELED )
421 {
422 if( watchdogExitResult )
423 *watchdogExitResult = *(PaError *) pret;
424 free( pret );
425 }
426 }
427 #endif
428
429 /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
430 /* TODO: Make join time out */
431 self->stopRequested = wait;
432 if( !wait )
433 {
434 PA_DEBUG(( "%s: Canceling thread %d\n", __FUNCTION__, self->thread ));
435 /* XXX: Safe to call this if the thread has exited on its own? */
436 #ifdef PTHREAD_CANCELED
437 pthread_cancel( self->thread );
438 #endif
439 }
440 PA_DEBUG(( "%s: Joining thread %d\n", __FUNCTION__, self->thread ));
441 PA_ENSURE_SYSTEM( pthread_join( self->thread, &pret ), 0 );
442
443 #ifdef PTHREAD_CANCELED
444 if( pret && PTHREAD_CANCELED != pret )
445 #else
446 /* !wait means the thread may have been canceled */
447 if( pret && wait )
448 #endif
449 {
450 if( exitResult )
451 {
452 *exitResult = *(PaError*)pret;
453 }
454 free( pret );
455 }
456
457 error:
458 PA_ASSERT_CALL( PaUnixMutex_Terminate( &self->mtx ), paNoError );
459 PA_ASSERT_CALL( pthread_cond_destroy( &self->cond ), 0 );
460
461 return result;
462 }
463
PaUnixThread_PrepareNotify(PaUnixThread * self)464 PaError PaUnixThread_PrepareNotify( PaUnixThread* self )
465 {
466 PaError result = paNoError;
467 PA_UNLESS( self->parentWaiting, paInternalError );
468
469 PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) );
470 self->locked = 1;
471
472 error:
473 return result;
474 }
475
PaUnixThread_NotifyParent(PaUnixThread * self)476 PaError PaUnixThread_NotifyParent( PaUnixThread* self )
477 {
478 PaError result = paNoError;
479 PA_UNLESS( self->parentWaiting, paInternalError );
480
481 if( !self->locked )
482 {
483 PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) );
484 self->locked = 1;
485 }
486 self->parentWaiting = 0;
487 pthread_cond_signal( &self->cond );
488 PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) );
489 self->locked = 0;
490
491 error:
492 return result;
493 }
494
PaUnixThread_StopRequested(PaUnixThread * self)495 int PaUnixThread_StopRequested( PaUnixThread* self )
496 {
497 return self->stopRequested;
498 }
499
PaUnixMutex_Initialize(PaUnixMutex * self)500 PaError PaUnixMutex_Initialize( PaUnixMutex* self )
501 {
502 PaError result = paNoError;
503 PA_ASSERT_CALL( pthread_mutex_init( &self->mtx, NULL ), 0 );
504 return result;
505 }
506
PaUnixMutex_Terminate(PaUnixMutex * self)507 PaError PaUnixMutex_Terminate( PaUnixMutex* self )
508 {
509 PaError result = paNoError;
510 PA_ASSERT_CALL( pthread_mutex_destroy( &self->mtx ), 0 );
511 return result;
512 }
513
514 /** Lock mutex.
515 *
516 * We're disabling thread cancellation while the thread is holding a lock, so mutexes are
517 * properly unlocked at termination time.
518 */
PaUnixMutex_Lock(PaUnixMutex * self)519 PaError PaUnixMutex_Lock( PaUnixMutex* self )
520 {
521 PaError result = paNoError;
522
523 #ifdef PTHREAD_CANCEL
524 int oldState;
525 PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldState ), 0 );
526 #endif
527 PA_ENSURE_SYSTEM( pthread_mutex_lock( &self->mtx ), 0 );
528
529 error:
530 return result;
531 }
532
533 /** Unlock mutex.
534 *
535 * Thread cancellation is enabled again after the mutex is properly unlocked.
536 */
PaUnixMutex_Unlock(PaUnixMutex * self)537 PaError PaUnixMutex_Unlock( PaUnixMutex* self )
538 {
539 PaError result = paNoError;
540
541 PA_ENSURE_SYSTEM( pthread_mutex_unlock( &self->mtx ), 0 );
542 #ifdef PTHREAD_CANCEL
543 int oldState;
544 PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldState ), 0 );
545 #endif
546
547 error:
548 return result;
549 }
550
551
552 #if 0
553 static void OnWatchdogExit( void *userData )
554 {
555 PaAlsaThreading *th = (PaAlsaThreading *) userData;
556 struct sched_param spm = { 0 };
557 assert( th );
558
559 PA_ASSERT_CALL( pthread_setschedparam( th->callbackThread, SCHED_OTHER, &spm ), 0 ); /* Lower before exiting */
560 PA_DEBUG(( "Watchdog exiting\n" ));
561 }
562
563 static void *WatchdogFunc( void *userData )
564 {
565 PaError result = paNoError, *pres = NULL;
566 int err;
567 PaAlsaThreading *th = (PaAlsaThreading *) userData;
568 unsigned intervalMsec = 500;
569 const PaTime maxSeconds = 3.; /* Max seconds between callbacks */
570 PaTime timeThen = PaUtil_GetTime(), timeNow, timeElapsed, cpuTimeThen, cpuTimeNow, cpuTimeElapsed;
571 double cpuLoad, avgCpuLoad = 0.;
572 int throttled = 0;
573
574 assert( th );
575
576 /* Execute OnWatchdogExit when exiting */
577 pthread_cleanup_push( &OnWatchdogExit, th );
578
579 /* Boost priority of callback thread */
580 PA_ENSURE( result = BoostPriority( th ) );
581 if( !result )
582 {
583 /* Boost failed, might as well exit */
584 pthread_exit( NULL );
585 }
586
587 cpuTimeThen = th->callbackCpuTime;
588 {
589 int policy;
590 struct sched_param spm = { 0 };
591 pthread_getschedparam( pthread_self(), &policy, &spm );
592 PA_DEBUG(( "%s: Watchdog priority is %d\n", __FUNCTION__, spm.sched_priority ));
593 }
594
595 while( 1 )
596 {
597 double lowpassCoeff = 0.9, lowpassCoeff1 = 0.99999 - lowpassCoeff;
598
599 /* Test before and after in case whatever underlying sleep call isn't interrupted by pthread_cancel */
600 pthread_testcancel();
601 Pa_Sleep( intervalMsec );
602 pthread_testcancel();
603
604 if( PaUtil_GetTime() - th->callbackTime > maxSeconds )
605 {
606 PA_DEBUG(( "Watchdog: Terminating callback thread\n" ));
607 /* Tell thread to terminate */
608 err = pthread_kill( th->callbackThread, SIGKILL );
609 pthread_exit( NULL );
610 }
611
612 PA_DEBUG(( "%s: PortAudio reports CPU load: %g\n", __FUNCTION__, PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) ));
613
614 /* Check if we should throttle, or unthrottle :P */
615 cpuTimeNow = th->callbackCpuTime;
616 cpuTimeElapsed = cpuTimeNow - cpuTimeThen;
617 cpuTimeThen = cpuTimeNow;
618
619 timeNow = PaUtil_GetTime();
620 timeElapsed = timeNow - timeThen;
621 timeThen = timeNow;
622 cpuLoad = cpuTimeElapsed / timeElapsed;
623 avgCpuLoad = avgCpuLoad * lowpassCoeff + cpuLoad * lowpassCoeff1;
624 /*
625 if( throttled )
626 PA_DEBUG(( "Watchdog: CPU load: %g, %g\n", avgCpuLoad, cpuTimeElapsed ));
627 */
628 if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) > .925 )
629 {
630 static int policy;
631 static struct sched_param spm = { 0 };
632 static const struct sched_param defaultSpm = { 0 };
633 PA_DEBUG(( "%s: Throttling audio thread, priority %d\n", __FUNCTION__, spm.sched_priority ));
634
635 pthread_getschedparam( th->callbackThread, &policy, &spm );
636 if( !pthread_setschedparam( th->callbackThread, SCHED_OTHER, &defaultSpm ) )
637 {
638 throttled = 1;
639 }
640 else
641 PA_DEBUG(( "Watchdog: Couldn't lower priority of audio thread: %s\n", strerror( errno ) ));
642
643 /* Give other processes a go, before raising priority again */
644 PA_DEBUG(( "%s: Watchdog sleeping for %lu msecs before unthrottling\n", __FUNCTION__, th->throttledSleepTime ));
645 Pa_Sleep( th->throttledSleepTime );
646
647 /* Reset callback priority */
648 if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 )
649 {
650 PA_DEBUG(( "%s: Couldn't raise priority of audio thread: %s\n", __FUNCTION__, strerror( errno ) ));
651 }
652
653 if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) >= .99 )
654 intervalMsec = 50;
655 else
656 intervalMsec = 100;
657
658 /*
659 lowpassCoeff = .97;
660 lowpassCoeff1 = .99999 - lowpassCoeff;
661 */
662 }
663 else if( throttled && avgCpuLoad < .8 )
664 {
665 intervalMsec = 500;
666 throttled = 0;
667
668 /*
669 lowpassCoeff = .9;
670 lowpassCoeff1 = .99999 - lowpassCoeff;
671 */
672 }
673 }
674
675 pthread_cleanup_pop( 1 ); /* Execute cleanup on exit */
676
677 error:
678 /* Shouldn't get here in the normal case */
679
680 /* Pass on error code */
681 pres = malloc( sizeof (PaError) );
682 *pres = result;
683
684 pthread_exit( pres );
685 }
686
687 static void CallbackUpdate( PaAlsaThreading *th )
688 {
689 th->callbackTime = PaUtil_GetTime();
690 th->callbackCpuTime = PaUtil_GetCpuLoad( th->cpuLoadMeasurer );
691 }
692
693 /*
694 static void *CanaryFunc( void *userData )
695 {
696 const unsigned intervalMsec = 1000;
697 PaUtilThreading *th = (PaUtilThreading *) userData;
698
699 while( 1 )
700 {
701 th->canaryTime = PaUtil_GetTime();
702
703 pthread_testcancel();
704 Pa_Sleep( intervalMsec );
705 }
706
707 pthread_exit( NULL );
708 }
709 */
710 #endif
711