static int PaHost_CanaryProc( PaHostSoundControl *pahsc ) { int result = 0; #ifdef GNUSTEP GSRegisterCurrentThread(); /* SB20010904 */ #endif while( pahsc->pahsc_CanaryRun) { usleep( WATCHDOG_INTERVAL_USEC ); gettimeofday( &pahsc->pahsc_CanaryTime, NULL ); } DBUG(("PaHost_CanaryProc: exiting.\n")); #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif return result; }
static PaError Pa_AudioThreadProc( internalPortAudioStream *past ) { PaError result; PaHostSoundControl *pahsc; ssize_t bytes_read, bytes_written; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paInternalError; #ifdef GNUSTEP GSRegisterCurrentThread(); /* SB20010904 */ #endif result = PaHost_BoostPriority( past ); if( result < 0 ) goto error; past->past_IsActive = 1; DBUG(("entering thread.\n")); while( (past->past_StopNow == 0) && (past->past_StopSoon == 0) ) { /* Read data from device */ if(pahsc->pahsc_NativeInputBuffer) { unsigned int totalread = 0; DBUG(("Pa_AudioThreadProc: attempt to read %d bytes\n", pahsc->pahsc_BytesPerInputBuffer)); do { bytes_read = read(pahsc->pahsc_InputHandle, (char *)pahsc->pahsc_NativeInputBuffer + totalread, pahsc->pahsc_BytesPerInputBuffer - totalread); if (bytes_read < 0) { ERR_RPT(("PortAudio: read interrupted!\n")); break; } totalread += bytes_read; } while( totalread < pahsc->pahsc_BytesPerInputBuffer); } /* Convert 16 bit native data to user data and call user routine. */ DBUG(("converting...\n")); Pa_StartUsageCalculation( past ); result = Pa_CallConvertInt16( past, pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_NativeOutputBuffer ); Pa_EndUsageCalculation( past ); if( result != 0) { DBUG(("hmm, Pa_CallConvertInt16() says: %d. i'm bailing.\n", result)); break; } /* Write data to device. */ if( pahsc->pahsc_NativeOutputBuffer ) { unsigned int totalwritten = 0; do { bytes_written = write(pahsc->pahsc_OutputHandle, (void *)pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer); if( bytes_written < 0 ) { ERR_RPT(("PortAudio: write interrupted!")); break; } totalwritten += bytes_written; } while( totalwritten < pahsc->pahsc_BytesPerOutputBuffer); } Pa_UpdateStreamTime(pahsc); } DBUG(("Pa_AudioThreadProc: left audio loop.\n")); past->past_IsActive = 0; PaHost_StopWatchDog( pahsc ); error: DBUG(("leaving audio thread.\n")); #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif return result; }
static PaError PaHost_WatchDogProc( PaHostSoundControl *pahsc ) { struct sched_param schp = { 0 }; int maxPri; #ifdef GNUSTEP GSRegisterCurrentThread(); /* SB20010904 */ #endif /* Run at a priority level above audio thread so we can still run if it hangs. */ /* Rise more than 1 because of rumored off-by-one scheduler bugs. */ schp.sched_priority = pahsc->pahsc_AudioPriority + 4; maxPri = sched_get_priority_max(SCHEDULER_POLICY); if( schp.sched_priority > maxPri ) schp.sched_priority = maxPri; if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0) { ERR_RPT(("PaHost_WatchDogProc: cannot set watch dog priority!\n")); goto killAudio; } /* Compare watchdog time with audio and canary thread times. */ /* Sleep for a while or until thread cancelled. */ while( pahsc->pahsc_WatchDogRun ) { int delta; struct timeval currentTime; usleep( WATCHDOG_INTERVAL_USEC ); gettimeofday( ¤tTime, NULL ); /* If audio thread is not advancing, then it must be hung so kill it. */ delta = currentTime.tv_sec - pahsc->pahsc_EntryTime.tv_sec; DBUG(("PaHost_WatchDogProc: audio delta = %d\n", delta )); if( delta > WATCHDOG_MAX_SECONDS ) { goto killAudio; } /* If canary died, then lower audio priority and halt canary. */ delta = currentTime.tv_sec - pahsc->pahsc_CanaryTime.tv_sec; if( delta > WATCHDOG_MAX_SECONDS ) { ERR_RPT(("PaHost_WatchDogProc: canary died!\n")); goto lowerAudio; } } DBUG(("PaHost_WatchDogProc: exiting.\n")); #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif return 0; lowerAudio: { struct sched_param schat = { 0 }; if( sched_setscheduler(pahsc->pahsc_AudioThreadPID, SCHED_OTHER, &schat) != 0) { ERR_RPT(("PaHost_WatchDogProc: failed to lower audio priority. errno = %d\n", errno )); /* Fall through into killing audio thread. */ } else { ERR_RPT(("PaHost_WatchDogProc: lowered audio priority to prevent hogging of CPU.\n")); goto cleanup; } } killAudio: ERR_RPT(("PaHost_WatchDogProc: killing hung audio thread!\n")); pthread_kill( pahsc->pahsc_AudioThread, SIGKILL ); cleanup: pahsc->pahsc_CanaryRun = 0; DBUG(("PaHost_WatchDogProc: cancel Canary\n")); pthread_cancel( pahsc->pahsc_CanaryThread ); DBUG(("PaHost_WatchDogProc: join Canary\n")); pthread_join( pahsc->pahsc_CanaryThread, NULL ); DBUG(("PaHost_WatchDogProc: forget Canary\n")); pahsc->pahsc_IsCanaryThreadValid = 0; #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif return 0; }
static int WatchDogProc( prioboost *b ) { struct sched_param schp = { 0 }; int maxPri; /* Run at a priority level above main thread so we can still run if it hangs. */ /* Rise more than 1 because of rumored off-by-one scheduler bugs. */ schp.sched_priority = b->priority + 4; maxPri = sched_get_priority_max(SCHEDULER_POLICY); if( schp.sched_priority > maxPri ) schp.sched_priority = maxPri; if (pthread_setschedparam(pthread_self(), SCHEDULER_POLICY, &schp) != 0) { ERR_RPT("WatchDogProc: cannot set watch dog priority!\n"); goto killAudio; } DBUG("prioboost: WatchDog priority set to level %d!\n", schp.sched_priority); /* Compare watchdog time with audio and canary thread times. */ /* Sleep for a while or until thread cancelled. */ while( b->WatchDogRun ) { int delta; struct timeval currentTime; usleep( WATCHDOG_INTERVAL_USEC ); gettimeofday( ¤tTime, NULL ); #if 0 /* If audio thread is not advancing, then it must be hung so kill it. */ delta = currentTime.tv_sec - b->EntryTime.tv_sec; DBUG(("WatchDogProc: audio delta = %d\n", delta )); if( delta > WATCHDOG_MAX_SECONDS ) { goto killAudio; } #endif /* If canary died, then lower audio priority and halt canary. */ delta = currentTime.tv_sec - b->CanaryTime.tv_sec; DBUG("WatchDogProc: dogging, delta = %ld, mysec=%d\n", delta, currentTime.tv_sec); if( delta > WATCHDOG_MAX_SECONDS ) { ERR_RPT("WatchDogProc: canary died!\n"); goto lowerAudio; } } DBUG("WatchDogProc: exiting.\n"); return 0; lowerAudio: { struct sched_param schat = { 0 }; if( pthread_setschedparam(b->ThreadID, SCHED_OTHER, &schat) != 0) { ERR_RPT("WatchDogProc: failed to lower audio priority. errno = %d\n", errno ); /* Fall through into killing audio thread. */ } else { ERR_RPT("WatchDogProc: lowered audio priority to prevent hogging of CPU.\n"); goto cleanup; } } killAudio: ERR_RPT("WatchDogProc: killing hung audio thread!\n"); //pthread_cancel( b->ThreadID); //pthread_join( b->ThreadID); exit(1); cleanup: b->CanaryRun = 0; DBUG("WatchDogProc: cancel Canary\n"); pthread_cancel( b->CanaryThread ); DBUG("WatchDogProc: join Canary\n"); pthread_join( b->CanaryThread, NULL ); DBUG("WatchDogProc: forget Canary\n"); b->IsCanaryThreadValid = 0; #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif return 0; }