From: Zebediah Figura zfigura@codeweavers.com
The code originally intended to achieve this by simply waiting on flushing_cs, and having the application thread hold flushing_cs while seeking. Unfortunately, this can result in starvation of the application thread, since the streaming thread always reacquires flushing_cs immediately after releasing it. Avoid this by using a separate condition variable.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53403 Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/quartz_parser.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-)
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 36ca84debba..5561b106327 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -54,20 +54,23 @@ struct parser
struct wg_parser *wg_parser;
- /* This protects the "streaming" field, accessed by both the application - * and streaming threads. + /* This protects the "streaming" and "flushing" fields, accessed by both + * the application and streaming threads. * We cannot use the filter lock for this, since that is held while waiting * for the streaming thread, and hence the streaming thread cannot take the * filter lock. * This lock must not be acquired before acquiring the filter lock or * flushing_cs. */ CRITICAL_SECTION streaming_cs; + CONDITION_VARIABLE flushing_cv;
/* FIXME: It would be nice to avoid duplicating these with strmbase. * However, synchronization is tricky; we need access to be protected by a * separate lock. */ bool streaming, sink_connected;
+ bool flushing; + HANDLE read_thread;
BOOL (*init_gst)(struct parser *filter); @@ -986,11 +989,16 @@ static DWORD CALLBACK stream_thread(void *arg) struct wg_parser_buffer buffer;
EnterCriticalSection(&filter->streaming_cs); + + while (filter->flushing) + SleepConditionVariableCS(&filter->flushing_cv, &filter->streaming_cs, INFINITE); + if (!filter->streaming) { LeaveCriticalSection(&filter->streaming_cs); break; } + LeaveCriticalSection(&filter->streaming_cs);
EnterCriticalSection(&pin->flushing_cs); @@ -1384,6 +1392,8 @@ static HRESULT parser_create(enum wg_parser_type type, struct parser **parser) InitializeCriticalSection(&object->streaming_cs); object->streaming_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": parser.streaming_cs");
+ InitializeConditionVariable(&object->flushing_cv); + *parser = object; return S_OK; } @@ -1532,8 +1542,13 @@ static HRESULT WINAPI GST_Seeking_SetPositions(IMediaSeeking *iface, IAsyncReader_BeginFlush(filter->reader); }
- /* Acquire the flushing locks. This blocks the streaming threads, and - * ensures the seek is serialized between flushes. */ + /* Signal the streaming threads to "pause". */ + EnterCriticalSection(&filter->streaming_cs); + filter->flushing = true; + LeaveCriticalSection(&filter->streaming_cs); + + /* Acquire the flushing locks, to make sure the streaming threads really + * are paused. This ensures the seek is serialized between flushes. */ for (i = 0; i < filter->source_count; ++i) { struct parser_source *flush_pin = filter->sources[i]; @@ -1576,6 +1591,12 @@ static HRESULT WINAPI GST_Seeking_SetPositions(IMediaSeeking *iface, } }
+ /* Signal the streaming threads to resume. */ + EnterCriticalSection(&filter->streaming_cs); + filter->flushing = false; + LeaveCriticalSection(&filter->streaming_cs); + WakeConditionVariable(&filter->flushing_cv); + return S_OK; }