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; 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 ); pollResults = poll( self->pfds, totalFds, pollTimeout );
#ifdef PTHREAD_CANCELED
if( self->callbackMode )
{
pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL );
}
#endif
if( pollResults < 0 ) if( pollResults < 0 )
{ {
/* XXX: Depend on preprocessor condition? */ /* XXX: Depend on preprocessor condition? */
@ -4175,12 +4190,18 @@ static void *CallbackThreadFunc( void *userData )
int streamStarted = 0; int streamStarted = 0;
assert( stream ); assert( stream );
/* Not implemented */
assert( !stream->primeBuffers );
/* Execute OnExit when exiting */ /* Execute OnExit when exiting */
pthread_cleanup_push( &OnExit, stream ); pthread_cleanup_push( &OnExit, stream );
#ifdef PTHREAD_CANCELED
/* Not implemented */ /* 'Abort' will use thread cancellation to terminate the callback thread, but the Alsa-lib functions
assert( !stream->primeBuffers ); * 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 /* @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. * stream is started immediately. The latter involves signaling the waiting main thread.
@ -4265,10 +4286,6 @@ static void *CallbackThreadFunc( void *userData )
{ {
xrun = 0; xrun = 0;
#ifdef PTHREAD_CANCELED
pthread_testcancel();
#endif
/** @concern Xruns Under/overflows are to be reported to the callback */ /** @concern Xruns Under/overflows are to be reported to the callback */
if( stream->underrun > 0.0 ) if( stream->underrun > 0.0 )
{ {
@ -4299,11 +4316,12 @@ static void *CallbackThreadFunc( void *userData )
#if 0 #if 0
CallbackUpdate( &stream->threading ); CallbackUpdate( &stream->threading );
#endif #endif
CalculateTimeInfo( stream, &timeInfo ); CalculateTimeInfo( stream, &timeInfo );
PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags ); PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags );
cbFlags = 0; 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 ); PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
framesGot = framesAvail; framesGot = framesAvail;
@ -4334,7 +4352,6 @@ static void *CallbackThreadFunc( void *userData )
{ {
/* Go back to polling for more frames */ /* Go back to polling for more frames */
break; break;
} }
if( paContinue != callbackResult ) if( paContinue != callbackResult )