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 <Friedemann.Kleint@qt.io>
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
Oliver Wolff 2018-09-10 12:19:09 +02:00
parent 05b8ba5155
commit 29208fa07c
3 changed files with 40 additions and 2 deletions

View File

@ -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.");

View File

@ -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; }

View File

@ -140,11 +140,15 @@ QThreadData *QThreadData::current(bool createIfNecessary)
threadData->isAdopted = true;
threadData->threadId.store(reinterpret_cast<Qt::HANDLE>(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<QThreadData *>(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<Qt::HANDLE>(quintptr(GetCurrentThreadId())));
}
QCoreApplicationPrivate::theMainThread = threadData->thread.load();
}
#endif
void QAdoptedThread::init()
{
d_func()->handle = GetCurrentThread();