[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