[PATCH 0/1] MR8495: winepulse.drv: Avoid hangs on exit when pulse main loop thread gets killed.
From: Paul Gofman <pgofman(a)codeweavers.com> --- dlls/winepulse.drv/pulse.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c index e83ef64e887..4b287578e8b 100644 --- a/dlls/winepulse.drv/pulse.c +++ b/dlls/winepulse.drv/pulse.c @@ -209,10 +209,10 @@ static BOOL wait_pa_operation_complete(pa_operation *o) if (!o) return FALSE; - while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) + while (pulse_ml && pa_operation_get_state(o) == PA_OPERATION_RUNNING) pulse_cond_wait(); pa_operation_unref(o); - return TRUE; + return !!pulse_ml; } /* Following pulseaudio design here, mainloop has the lock taken whenever @@ -244,6 +244,7 @@ static NTSTATUS pulse_process_attach(void *args) pthread_mutexattr_init(&attr); pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT); + pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST); if (pthread_mutex_init(&pulse_mutex, &attr) != 0) pthread_mutex_init(&pulse_mutex, NULL); @@ -275,6 +276,14 @@ static NTSTATUS pulse_process_detach(void *args) return STATUS_SUCCESS; } +static void pulse_main_loop_thread_cleanup(void *context) +{ + TRACE("Main loop thread is being aborted.\n"); + + pulse_ml = NULL; + pulse_broadcast(); +} + static NTSTATUS pulse_main_loop(void *args) { struct main_loop_params *params = args; @@ -283,7 +292,9 @@ static NTSTATUS pulse_main_loop(void *args) pulse_ml = pa_mainloop_new(); pa_mainloop_set_poll_func(pulse_ml, pulse_poll_func, NULL); NtSetEvent(params->event, NULL); + pthread_cleanup_push(pulse_main_loop_thread_cleanup, NULL); pa_mainloop_run(pulse_ml, &ret); + pthread_cleanup_pop(0); pa_mainloop_free(pulse_ml); pulse_unlock(); return STATUS_SUCCESS; @@ -1247,7 +1258,7 @@ static NTSTATUS pulse_release_stream(void *args) pulse_lock(); if (PA_STREAM_IS_GOOD(pa_stream_get_state(stream->stream))) { pa_stream_disconnect(stream->stream); - while (PA_STREAM_IS_GOOD(pa_stream_get_state(stream->stream))) + while (pulse_ml && PA_STREAM_IS_GOOD(pa_stream_get_state(stream->stream))) pulse_cond_wait(); } pa_stream_unref(stream->stream); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/8495
When a thread executtes NtTerminateProcess(self), all the other threads get killed by wineserver. Then, if self-terminating thread tries to tear down mmdevapi streams during loader shutdown sequence, wait operations on stream hang forever waiting for the condition which can only be set from PA main loop thread. Fixes hang on exit in Warrior Maiden Lecia and the Lost Fortress. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8495#note_108692
This merge request was approved by Huw Davies. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/8495
participants (3)
-
Huw Davies (@huw) -
Paul Gofman -
Paul Gofman (@gofman)