[PATCH 3/5] amstream: Add a second critical section for filter methods that are called from streams.

Anton Baskanov baskanov at gmail.com
Tue Apr 6 13:04:34 CDT 2021


Signed-off-by: Anton Baskanov <baskanov at gmail.com>
---
This is required to avoid deadlocks, e.g. when the filter is stopped
while EndOfStream is being called.
---
 dlls/amstream/filter.c | 88 +++++++++++++++++++++++++++++++-----------
 1 file changed, 65 insertions(+), 23 deletions(-)

diff --git a/dlls/amstream/filter.c b/dlls/amstream/filter.c
index 3c0436a294f..6fac4b9b4b7 100644
--- a/dlls/amstream/filter.c
+++ b/dlls/amstream/filter.c
@@ -167,7 +167,9 @@ struct filter
     IMediaSeeking IMediaSeeking_iface;
     LONG refcount;
     CRITICAL_SECTION cs;
+    CRITICAL_SECTION stream_cs;
 
+    /* Protected either by cs or stream_cs, lock both when modifying. */
     IReferenceClock *clock;
     WCHAR name[128];
     IFilterGraph *graph;
@@ -176,6 +178,8 @@ struct filter
     IAMMediaStream *seekable_stream;
     FILTER_STATE state;
     REFERENCE_TIME start_time;
+
+    /* Protected by stream_cs. */
     struct list free_events;
     struct list used_events;
 };
@@ -253,6 +257,7 @@ static ULONG WINAPI filter_Release(IMediaStreamFilter *iface)
         heap_free(filter->streams);
         if (filter->clock)
             IReferenceClock_Release(filter->clock);
+        DeleteCriticalSection(&filter->stream_cs);
         DeleteCriticalSection(&filter->cs);
         heap_free(filter);
     }
@@ -266,28 +271,28 @@ static HRESULT WINAPI filter_GetClassID(IMediaStreamFilter *iface, CLSID *clsid)
     return S_OK;
 }
 
-static void set_state(struct filter *filter, FILTER_STATE state)
-{
-    if (filter->state != state)
-    {
-        ULONG i;
-
-        for (i = 0; i < filter->nb_streams; ++i)
-            IAMMediaStream_SetState(filter->streams[i], state);
-        filter->state = state;
-    }
-}
-
 static HRESULT WINAPI filter_Stop(IMediaStreamFilter *iface)
 {
     struct filter *filter = impl_from_IMediaStreamFilter(iface);
     struct event *event;
+    ULONG i;
 
     TRACE("iface %p.\n", iface);
 
     EnterCriticalSection(&filter->cs);
 
-    set_state(filter, State_Stopped);
+    if (filter->state == State_Stopped)
+    {
+        LeaveCriticalSection(&filter->cs);
+        return S_OK;
+    }
+
+    for (i = 0; i < filter->nb_streams; ++i)
+        IAMMediaStream_SetState(filter->streams[i], State_Stopped);
+
+    EnterCriticalSection(&filter->stream_cs);
+
+    filter->state = State_Stopped;
 
     LIST_FOR_EACH_ENTRY(event, &filter->used_events, struct event, entry)
     {
@@ -299,6 +304,7 @@ static HRESULT WINAPI filter_Stop(IMediaStreamFilter *iface)
         }
     }
 
+    LeaveCriticalSection(&filter->stream_cs);
     LeaveCriticalSection(&filter->cs);
 
     return S_OK;
