diff options
Diffstat (limited to 'src/corelib/thread/qthread.h')
-rw-r--r-- | src/corelib/thread/qthread.h | 190 |
1 files changed, 55 insertions, 135 deletions
diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h index 5a1e63ee0a..641c8ef68a 100644 --- a/src/corelib/thread/qthread.h +++ b/src/corelib/thread/qthread.h @@ -1,42 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> -** 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. +// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QTHREAD_H #define QTHREAD_H @@ -44,18 +8,12 @@ #include <QtCore/qobject.h> #include <QtCore/qdeadlinetimer.h> -// For QThread::create. The configure-time test just checks for the availability -// of std::future and std::async; for the C++17 codepath we perform some extra -// checks here (for std::invoke and C++14 lambdas). -#if QT_CONFIG(cxx11_future) -# include <future> // for std::async -# include <functional> // for std::invoke; no guard needed as it's a C++98 header - -# if defined(__cpp_lib_invoke) && __cpp_lib_invoke >= 201411 \ - && defined(__cpp_init_captures) && __cpp_init_captures >= 201304 \ - && defined(__cpp_generic_lambdas) && __cpp_generic_lambdas >= 201304 -# define QTHREAD_HAS_VARIADIC_CREATE -# endif +// For QThread::create +#include <future> // for std::async +#include <functional> // for std::invoke; no guard needed as it's a C++98 header +// internal compiler error with mingw 8.1 +#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86) +#include <intrin.h> #endif QT_BEGIN_NAMESPACE @@ -64,6 +22,7 @@ QT_BEGIN_NAMESPACE class QThreadData; class QThreadPrivate; class QAbstractEventDispatcher; +class QEventLoopLocker; class Q_CORE_EXPORT QThread : public QObject { @@ -71,6 +30,7 @@ class Q_CORE_EXPORT QThread : public QObject public: static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION; static QThread *currentThread(); + static bool isMainThread(); static int idealThreadCount() noexcept; static void yieldCurrentThread(); @@ -103,44 +63,36 @@ public: void setStackSize(uint stackSize); uint stackSize() const; - void exit(int retcode = 0); - QAbstractEventDispatcher *eventDispatcher() const; void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher); bool event(QEvent *event) override; int loopLevel() const; -#ifdef Q_CLANG_QDOC - template <typename Function, typename... Args> - static QThread *create(Function &&f, Args &&... args); - template <typename Function> - static QThread *create(Function &&f); -#else -# if QT_CONFIG(cxx11_future) -# ifdef QTHREAD_HAS_VARIADIC_CREATE + bool isCurrentThread() const; + template <typename Function, typename... Args> - static QThread *create(Function &&f, Args &&... args); -# else - template <typename Function> - static QThread *create(Function &&f); -# endif // QTHREAD_HAS_VARIADIC_CREATE -# endif // QT_CONFIG(cxx11_future) -#endif // Q_CLANG_QDOC + [[nodiscard]] static QThread *create(Function &&f, Args &&... args); public Q_SLOTS: void start(Priority = InheritPriority); void terminate(); + void exit(int retcode = 0); void quit(); public: bool wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever)); - // ### Qt6 inline this function - bool wait(unsigned long time); + bool wait(unsigned long time) + { + if (time == (std::numeric_limits<unsigned long>::max)()) + return wait(QDeadlineTimer(QDeadlineTimer::Forever)); + return wait(QDeadlineTimer(time)); + } static void sleep(unsigned long); static void msleep(unsigned long); static void usleep(unsigned long); + static void sleep(std::chrono::nanoseconds nsec); Q_SIGNALS: void started(QPrivateSignal); @@ -157,20 +109,15 @@ protected: private: Q_DECLARE_PRIVATE(QThread) + friend class QEventLoopLocker; -#if QT_CONFIG(cxx11_future) - static QThread *createThreadImpl(std::future<void> &&future); -#endif + [[nodiscard]] static QThread *createThreadImpl(std::future<void> &&future); static Qt::HANDLE currentThreadIdImpl() noexcept Q_DECL_PURE_FUNCTION; friend class QCoreApplication; friend class QThreadData; }; -#if QT_CONFIG(cxx11_future) - -#if defined(QTHREAD_HAS_VARIADIC_CREATE) || defined(Q_CLANG_QDOC) -// C++17: std::thread's constructor complying call template <typename Function, typename... Args> QThread *QThread::create(Function &&f, Args &&... args) { @@ -185,57 +132,6 @@ QThread *QThread::create(Function &&f, Args &&... args) std::move(threadFunction), std::forward<Args>(args)...)); } -#elif defined(__cpp_init_captures) && __cpp_init_captures >= 201304 -// C++14: implementation for just one callable -template <typename Function> -QThread *QThread::create(Function &&f) -{ - using DecayedFunction = typename std::decay<Function>::type; - auto threadFunction = - [f = static_cast<DecayedFunction>(std::forward<Function>(f))]() mutable -> void - { - (void)f(); - }; - - return createThreadImpl(std::async(std::launch::deferred, std::move(threadFunction))); -} -#else -// C++11: same as C++14, but with a workaround for not having generalized lambda captures -namespace QtPrivate { -template <typename Function> -struct Callable -{ - explicit Callable(Function &&f) - : m_function(std::forward<Function>(f)) - { - } - - // Apply the same semantics of a lambda closure type w.r.t. the special - // member functions, if possible: delete the copy assignment operator, - // bring back all the others as per the RO5 (cf. §8.1.5.1/11 [expr.prim.lambda.closure]) - ~Callable() = default; - Callable(const Callable &) = default; - Callable(Callable &&) = default; - Callable &operator=(const Callable &) = delete; - Callable &operator=(Callable &&) = default; - - void operator()() - { - (void)m_function(); - } - - typename std::decay<Function>::type m_function; -}; -} // namespace QtPrivate - -template <typename Function> -QThread *QThread::create(Function &&f) -{ - return createThreadImpl(std::async(std::launch::deferred, QtPrivate::Callable<Function>(std::forward<Function>(f)))); -} -#endif // QTHREAD_HAS_VARIADIC_CREATE - -#endif // QT_CONFIG(cxx11_future) /* On architectures and platforms we know, interpret the thread control @@ -247,23 +143,47 @@ QThread *QThread::create(Function &&f) value for anything. In Qt we use the handle to check if threads are identical, for which the TCB is sufficient. - So we use the fastest possible way, rathern than spend time on returning + So we use the fastest possible way, rather than spend time on returning some pseudo-interoperable value. */ inline Qt::HANDLE QThread::currentThreadId() noexcept { + // define is undefed if we have to fall back to currentThreadIdImpl +#define QT_HAS_FAST_CURRENT_THREAD_ID Qt::HANDLE tid; // typedef to void* static_assert(sizeof(tid) == sizeof(void*)); // See https://akkadia.org/drepper/tls.pdf for x86 ABI -#if defined(Q_PROCESSOR_X86_32) && defined(Q_OS_LINUX) // x86 32-bit always uses GS - __asm__("movl %%gs:0, %0" : "=r" (tid) : : ); -#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_DARWIN64) +#if defined(Q_PROCESSOR_X86_32) && ((defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD)) // x86 32-bit always uses GS + __asm__("mov %%gs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : ); +#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_DARWIN) // 64bit macOS uses GS, see https://github.com/apple/darwin-xnu/blob/master/libsyscall/os/tsd.h - __asm__("movq %%gs:0, %0" : "=r" (tid) : : ); -#elif defined(Q_PROCESSOR_X86_64) && (defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)) + __asm__("mov %%gs:0, %0" : "=r" (tid) : : ); +#elif defined(Q_PROCESSOR_X86_64) && ((defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD)) // x86_64 Linux, BSD uses FS - __asm__("movq %%fs:0, %0" : "=r" (tid) : : ); + __asm__("mov %%fs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : ); +#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_WIN) + // See https://en.wikipedia.org/wiki/Win32_Thread_Information_Block + // First get the pointer to the TIB + quint8 *tib; +# if defined(Q_CC_MINGW) // internal compiler error when using the intrinsics + __asm__("movq %%gs:0x30, %0" : "=r" (tib) : :); +# else + tib = reinterpret_cast<quint8 *>(__readgsqword(0x30)); +# endif + // Then read the thread ID + tid = *reinterpret_cast<Qt::HANDLE *>(tib + 0x48); +#elif defined(Q_PROCESSOR_X86_32) && defined(Q_OS_WIN) + // First get the pointer to the TIB + quint8 *tib; +# if defined(Q_CC_MINGW) // internal compiler error when using the intrinsics + __asm__("movl %%fs:0x18, %0" : "=r" (tib) : :); +# else + tib = reinterpret_cast<quint8 *>(__readfsdword(0x18)); +# endif + // Then read the thread ID + tid = *reinterpret_cast<Qt::HANDLE *>(tib + 0x24); #else +#undef QT_HAS_FAST_CURRENT_THREAD_ID tid = currentThreadIdImpl(); #endif return tid; |