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
53QT_BEGIN_NAMESPACE
54
55
56class QThreadData;
57class QThreadPrivate;
58class QAbstractEventDispatcher;
59
60class Q_CORE_EXPORT QThread : public QObject
61{
62 Q_OBJECT
63public:
64 static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION;
65 static QThread *currentThread();
66 static int idealThreadCount() noexcept;
67 static void yieldCurrentThread();
68
69 explicit QThread(QObject *parent = nullptr);
70 ~QThread();
71
72 enum Priority {
73 IdlePriority,
74
75 LowestPriority,
76 LowPriority,
77 NormalPriority,
78 HighPriority,
79 HighestPriority,
80
81 TimeCriticalPriority,
82
83 InheritPriority
84 };
85
86 void setPriority(Priority priority);
87 Priority priority() const;
88
89 bool isFinished() const;
90 bool isRunning() const;
91
92 void requestInterruption();
93 bool isInterruptionRequested() const;
94
95 void setStackSize(uint stackSize);
96 uint stackSize() const;
97
98 void exit(int retcode = 0);
99
100 QAbstractEventDispatcher *eventDispatcher() const;
101 void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher);
102
103 bool event(QEvent *event) override;
104 int loopLevel() const;
105
106#if QT_CONFIG(cxx11_future) || defined(Q_CLANG_QDOC)
107 template <typename Function, typename... Args>
108 [[nodiscard]] static QThread *create(Function &&f, Args &&... args);
109#endif
110
111public Q_SLOTS:
112 void start(Priority = InheritPriority);
113 void terminate();
114 void quit();
115
116public:
117 bool wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer::Forever));
118 bool wait(unsigned long time)
119 {
120 if (time == std::numeric_limits<unsigned long>::max())
121 return wait(QDeadlineTimer(QDeadlineTimer::Forever));
122 return wait(QDeadlineTimer(time));
123 }
124
125 static void sleep(unsigned long);
126 static void msleep(unsigned long);
127 static void usleep(unsigned long);
128
129Q_SIGNALS:
130 void started(QPrivateSignal);
131 void finished(QPrivateSignal);
132
133protected:
134 virtual void run();
135 int exec();
136
137 static void setTerminationEnabled(bool enabled = true);
138
139protected:
140 QThread(QThreadPrivate &dd, QObject *parent = nullptr);
141
142private:
143 Q_DECLARE_PRIVATE(QThread)
144
145#if QT_CONFIG(cxx11_future)
146 [[nodiscard]] static QThread *createThreadImpl(std::future<void> &&future);
147#endif
148 static Qt::HANDLE currentThreadIdImpl() noexcept Q_DECL_PURE_FUNCTION;
149
150 friend class QCoreApplication;
151 friend class QThreadData;
152};
153
154#if QT_CONFIG(cxx11_future)
155template <typename Function, typename... Args>
156QThread *QThread::create(Function &&f, Args &&... args)
157{
158 using DecayedFunction = typename std::decay<Function>::type;
159 auto threadFunction =
160 [f = static_cast<DecayedFunction>(std::forward<Function>(f))](auto &&... largs) mutable -> void
161 {
162 (void)std::invoke(std::move(f), std::forward<decltype(largs)>(largs)...);
163 };
164
165 return createThreadImpl(std::async(std::launch::deferred,
166 std::move(threadFunction),
167 std::forward<Args>(args)...));
168}
169#endif // QT_CONFIG(cxx11_future)
170
171/*
172 On architectures and platforms we know, interpret the thread control
173 block (TCB) as a unique identifier for a thread within a process. Otherwise,
174 fall back to a slower but safe implementation.
175
176 As per the documentation of currentThreadId, we return an opaque handle
177 as a thread identifier, and application code is not supposed to use that
178 value for anything. In Qt we use the handle to check if threads are identical,
179 for which the TCB is sufficient.
180
181 So we use the fastest possible way, rathern than spend time on returning
182 some pseudo-interoperable value.
183*/
184inline Qt::HANDLE QThread::currentThreadId() noexcept
185{
186 Qt::HANDLE tid; // typedef to void*
187 static_assert(sizeof(tid) == sizeof(void*));
188 // See https://akkadia.org/drepper/tls.pdf for x86 ABI
189#if defined(Q_PROCESSOR_X86_32) && defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) // x86 32-bit always uses GS
190 __asm__("movl %%gs:0, %0" : "=r" (tid) : : );
191#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_DARWIN64)
192 // 64bit macOS uses GS, see https://github.com/apple/darwin-xnu/blob/master/libsyscall/os/tsd.h
193 __asm__("movq %%gs:0, %0" : "=r" (tid) : : );
194#elif defined(Q_PROCESSOR_X86_64) && (defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)) && !defined(Q_OS_ANDROID)
195 // x86_64 Linux, BSD uses FS
196 __asm__("movq %%fs:0, %0" : "=r" (tid) : : );
197#else
198 tid = currentThreadIdImpl();
199#endif
200 return tid;
201}
202
203QT_END_NAMESPACE
204
205#endif // QTHREAD_H
206