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

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