From 29208fa07c1b9f656ea2535696828385b7832226 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Mon, 10 Sep 2018 12:19:09 +0200 Subject: winrt: Explicitly set main thread in QCoreApplication's constructor For winrt we cannot rely on the fact, that QThread::current will be called from the correct thread for the first time. The application's main entry point creates a suspended thread and starts it right afterwards. At that moment, other functionality (QLoggingRegistry for example) might have called QThread::current, which set the wrong thread as the main thread. In order to avoid this situation, the main thread is explicitly set in QCoreApplication's constructor. Task-number: QTBUG-66418 Change-Id: I8b6347357a80eb395ae758bd3d420adef0826751 Reviewed-by: Friedemann Kleint Reviewed-by: Simon Hausmann --- src/corelib/kernel/qcoreapplication.cpp | 4 ++++ src/corelib/thread/qthread_p.h | 3 +++ src/corelib/thread/qthread_win.cpp | 35 +++++++++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 1350a7aa94..463e30e1c3 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -482,6 +482,10 @@ QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv, uint qFatal("FATAL: The application binary appears to be running setuid, this is a security hole."); # endif // Q_OS_UNIX +#ifdef Q_OS_WINRT + QThreadData::setMainThread(); +#endif + QThread *cur = QThread::currentThread(); // note: this may end up setting theMainThread! if (cur != theMainThread) qWarning("WARNING: QApplication was not created in the main() thread."); diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index 64e3f33191..7d9442ab79 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -243,6 +243,9 @@ public: ~QThreadData(); static Q_AUTOTEST_EXPORT QThreadData *current(bool createIfNecessary = true); +#ifdef Q_OS_WINRT + static void setMainThread(); +#endif static void clearCurrentThreadData(); static QThreadData *get2(QThread *thread) { Q_ASSERT_X(thread != 0, "QThread", "internal error"); return thread->d_func()->data; } diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index eebaf90d9b..e04d27d7b6 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -140,11 +140,15 @@ QThreadData *QThreadData::current(bool createIfNecessary) threadData->isAdopted = true; threadData->threadId.store(reinterpret_cast(quintptr(GetCurrentThreadId()))); +#ifndef Q_OS_WINRT if (!QCoreApplicationPrivate::theMainThread) { QCoreApplicationPrivate::theMainThread = threadData->thread.load(); - // TODO: is there a way to reflect the branch's behavior using - // WinRT API? } else { +#else + // for winrt the main thread is set explicitly in QCoreApplication's constructor as the + // native main thread (Xaml thread) is not Qt's main thread. + { +#endif HANDLE realHandle = INVALID_HANDLE_VALUE; DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), @@ -159,6 +163,33 @@ QThreadData *QThreadData::current(bool createIfNecessary) return threadData; } +#ifdef Q_OS_WINRT +void QThreadData::setMainThread() +{ + Q_ASSERT(!QCoreApplicationPrivate::theMainThread); + qt_create_tls(); + QThreadData *threadData = reinterpret_cast(TlsGetValue(qt_current_thread_data_tls_index)); + if (!threadData) { + threadData = new QThreadData; + // This needs to be called prior to new AdoptedThread() to + // avoid recursion. + TlsSetValue(qt_current_thread_data_tls_index, threadData); + QT_TRY { + threadData->thread = new QAdoptedThread(threadData); + } QT_CATCH(...) { + TlsSetValue(qt_current_thread_data_tls_index, 0); + threadData->deref(); + threadData = 0; + QT_RETHROW; + } + threadData->deref(); + threadData->isAdopted = true; + threadData->threadId.store(reinterpret_cast(quintptr(GetCurrentThreadId()))); + } + QCoreApplicationPrivate::theMainThread = threadData->thread.load(); +} +#endif + void QAdoptedThread::init() { d_func()->handle = GetCurrentThread(); -- cgit v1.2.3