From b0e89845dfbd1aa875e29619a68305301b761178 Mon Sep 17 00:00:00 2001 From: Samuel Nevala Date: Tue, 3 Nov 2015 16:25:54 +0200 Subject: winrt: Don't wait for runOnXamlThread to finish for timers. Fixes possible deadlock that occurs when synchronous WS event handling (introduced in ee767c8) is used across threads. Task-Id: QTBUG-49051 Change-Id: Iae973c2d4f4619b9eeb6e9393330b166ec608d27 Reviewed-by: Andrew Knight --- src/corelib/kernel/qeventdispatcher_winrt.cpp | 26 ++++++++++++++------------ src/corelib/kernel/qeventdispatcher_winrt_p.h | 2 +- 2 files changed, 15 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/corelib/kernel/qeventdispatcher_winrt.cpp b/src/corelib/kernel/qeventdispatcher_winrt.cpp index 490a7c566a..58b87bd36b 100644 --- a/src/corelib/kernel/qeventdispatcher_winrt.cpp +++ b/src/corelib/kernel/qeventdispatcher_winrt.cpp @@ -97,8 +97,6 @@ public: ~QEventDispatcherWinRTPrivate(); private: - ComPtr timerFactory; - QHash timerIdToObject; QVector timerInfos; QHash timerHandleToId; @@ -167,7 +165,7 @@ QEventDispatcherWinRT::~QEventDispatcherWinRT() { } -HRESULT QEventDispatcherWinRT::runOnXamlThread(const std::function &delegate) +HRESULT QEventDispatcherWinRT::runOnXamlThread(const std::function &delegate, bool waitForRun) { static __declspec(thread) ICoreDispatcher *dispatcher = nullptr; if (!dispatcher) { @@ -194,7 +192,7 @@ HRESULT QEventDispatcherWinRT::runOnXamlThread(const std::function & ComPtr op; hr = dispatcher->RunAsync(CoreDispatcherPriority_Normal, Make(delegate).Get(), &op); - if (FAILED(hr)) + if (FAILED(hr) || !waitForRun) return hr; return QWinRTFunctions::await(op); } @@ -292,9 +290,16 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy period.Duration = qMax(qint64(1), qint64(interval) * 10000); const HANDLE handle = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, SYNCHRONIZE | EVENT_MODIFY_STATE); const HANDLE cancelHandle = CreateEventEx(NULL, NULL, CREATE_EVENT_MANUAL_RESET, SYNCHRONIZE|EVENT_MODIFY_STATE); - HRESULT hr = runOnXamlThread([&]() { + HRESULT hr = runOnXamlThread([cancelHandle, handle, period]() { + static ComPtr timerFactory; + HRESULT hr; + if (!timerFactory) { + hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), + &timerFactory); + Q_ASSERT_SUCCEEDED(hr); + } IThreadPoolTimer *timer; - HRESULT hr = d->timerFactory->CreatePeriodicTimerWithCompletion( + hr = timerFactory->CreatePeriodicTimerWithCompletion( Callback([handle, cancelHandle](IThreadPoolTimer *timer) { DWORD cancelResult = WaitForSingleObjectEx(cancelHandle, 0, TRUE); if (cancelResult == WAIT_OBJECT_0) { @@ -314,14 +319,14 @@ void QEventDispatcherWinRT::registerTimer(int timerId, int interval, Qt::TimerTy return S_OK; }).Get(), &timer); RETURN_HR_IF_FAILED("Failed to create periodic timer"); - - d->addTimer(timerId, interval, timerType, object, handle, cancelHandle); return hr; - }); + }, false); if (FAILED(hr)) { CloseHandle(handle); CloseHandle(cancelHandle); + return; } + d->addTimer(timerId, interval, timerType, object, handle, cancelHandle); } bool QEventDispatcherWinRT::unregisterTimer(int timerId) @@ -495,9 +500,6 @@ QEventDispatcherWinRTPrivate::QEventDispatcherWinRTPrivate() const bool isGuiThread = QCoreApplication::instance() && QThread::currentThread() == QCoreApplication::instance()->thread(); CoInitializeEx(NULL, isGuiThread ? COINIT_APARTMENTTHREADED : COINIT_MULTITHREADED); - HRESULT hr; - hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_System_Threading_ThreadPoolTimer).Get(), &timerFactory); - Q_ASSERT_SUCCEEDED(hr); HANDLE interruptHandle = CreateEventEx(NULL, NULL, NULL, SYNCHRONIZE|EVENT_MODIFY_STATE); timerIdToHandle.insert(INTERRUPT_HANDLE, interruptHandle); timerHandleToId.insert(interruptHandle, INTERRUPT_HANDLE); diff --git a/src/corelib/kernel/qeventdispatcher_winrt_p.h b/src/corelib/kernel/qeventdispatcher_winrt_p.h index 073aa1c121..1f9826f048 100644 --- a/src/corelib/kernel/qeventdispatcher_winrt_p.h +++ b/src/corelib/kernel/qeventdispatcher_winrt_p.h @@ -67,7 +67,7 @@ public: explicit QEventDispatcherWinRT(QObject *parent = 0); ~QEventDispatcherWinRT(); - static HRESULT runOnXamlThread(const std::function &delegate); + static HRESULT runOnXamlThread(const std::function &delegate, bool waitForRun = true); bool processEvents(QEventLoop::ProcessEventsFlags flags); bool hasPendingEvents(); -- cgit v1.2.3