To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at https://github.com/sonic-visualiser/sv-dependency-builds .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / src / portaudio_20161030_catalina_patch / src / os / unix / pa_unix_util.c @ 162:d43aab368df9

History | View | Annotate | Download (20.1 KB)

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

    
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

    
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

    
98
int PaUtil_CountCurrentlyAllocatedBlocks( void )
99
{
100
#if PA_TRACK_MEMORY
101
    return numAllocations_;
102
#else
103
    return 0;
104
#endif
105
}
106

    
107

    
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

    
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

    
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

    
172
PaError PaUtil_InitializeThreading( PaUtilThreading *threading )
173
{
174
    (void) paUtilErr_;
175
    return paNoError;
176
}
177

    
178
void PaUtil_TerminateThreading( PaUtilThreading *threading )
179
{
180
}
181

    
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

    
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

    
239
PaError PaUnixThreading_Initialize()
240
{
241
    paUnixMainThread = pthread_self();
242
    return paNoError;
243
}
244

    
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

    
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

    
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

    
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

    
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

    
495
int PaUnixThread_StopRequested( PaUnixThread* self )
496
{
497
    return self->stopRequested;
498
}
499

    
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

    
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
 */
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
 */
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