QWinRtFunctions::await() - introduce early exit condition

The await() method waits for the result of async operation in a
non-blocking way (triggering processEvent periodically).
It means that during this wait some other things might happen, and
there would be no reason to wait for the end of the operation execution.

This patch implements an additional parameter - a function that specifies
a condition for an early return. When this function returns true, the
await() method returns with E_ABORT, which makes it possible to
distinguish it from timer expiration.

Task-number: QTBUG-96057
Pick-to: 6.2 5.15
Change-Id: Ide73d768b7cbb3a35be7160ce7555aeb2dca5235
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
Reviewed-by: Juha Vuolle <juha.vuolle@insta.fi>
bb10
Ivan Solovev 2021-09-22 17:54:40 +02:00
parent 0acada9c7b
commit 1f86957f1d
1 changed files with 19 additions and 8 deletions

View File

@ -101,8 +101,11 @@ enum AwaitStyle
ProcessMainThreadEvents = 2
};
template <typename T>
static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle awaitStyle, uint timeout)
using EarlyExitConditionFunction = std::function<bool(void)>;
template<typename T>
static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle awaitStyle,
uint timeout, EarlyExitConditionFunction func)
{
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
HRESULT hr = asyncOp.As(&asyncInfo);
@ -117,6 +120,8 @@ static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, Awai
case ProcessMainThreadEvents:
while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == AsyncStatus::Started) {
QCoreApplication::processEvents();
if (func && func())
return E_ABORT;
if (timeout && t.hasExpired(timeout))
return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
}
@ -125,6 +130,8 @@ static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, Awai
if (QAbstractEventDispatcher *dispatcher = QThread::currentThread()->eventDispatcher()) {
while (SUCCEEDED(hr = asyncInfo->get_Status(&status)) && status == AsyncStatus::Started) {
dispatcher->processEvents(QEventLoop::AllEvents);
if (func && func())
return E_ABORT;
if (timeout && t.hasExpired(timeout))
return HRESULT_FROM_WIN32(ERROR_TIMEOUT);
}
@ -155,20 +162,24 @@ static inline HRESULT _await_impl(const Microsoft::WRL::ComPtr<T> &asyncOp, Awai
return hr;
}
template <typename T>
static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, AwaitStyle awaitStyle = YieldThread, uint timeout = 0)
template<typename T>
static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp,
AwaitStyle awaitStyle = YieldThread, uint timeout = 0,
EarlyExitConditionFunction func = nullptr)
{
HRESULT hr = _await_impl(asyncOp, awaitStyle, timeout);
HRESULT hr = _await_impl(asyncOp, awaitStyle, timeout, func);
if (FAILED(hr))
return hr;
return asyncOp->GetResults();
}
template <typename T, typename U>
static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, U *results, AwaitStyle awaitStyle = YieldThread, uint timeout = 0)
template<typename T, typename U>
static inline HRESULT await(const Microsoft::WRL::ComPtr<T> &asyncOp, U *results,
AwaitStyle awaitStyle = YieldThread, uint timeout = 0,
EarlyExitConditionFunction func = nullptr)
{
HRESULT hr = _await_impl(asyncOp, awaitStyle, timeout);
HRESULT hr = _await_impl(asyncOp, awaitStyle, timeout, func);
if (FAILED(hr))
return hr;