From 758d5a492f6e7a7bc6741766c7f2d54f8ddcead1 Mon Sep 17 00:00:00 2001 From: Tuukka Pasanen Date: Sat, 19 Oct 2024 10:23:28 +0300 Subject: [PATCH 1/2] Pulseaudio: Termination stream before operation release can lead locking Cases when Pulseaudio server releases stream before operation releasing can be lead locking in pa_threaded_mainloop_wait forever. Test if operation is running before running pa_threaded_mainloop_wait which should prevent forever waiting releasing lock. --- src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c b/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c index b298cf713..92fdb5365 100644 --- a/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c +++ b/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c @@ -119,21 +119,23 @@ void PaPulseAudio_ReleaseOperation(PaPulseAudio_HostApiRepresentation *hostapi, while( waitOperation > 0 ) { - PaPulseAudio_Lock( hostapi->mainloop ); - pa_threaded_mainloop_wait( hostapi->mainloop ); - PaPulseAudio_UnLock( hostapi->mainloop ); + PaPulseAudio_Lock( hostapi->mainloop ); localOperationState = pa_operation_get_state( localOperation ); - // No wait if operation have been DONE or CANCELLED - if( localOperationState != PA_OPERATION_RUNNING) + if( localOperationState == PA_OPERATION_RUNNING ) + { + pa_threaded_mainloop_wait( hostapi->mainloop ); + } + else { + // Result is DONE or CANCEL + PaPulseAudio_UnLock( hostapi->mainloop ); break; } + PaPulseAudio_UnLock( hostapi->mainloop ); waitOperation --; - - usleep( 1000 ); } // No wait if operation have been DONE or CANCELLED From 80b11687c59ea9f2195b799e01b5793116c73c20 Mon Sep 17 00:00:00 2001 From: Tuukka Pasanen Date: Sun, 24 Nov 2024 10:55:06 +0200 Subject: [PATCH 2/2] Pulseaudio: Debug print if we are in main thread As documentation says: This function may not be called inside the event loop thread. Events that are dispatched from the event loop thread are executed with this lock held. Add small debug print that makes sure that future code won't be calling it from main thread. --- src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c b/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c index 92fdb5365..4c86c7d57 100644 --- a/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c +++ b/src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c @@ -158,6 +158,12 @@ void PaPulseAudio_Lock( pa_threaded_mainloop *mainloop ) if( !pa_threaded_mainloop_in_thread( mainloop ) ) { pa_threaded_mainloop_lock( mainloop ); } + else + { + PA_DEBUG( ("Portaudio %s: Called from event loop thread as value is: %d (not locked)\n", + __FUNCTION__, + pa_threaded_mainloop_in_thread( mainloop )) ); + } } /* unlocks the Pulse Main loop when not called from it */ @@ -166,6 +172,12 @@ void PaPulseAudio_UnLock( pa_threaded_mainloop *mainloop ) if( !pa_threaded_mainloop_in_thread( mainloop ) ) { pa_threaded_mainloop_unlock( mainloop ); } + else + { + PA_DEBUG( ("Portaudio %s: Called from event loop thread as value is: %d (not unlocked)\n", + __FUNCTION__, + pa_threaded_mainloop_in_thread( mainloop )) ); + } } void _PaPulseAudio_WriteRingBuffer( PaUtilRingBuffer *ringbuffer,