1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QTHREAD_H
6#define QTHREAD_H
7
8#include <QtCore/qobject.h>
9#include <QtCore/qdeadlinetimer.h>
10
11// For QThread::create
12#if QT_CONFIG(cxx11_future)
13# include <future> // for std::async
14# include <functional> // for std::invoke; no guard needed as it's a C++98 header
15#endif
16// internal compiler error with mingw 8.1
17#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86)
18#include <intrin.h>
19#endif
20
21QT_BEGIN_NAMESPACE
22
23
24class QThreadData;
25class QThreadPrivate;
26class QAbstractEventDispatcher;
27class QEventLoopLocker;
28
29class Q_CORE_EXPORT QThread : public QObject
30{
31 Q_OBJECT
32public:
33 static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION;
34 static QThread *currentThread();
35 static int idealThreadCount() noexcept;
36 static void yieldCurrentThread();
37
38 explicit QThread(QObject *parent = nullptr);
39 ~QThread();
40
41 enum Priority {
42 IdlePriority,
43
44 LowestPriority,
45 LowPriority,
46 NormalPriority,
47 HighPriority,
48 HighestPriority,
49
50 TimeCriticalPriority,
51
52 InheritPriority
53 };
54
55 void setPriority(Priority priority);
56 Priority priority() const;
57
58 bool isFinished() const;
59 bool isRunning() const;
60
61 void requestInterruption();
62 bool isInterruptionRequested() const;
63
64 void setStackSize(uint stackSize);
65 uint stackSize() const;
66
67 QAbstractEventDispatcher *eventDispatcher() const;
68 void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher);
69
70 bool event(QEvent *event) override;
71 int loopLevel() const;
72
73#if QT_CONFIG(cxx11_future) || defined(Q_QDOC)
74 template <typename Function, typename... Args>
75 [[nodiscard]] static QThread *create(Function &&f, Args &&... args);
76#endif
77
78public Q_SLOTS:
79 void start(Priority = InheritPriority);
80 void terminate();
81 void exit(int retcode = 0);
82 void quit();
83
84public:
85 bool wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever));
86 bool wait(unsigned long time)
87 {
88 if (time == (std::numeric_limits<unsigned long>::max)())
89 return wait(deadline: QDeadlineTimer(QDeadlineTimer::Forever));
90 return wait(deadline: QDeadlineTimer(time));
91 }
92
93 static void sleep(unsigned long);
94 static void msleep(unsigned long);
95 static void usleep(unsigned long);
96 static void sleep(std::chrono::nanoseconds nsec);
97
98Q_SIGNALS:
99 void started(QPrivateSignal);
100 void finished(QPrivateSignal);
101
102protected:
103 virtual void run();
104 int exec();
105
106 static void setTerminationEnabled(bool enabled = true);
107
108protected:
109 QThread(QThreadPrivate &dd, QObject *parent = nullptr);
110
111private:
112 Q_DECLARE_PRIVATE(QThread)
113 friend class QEventLoopLocker;
114
115#if QT_CONFIG(cxx11_future)
116 [[nodiscard]] static QThread *createThreadImpl(std::future<void> &&future);
117#endif
118 static Qt::HANDLE currentThreadIdImpl() noexcept Q_DECL_PURE_FUNCTION;
119
120 friend class QCoreApplication;
121 friend class QThreadData;
122};
123
124#if QT_CONFIG(cxx11_future)
125template <typename Function, typename... Args>
126QThread *QThread::create(Function &&f, Args &&... args)
127{
128 using DecayedFunction = typename std::decay<Function>::type;
129 auto threadFunction =
130 [f = static_cast<DecayedFunction>(std::forward<Function>(f))](auto &&... largs) mutable -> void
131 {
132 (void)std::invoke(std::move(f), std::forward<decltype(largs)>(largs)...);
133 };
134
135 return createThreadImpl(future: std::async(std::launch::deferred,
136 std::move(threadFunction),
137 std::forward<Args>(args)...));
138}
139#endif // QT_CONFIG(cxx11_future)
140
141/*
142 On architectures and platforms we know, interpret the thread control
143 block (TCB) as a unique identifier for a thread within a process. Otherwise,
144 fall back to a slower but safe implementation.
145
146 As per the documentation of currentThreadId, we return an opaque handle
147 as a thread identifier, and application code is not supposed to use that
148 value for anything. In Qt we use the handle to check if threads are identical,
149 for which the TCB is sufficient.
150
151 So we use the fastest possible way, rather than spend time on returning
152 some pseudo-interoperable value.
153*/
154inline Qt::HANDLE QThread::currentThreadId() noexcept
155{
156 // define is undefed if we have to fall back to currentThreadIdImpl
157#define QT_HAS_FAST_CURRENT_THREAD_ID
158 Qt::HANDLE tid; // typedef to void*
159 static_assert(sizeof(tid) == sizeof(void*));
160 // See https://akkadia.org/drepper/tls.pdf for x86 ABI
161#if defined(Q_PROCESSOR_X86_32) && ((defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD)) // x86 32-bit always uses GS
162 __asm__("movl %%gs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : );
163#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_DARWIN)
164 // 64bit macOS uses GS, see https://github.com/apple/darwin-xnu/blob/master/libsyscall/os/tsd.h
165 __asm__("movq %%gs:0, %0" : "=r" (tid) : : );
166#elif defined(Q_PROCESSOR_X86_64) && ((defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD))
167 // x86_64 Linux, BSD uses FS
168 __asm__("movq %%fs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : );
169#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_WIN)
170 // See https://en.wikipedia.org/wiki/Win32_Thread_Information_Block
171 // First get the pointer to the TIB
172 quint8 *tib;
173# if defined(Q_CC_MINGW) // internal compiler error when using the intrinsics
174 __asm__("movq %%gs:0x30, %0" : "=r" (tib) : :);
175# else
176 tib = reinterpret_cast<quint8 *>(__readgsqword(0x30));
177# endif
178 // Then read the thread ID
179 tid = *reinterpret_cast<Qt::HANDLE *>(tib + 0x48);
180#elif defined(Q_PROCESSOR_X86_32) && defined(Q_OS_WIN)
181 // First get the pointer to the TIB
182 quint8 *tib;
183# if defined(Q_CC_MINGW) // internal compiler error when using the intrinsics
184 __asm__("movl %%fs:0x18, %0" : "=r" (tib) : :);
185# else
186 tib = reinterpret_cast<quint8 *>(__readfsdword(0x18));
187# endif
188 // Then read the thread ID
189 tid = *reinterpret_cast<Qt::HANDLE *>(tib + 0x24);
190#else
191#undef QT_HAS_FAST_CURRENT_THREAD_ID
192 tid = currentThreadIdImpl();
193#endif
194 return tid;
195}
196
197QT_END_NAMESPACE
198
199#endif // QTHREAD_H
200

source code of qtbase/src/corelib/thread/qthread.h