Bernhard Kölbl : windows.media.speech: Make IAsyncAction concurrent.
Alexandre Julliard
julliard at winehq.org
Tue May 24 15:55:00 CDT 2022
Module: wine
Branch: master
Commit: c6ab933bc3433dfa86d6a05c7a8b7d2bc7ef19de
URL: https://source.winehq.org/git/wine.git/?a=commit;h=c6ab933bc3433dfa86d6a05c7a8b7d2bc7ef19de
Author: Bernhard Kölbl <besentv at gmail.com>
Date: Tue May 3 16:34:55 2022 +0200
windows.media.speech: Make IAsyncAction concurrent.
Signed-off-by: Bernhard Kölbl <besentv at gmail.com>
---
dlls/windows.media.speech/async.c | 75 ++++++++++++++++++++++++++++++++--
dlls/windows.media.speech/private.h | 3 +-
dlls/windows.media.speech/recognizer.c | 7 +++-
3 files changed, 80 insertions(+), 5 deletions(-)
diff --git a/dlls/windows.media.speech/async.c b/dlls/windows.media.speech/async.c
index 3d67b90060e..5d20fe482f1 100644
--- a/dlls/windows.media.speech/async.c
+++ b/dlls/windows.media.speech/async.c
@@ -40,6 +40,11 @@ struct async_void
IAsyncActionCompletedHandler *handler;
+ async_action_callback callback;
+ TP_WORK *async_run_work;
+ IInspectable *invoker;
+
+ CRITICAL_SECTION cs;
AsyncStatus status;
HRESULT hr;
};
@@ -116,6 +121,7 @@ HRESULT WINAPI async_void_put_Completed( IAsyncAction *iface, IAsyncActionComple
TRACE("iface %p, handler %p.\n", iface, handler);
+ EnterCriticalSection(&impl->cs);
if (impl->status == Closed)
hr = E_ILLEGAL_METHOD_CALL;
else if (impl->handler != HANDLER_NOT_SET)
@@ -133,11 +139,15 @@ HRESULT WINAPI async_void_put_Completed( IAsyncAction *iface, IAsyncActionComple
IAsyncAction *action = &impl->IAsyncAction_iface;
AsyncStatus status = impl->status;
impl->handler = NULL; /* Prevent concurrent invoke. */
+ LeaveCriticalSection(&impl->cs);
IAsyncActionCompletedHandler_Invoke(handler, action, status);
IAsyncActionCompletedHandler_Release(handler);
+
+ return S_OK;
}
}
+ LeaveCriticalSection(&impl->cs);
return hr;
}
@@ -149,9 +159,11 @@ HRESULT WINAPI async_void_get_Completed( IAsyncAction *iface, IAsyncActionComple
FIXME("iface %p, handler %p semi stub!\n", iface, handler);
+ EnterCriticalSection(&impl->cs);
if (impl->status == Closed)
hr = E_ILLEGAL_METHOD_CALL;
*handler = (impl->handler != HANDLER_NOT_SET) ? impl->handler : NULL;
+ LeaveCriticalSection(&impl->cs);
return hr;
}
@@ -200,9 +212,11 @@ static HRESULT WINAPI async_void_info_get_Status( IAsyncInfo *iface, AsyncStatus
TRACE("iface %p, status %p.\n", iface, status);
+ EnterCriticalSection(&impl->cs);
if (impl->status == Closed)
hr = E_ILLEGAL_METHOD_CALL;
*status = impl->status;
+ LeaveCriticalSection(&impl->cs);
return hr;
}
@@ -214,10 +228,12 @@ static HRESULT WINAPI async_void_info_get_ErrorCode( IAsyncInfo *iface, HRESULT
TRACE("iface %p, error_code %p.\n", iface, error_code);
+ EnterCriticalSection(&impl->cs);
if (impl->status == Closed)
*error_code = hr = E_ILLEGAL_METHOD_CALL;
else
*error_code = impl->hr;
+ LeaveCriticalSection(&impl->cs);
return hr;
}
@@ -229,10 +245,12 @@ static HRESULT WINAPI async_void_info_Cancel( IAsyncInfo *iface )
TRACE("iface %p.\n", iface);
+ EnterCriticalSection(&impl->cs);
if (impl->status == Closed)
hr = E_ILLEGAL_METHOD_CALL;
else if (impl->status == Started)
impl->status = Canceled;
+ LeaveCriticalSection(&impl->cs);
return hr;
}
@@ -244,10 +262,16 @@ static HRESULT WINAPI async_void_info_Close( IAsyncInfo *iface )
TRACE("iface %p.\n", iface);
+ EnterCriticalSection(&impl->cs);
if (impl->status == Started)
hr = E_ILLEGAL_STATE_CHANGE;
else if (impl->status != Closed)
+ {
+ CloseThreadpoolWork(impl->async_run_work);
+ impl->async_run_work = NULL;
impl->status = Closed;
+ }
+ LeaveCriticalSection(&impl->cs);
return hr;
}
@@ -270,11 +294,40 @@ static const struct IAsyncInfoVtbl async_void_info_vtbl =
async_void_info_Close
};
-HRESULT async_action_create( IAsyncAction **out )
+static void CALLBACK async_void_run_cb(TP_CALLBACK_INSTANCE *instance, void *data, TP_WORK *work)
+{
+ IAsyncAction *action = data;
+ struct async_void *impl = impl_from_IAsyncAction(action);
+ HRESULT hr;
+
+ hr = impl->callback(impl->invoker);
+
+ EnterCriticalSection(&impl->cs);
+ if (impl->status < Closed)
+ impl->status = FAILED(hr) ? Error : Completed;
+
+ impl->hr = hr;
+
+ if (impl->handler != NULL && impl->handler != HANDLER_NOT_SET)
+ {
+ IAsyncActionCompletedHandler*handler = impl->handler;
+ AsyncStatus status = impl->status;
+ impl->handler = NULL; /* Prevent concurrent invoke. */
+ LeaveCriticalSection(&impl->cs);
+
+ IAsyncActionCompletedHandler_Invoke(handler, action, status);
+ IAsyncActionCompletedHandler_Release(handler);
+ }
+ else LeaveCriticalSection(&impl->cs);
+
+ IAsyncAction_Release(action);
+}
+
+HRESULT async_action_create( IInspectable *invoker, async_action_callback callback, IAsyncAction **out )
{
struct async_void *impl;
- TRACE("out %p.\n", out);
+ TRACE("invoker %p, callback %p, out %p.\n", invoker, callback, out);
if (!(impl = calloc(1, sizeof(*impl))))
{
@@ -287,7 +340,23 @@ HRESULT async_action_create( IAsyncAction **out )
impl->ref = 1;
impl->handler = HANDLER_NOT_SET;
- impl->status = Completed;
+ impl->callback = callback;
+ impl->status = Started;
+
+ if (!(impl->async_run_work = CreateThreadpoolWork(async_void_run_cb, &impl->IAsyncAction_iface, NULL)))
+ {
+ free(impl);
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ if (invoker) IInspectable_AddRef((impl->invoker = invoker));
+
+ InitializeCriticalSection(&impl->cs);
+ impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": async_action.cs");
+
+ /* AddRef to keep the obj alive in the callback. */
+ IAsyncAction_AddRef(&impl->IAsyncAction_iface);
+ SubmitThreadpoolWork(impl->async_run_work);
*out = &impl->IAsyncAction_iface;
TRACE("created %p\n", *out);
diff --git a/dlls/windows.media.speech/private.h b/dlls/windows.media.speech/private.h
index ba8e942fe5f..13964329697 100644
--- a/dlls/windows.media.speech/private.h
+++ b/dlls/windows.media.speech/private.h
@@ -69,9 +69,10 @@ struct vector_iids
const GUID *view;
};
+typedef HRESULT (WINAPI *async_action_callback)( IInspectable *invoker );
typedef HRESULT (WINAPI *async_operation_inspectable_callback)( IInspectable *invoker, IInspectable **result );
-HRESULT async_action_create( IAsyncAction **out );
+HRESULT async_action_create( IInspectable *invoker, async_action_callback callback, IAsyncAction **out );
HRESULT async_operation_inspectable_create( const GUID *iid, IInspectable *invoker, async_operation_inspectable_callback callback,
IAsyncOperation_IInspectable **out );
diff --git a/dlls/windows.media.speech/recognizer.c b/dlls/windows.media.speech/recognizer.c
index 853e9eb9830..6a058df86e5 100644
--- a/dlls/windows.media.speech/recognizer.c
+++ b/dlls/windows.media.speech/recognizer.c
@@ -244,10 +244,15 @@ static HRESULT WINAPI session_set_AutoStopSilenceTimeout( ISpeechContinuousRecog
return E_NOTIMPL;
}
+static HRESULT WINAPI start_callback( IInspectable *invoker )
+{
+ return S_OK;
+}
+
static HRESULT WINAPI session_StartAsync( ISpeechContinuousRecognitionSession *iface, IAsyncAction **action )
{
FIXME("iface %p, action %p stub!\n", iface, action);
- return async_action_create(action);
+ return async_action_create(NULL, start_callback, action);
}
static HRESULT WINAPI session_StartWithModeAsync( ISpeechContinuousRecognitionSession *iface,
More information about the wine-cvs
mailing list