pa_linux_alsa: fix hang in callback caused by abort

The author of this patch is Alan Horstmann.

Fixes ticket #251
This commit is contained in:
Phil Burk 2016-09-14 08:50:33 -07:00
commit f17d549093

View file

@ -3805,8 +3805,23 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr
totalFds += self->playback.nfds;
}
#ifdef PTHREAD_CANCELED
if( self->callbackMode )
{
/* To allow 'Abort' to terminate the callback thread, enable cancelability just for poll() (& disable after) */
pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL );
}
#endif
pollResults = poll( self->pfds, totalFds, pollTimeout );
#ifdef PTHREAD_CANCELED
if( self->callbackMode )
{
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL );
}
#endif
if( pollResults < 0 )
{
/* XXX: Depend on preprocessor condition? */
@ -4175,12 +4190,18 @@ static void *CallbackThreadFunc( void *userData )
int streamStarted = 0;
assert( stream );
/* Not implemented */
assert( !stream->primeBuffers );
/* Execute OnExit when exiting */
pthread_cleanup_push( &OnExit, stream );
/* Not implemented */
assert( !stream->primeBuffers );
#ifdef PTHREAD_CANCELED
/* 'Abort' will use thread cancellation to terminate the callback thread, but the Alsa-lib functions
* are NOT cancel-safe, (and can end up in an inconsistent state). So, disable cancelability for
* the thread here, and just re-enable it for the poll() in PaAlsaStream_WaitForFrames(). */
pthread_testcancel();
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL );
#endif
/* @concern StreamStart If the output is being primed the output pcm needs to be prepared, otherwise the
* stream is started immediately. The latter involves signaling the waiting main thread.
@ -4265,10 +4286,6 @@ static void *CallbackThreadFunc( void *userData )
{
xrun = 0;
#ifdef PTHREAD_CANCELED
pthread_testcancel();
#endif
/** @concern Xruns Under/overflows are to be reported to the callback */
if( stream->underrun > 0.0 )
{
@ -4299,11 +4316,12 @@ static void *CallbackThreadFunc( void *userData )
#if 0
CallbackUpdate( &stream->threading );
#endif
CalculateTimeInfo( stream, &timeInfo );
PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags );
cbFlags = 0;
/* CPU load measurement should include processing activivity external to the stream callback */
/* CPU load measurement should include processing activity external to the stream callback */
PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
framesGot = framesAvail;
@ -4334,7 +4352,6 @@ static void *CallbackThreadFunc( void *userData )
{
/* Go back to polling for more frames */
break;
}
if( paContinue != callbackResult )