diff options
Diffstat (limited to 'src/corelib/thread/qthread_win.cpp')
-rw-r--r-- | src/corelib/thread/qthread_win.cpp | 148 |
1 files changed, 57 insertions, 91 deletions
diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 820ffa1149..74bc1d2650 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qthread.h" #include "qthread_p.h" @@ -55,6 +19,17 @@ #endif // _MT #include <process.h> +extern "C" { +// MinGW is missing the declaration of SetThreadDescription: +WINBASEAPI +HRESULT +WINAPI +SetThreadDescription( + _In_ HANDLE hThread, + _In_ PCWSTR lpThreadDescription + ); +} + QT_BEGIN_NAMESPACE #if QT_CONFIG(thread) @@ -67,7 +42,7 @@ void qt_create_tls() { if (qt_current_thread_data_tls_index != TLS_OUT_OF_INDEXES) return; - static QBasicMutex mutex; + Q_CONSTINIT static QBasicMutex mutex; QMutexLocker locker(&mutex); if (qt_current_thread_data_tls_index != TLS_OUT_OF_INDEXES) return; @@ -112,8 +87,9 @@ QThreadData *QThreadData::current(bool createIfNecessary) threadData->isAdopted = true; threadData->threadId.storeRelaxed(reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId()))); - if (!QCoreApplicationPrivate::theMainThread) { - QCoreApplicationPrivate::theMainThread = threadData->thread.loadRelaxed(); + if (!QCoreApplicationPrivate::theMainThreadId) { + QCoreApplicationPrivate::theMainThread.storeRelease(threadData->thread.loadRelaxed()); + QCoreApplicationPrivate::theMainThreadId.storeRelaxed(threadData->threadId.loadRelaxed()); } else { HANDLE realHandle = INVALID_HANDLE_VALUE; DuplicateHandle(GetCurrentProcess(), @@ -137,7 +113,7 @@ void QAdoptedThread::init() static QList<HANDLE> qt_adopted_thread_handles; static QList<QThread *> qt_adopted_qthreads; -static QBasicMutex qt_adopted_thread_watcher_mutex; +Q_CONSTINIT static QBasicMutex qt_adopted_thread_watcher_mutex; static DWORD qt_adopted_thread_watcher_id = 0; static HANDLE qt_adopted_thread_wakeup = 0; @@ -248,39 +224,6 @@ DWORD WINAPI qt_adopted_thread_watcher_function(LPVOID) return 0; } -#if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) - -#ifndef Q_OS_WIN64 -# define ULONG_PTR DWORD -#endif - -typedef struct tagTHREADNAME_INFO -{ - DWORD dwType; // must be 0x1000 - LPCSTR szName; // pointer to name (in user addr space) - HANDLE dwThreadID; // thread ID (-1=caller thread) - DWORD dwFlags; // reserved for future use, must be zero -} THREADNAME_INFO; - -void qt_set_thread_name(HANDLE threadId, LPCSTR threadName) -{ - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = threadName; - info.dwThreadID = threadId; - info.dwFlags = 0; - - __try - { - RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD), - reinterpret_cast<const ULONG_PTR*>(&info)); - } - __except (EXCEPTION_CONTINUE_EXECUTION) - { - } -} -#endif // !QT_NO_DEBUG && Q_CC_MSVC - /************************************************************************** ** QThreadPrivate *************************************************************************/ @@ -314,13 +257,11 @@ unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(voi data->ensureEventDispatcher(); data->eventDispatcher.loadRelaxed()->startingUp(); -#if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC) // sets the name of the current thread. - QByteArray objectName = thr->objectName().toLocal8Bit(); - qt_set_thread_name(HANDLE(-1), - objectName.isEmpty() ? - thr->metaObject()->className() : objectName.constData()); -#endif + QString threadName = std::exchange(thr->d_func()->objectName, {}); + if (Q_LIKELY(threadName.isEmpty())) + threadName = QString::fromUtf8(thr->metaObject()->className()); + SetThreadDescription(GetCurrentThread(), reinterpret_cast<const wchar_t *>(threadName.utf16())); emit thr->started(QThread::QPrivateSignal()); QThread::setTerminationEnabled(true); @@ -330,34 +271,50 @@ unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(voi return 0; } +/* + For regularly terminating threads, this will be called and executed by the thread as the + last code before the thread exits. In that case, \a arg is the current QThread. + + However, this function will also be called by QThread::terminate (as well as wait() and + setTerminationEnabled) to give Qt a chance to update the terminated thread's state and + process pending DeleteLater events for objects that live in the terminated thread. And for + adopted thread, this method is called by the thread watcher. + + In those cases, \a arg will not be the current thread. +*/ void QThreadPrivate::finish(void *arg, bool lockAnyway) noexcept { QThread *thr = reinterpret_cast<QThread *>(arg); QThreadPrivate *d = thr->d_func(); - QMutexLocker locker(lockAnyway ? &d->mutex : 0); + QMutexLocker locker(lockAnyway ? &d->mutex : nullptr); d->isInFinish = true; d->priority = QThread::InheritPriority; void **tls_data = reinterpret_cast<void **>(&d->data->tls); - locker.unlock(); + if (lockAnyway) + locker.unlock(); emit thr->finished(QThread::QPrivateSignal()); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + qCDebug(lcDeleteLater) << "Sending deferred delete events as part of finishing thread" << thr; + QCoreApplicationPrivate::sendPostedEvents(nullptr, QEvent::DeferredDelete, d->data); QThreadStorageData::finish(tls_data); - locker.relock(); + if (lockAnyway) + locker.relock(); QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed(); if (eventDispatcher) { d->data->eventDispatcher = 0; - locker.unlock(); + if (lockAnyway) + locker.unlock(); eventDispatcher->closingDown(); delete eventDispatcher; - locker.relock(); + if (lockAnyway) + locker.relock(); } d->running = false; d->finished = true; d->isInFinish = false; - d->interruptionRequested = false; + d->interruptionRequested.store(false, std::memory_order_relaxed); if (!d->waiters) { CloseHandle(d->handle); @@ -390,6 +347,12 @@ void QThread::yieldCurrentThread() #endif // QT_CONFIG(thread) +void QThread::sleep(std::chrono::nanoseconds nsecs) +{ + using namespace std::chrono; + ::Sleep(DWORD(duration_cast<milliseconds>(nsecs).count())); +} + void QThread::sleep(unsigned long secs) { ::Sleep(secs * 1000); @@ -421,11 +384,14 @@ void QThread::start(Priority priority) if (d->running) return; + // avoid interacting with the binding system + d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings() + : QString(); d->running = true; d->finished = false; d->exited = false; d->returnCode = 0; - d->interruptionRequested = false; + d->interruptionRequested.store(false, std::memory_order_relaxed); /* NOTE: we create the thread in the suspended state, set the @@ -457,7 +423,7 @@ void QThread::start(Priority priority) int prio; d->priority = priority; - switch (d->priority) { + switch (priority) { case IdlePriority: prio = THREAD_PRIORITY_IDLE; break; @@ -584,7 +550,7 @@ void QThreadPrivate::setPriority(QThread::Priority threadPriority) int prio; priority = threadPriority; - switch (priority) { + switch (threadPriority) { case QThread::IdlePriority: prio = THREAD_PRIORITY_IDLE; break; |