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

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