First we set the EOS state, so the wait_parser_stream_buffer function doesn't call pthread_cond_wait again. Then we must call pthread_cond_signal to make sure that no one is waiting for it, if we don't do that, there is the possibility of hanging wg_parser_disconnect at the free_stream call, because pthread_cond_destroy will hang when the cond object is being waited by other threads.
Specifically this helps to fix a hang in some applications, specially Unreal Engine games when changing sources too fast in a MediaPlayer.
From: Santino Mazza smazza@codeweavers.com
First we set the EOS state, so the wait_parser_stream_buffer function doesn't call pthread_cond_wait again. Then we must call pthread_cond_signal to make sure that no one is waiting for it, if we don't do that, there is the possibility of hanging wg_parser_disconnect at the free_stream call, because pthread_cond_destroy will hang when the cond object is being waited by other threads.
Specifically this helps to fix a hang in some applications, specially Unreal Engine games when changing sources too fast in a MediaPlayer. --- dlls/winegstreamer/wg_parser.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index ef274b1dc27..b99ef9dbe31 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -1708,6 +1708,8 @@ static NTSTATUS wg_parser_disconnect(void *args) for (i = 0; i < parser->stream_count; ++i) { parser->streams[i]->flushing = true; + parser->streams[i]->eos = true; + pthread_cond_signal(&parser->streams[i]->event_cond); pthread_cond_signal(&parser->streams[i]->event_empty_cond); } pthread_mutex_unlock(&parser->mutex);
The intended API contract is that streaming threads can't still be running when we call wg_parser_destroy(). In quartz and wmvcore they should have been stopped already. From reading mfplat code it doesn't look like it should be possible to hit this case either: source_async_commands_Invoke() grabs the source cs and checks its state inside that cs; media_source_Shutdown() also grabs the cs and sets the state inside that CS.
How exactly are you seeing this deadlock? What's the backtrace look like?
Mmm, I just realized that the hangs happens when the game calls media_source_Shutdown and the source is in the running state. Like this ``` 0288:trace:mfplat:media_source_Shutdown 00000000117942F0 state 1. 0288:trace:mfplat:media_source_Shutdown returning wg_parser_disconnect 0288:trace:mfplat:media_source_Shutdown 00000000117942F0 state 4. 0134:trace:mfplat:media_source_Shutdown 0000000011B1EFD0 state 1. 0134:trace:mfplat:media_source_Shutdown returning wg_parser_disconnect 0134:trace:mfplat:media_source_Shutdown 0000000011B1EFD0 state 4. 0134:trace:mfplat:media_source_Shutdown 0000000001F28C00 state 1. 0134:trace:mfplat:media_source_Shutdown returning wg_parser_disconnect 0134:trace:mfplat:media_source_Shutdown 0000000001F28C00 state 4. 01f8:trace:mfplat:media_source_Shutdown 0000000011794370 state 3. 01f8:trace:mfplat:media_source_Shutdown returning wg_parser_disconnect 0218:trace:mfplat:media_source_Shutdown 0000000011B1EFD0 state 1. 0218:trace:mfplat:media_source_Shutdown returning wg_parser_disconnect 0218:trace:mfplat:media_source_Shutdown 0000000011B1EFD0 state 4. 01e8:trace:mfplat:media_source_Shutdown 000000007844FC50 state 1. 01e8:trace:mfplat:media_source_Shutdown returning wg_parser_disconnect 01e8:trace:mfplat:media_source_Shutdown 000000007844FC50 state 4. 021c:trace:mfplat:media_source_Shutdown 0000000001F28C00 state 1. 021c:trace:mfplat:media_source_Shutdown returning wg_parser_disconnect 021c:trace:mfplat:media_source_Shutdown 0000000001F28C00 state 4. 0200:trace:mfplat:media_source_Shutdown 0000000011794870 state 3. ```
Normally it calls Shutdown when the source is in the 1 state (Stopped), in that state it calls wg_parser_disconnect, which in turn calls free_stream. When it's in the 4 state (Shutdown) it doesn't do anything, but at the end it's in the 3 state (Running), and there it calls wg_parser_disconnect but never returns, because it hangs at free_stream.
I've tried to reproduce the bug, but apprently if I call IMFMediaSource::Shutdown after the session starts in windows it will hang when trying to Close the session, but in wine it only crashes.
This merge request was closed by Santino Mazza.
Already fixed in upstream.