From: Paul Gofman pgofman@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);
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.