@@ -307,12 +313,24 @@ static HRESULT WINAPI filter_Stop(IMediaStreamFilter *iface)
 static HRESULT WINAPI filter_Pause(IMediaStreamFilter *iface)
 {
     struct filter *filter = impl_from_IMediaStreamFilter(iface);
+    ULONG i;
 
     TRACE("iface %p.\n", iface);
 
     EnterCriticalSection(&filter->cs);
 
-    set_state(filter, State_Paused);
+    if (filter->state == State_Paused)
+    {
+        LeaveCriticalSection(&filter->cs);
+        return S_OK;
+    }
+
+    EnterCriticalSection(&filter->stream_cs);
+    filter->state = State_Paused;
+    LeaveCriticalSection(&filter->stream_cs);
+
+    for (i = 0; i < filter->nb_streams; ++i)
+        IAMMediaStream_SetState(filter->streams[i], State_Paused);
 
     LeaveCriticalSection(&filter->cs);
 
@@ -322,13 +340,27 @@ static HRESULT WINAPI filter_Pause(IMediaStreamFilter *iface)
 static HRESULT WINAPI filter_Run(IMediaStreamFilter *iface, REFERENCE_TIME start)
 {
     struct filter *filter = impl_from_IMediaStreamFilter(iface);
+    ULONG i;
 
     TRACE("iface %p, start %s.\n", iface, wine_dbgstr_longlong(start));
 
     EnterCriticalSection(&filter->cs);
 
+    if (filter->state == State_Running)
+    {
+        LeaveCriticalSection(&filter->cs);
+        return S_OK;
+    }
+
+    EnterCriticalSection(&filter->stream_cs);
+
+    filter->state = State_Running;
     filter->start_time = start;
-    set_state(filter, State_Running);
+
+    LeaveCriticalSection(&filter->stream_cs);
+
+    for (i = 0; i < filter->nb_streams; ++i)
+        IAMMediaStream_SetState(filter->streams[i], State_Running);
 
     LeaveCriticalSection(&filter->cs);
 
@@ -360,6 +392,7 @@ static HRESULT WINAPI filter_SetSyncSource(IMediaStreamFilter *iface, IReference
     TRACE("iface %p, clock %p.\n", iface, clock);
 
     EnterCriticalSection(&filter->cs);
+    EnterCriticalSection(&filter->stream_cs);
 
     if (clock)
         IReferenceClock_AddRef(clock);
@@ -367,6 +400,7 @@ static HRESULT WINAPI filter_SetSyncSource(IMediaStreamFilter *iface, IReference
         IReferenceClock_Release(filter->clock);
     filter->clock = clock;
 
+    LeaveCriticalSection(&filter->stream_cs);
     LeaveCriticalSection(&filter->cs);
 
     return S_OK;
@@ -491,6 +525,7 @@ static HRESULT WINAPI filter_JoinFilterGraph(IMediaStreamFilter *iface,
     TRACE("iface %p, graph %p, name.%s.\n", iface, graph, debugstr_w(name));
 
     EnterCriticalSection(&filter->cs);
+    EnterCriticalSection(&filter->stream_cs);
 
     if (name)
         wcsncpy(filter->name, name, ARRAY_SIZE(filter->name));
@@ -498,6 +533,7 @@ static HRESULT WINAPI filter_JoinFilterGraph(IMediaStreamFilter *iface,
         filter->name[0] = 0;
     filter->graph = graph;
 
+    LeaveCriticalSection(&filter->stream_cs);
     LeaveCriticalSection(&filter->cs);
 
     return S_OK;
@@ -624,6 +660,8 @@ static HRESULT WINAPI filter_SupportSeeking(IMediaStreamFilter *iface, BOOL rend
         return HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
     }
 
+    EnterCriticalSection(&filter->stream_cs);
+
     for (i = 0; i < filter->nb_streams; ++i)
     {
         IMediaSeeking *seeking = get_seeking(filter->streams[i]);
@@ -636,6 +674,7 @@ static HRESULT WINAPI filter_SupportSeeking(IMediaStreamFilter *iface, BOOL rend
         {
             filter->seekable_stream = filter->streams[i];
             IMediaSeeking_Release(seeking);
+            LeaveCriticalSection(&filter->stream_cs);
             LeaveCriticalSection(&filter->cs);
             return S_OK;
         }
@@ -643,6 +682,7 @@ static HRESULT WINAPI filter_SupportSeeking(IMediaStreamFilter *iface, BOOL rend
         IMediaSeeking_Release(seeking);
     }
 
+    LeaveCriticalSection(&filter->stream_cs);
     LeaveCriticalSection(&filter->cs);
     return E_NOINTERFACE;
 }
@@ -704,11 +744,11 @@ static HRESULT WINAPI filter_WaitUntil(IMediaStreamFilter *iface, REFERENCE_TIME
 
     TRACE("filter %p, time %s.\n", iface, wine_dbgstr_longlong(time));
 
-    EnterCriticalSection(&filter->cs);
+    EnterCriticalSection(&filter->stream_cs);
 
     if (!filter->clock)
     {
-        LeaveCriticalSection(&filter->cs);
+        LeaveCriticalSection(&filter->stream_cs);
         return E_FAIL;
     }
 
@@ -729,23 +769,23 @@ static HRESULT WINAPI filter_WaitUntil(IMediaStreamFilter *iface, REFERENCE_TIME
     if (FAILED(hr))
     {
         list_add_tail(&filter->free_events, entry);
-        LeaveCriticalSection(&filter->cs);
+        LeaveCriticalSection(&filter->stream_cs);
         return hr;
     }
 
     event->interrupted = FALSE;
     list_add_tail(&filter->used_events, entry);
 
-    LeaveCriticalSection(&filter->cs);
+    LeaveCriticalSection(&filter->stream_cs);
     WaitForSingleObject(event->event, INFINITE);
-    EnterCriticalSection(&filter->cs);
+    EnterCriticalSection(&filter->stream_cs);
 
     hr = event->interrupted ? S_FALSE : S_OK;
 
     list_remove(entry);
     list_add_tail(&filter->free_events, entry);
 
-    LeaveCriticalSection(&filter->cs);
+    LeaveCriticalSection(&filter->stream_cs);
 
     return hr;
 }
@@ -757,7 +797,7 @@ static HRESULT WINAPI filter_Flush(IMediaStreamFilter *iface, BOOL cancel_eos)
 
     TRACE("filter %p, cancel_eos %d.\n", iface, cancel_eos);
 
-    EnterCriticalSection(&filter->cs);
+    EnterCriticalSection(&filter->stream_cs);
 
     LIST_FOR_EACH_ENTRY(event, &filter->used_events, struct event, entry)
     {
@@ -769,7 +809,7 @@ static HRESULT WINAPI filter_Flush(IMediaStreamFilter *iface, BOOL cancel_eos)
         }
     }
 
-    LeaveCriticalSection(&filter->cs);
+    LeaveCriticalSection(&filter->stream_cs);
 
     return S_OK;
 }
@@ -1064,6 +1104,8 @@ HRESULT filter_create(IUnknown *outer, void **out)
     list_init(&object->used_events);
     InitializeCriticalSection(&object->cs);
     object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MediaStreamFilter.cs");
+    InitializeCriticalSection(&object->stream_cs);
+    object->stream_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MediaStreamFilter.stream_cs");
 
     TRACE("Created media stream filter %p.\n", object);
     *out = &object->IMediaStreamFilter_iface;
-- 
2.25.1




More information about the wine-devel mailing list