1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
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_P_H
42#define QTHREAD_P_H
43
44//
45// W A R N I N G
46// -------------
47//
48// This file is not part of the Qt API. It exists purely as an
49// implementation detail. This header file may change from version to
50// version without notice, or even be removed.
51//
52// We mean it.
53//
54//
55
56#include "qplatformdefs.h"
57#include "QtCore/qthread.h"
58#include "QtCore/qmutex.h"
59#include "QtCore/qstack.h"
60#if QT_CONFIG(thread)
61#include "QtCore/qwaitcondition.h"
62#endif
63#include "QtCore/qmap.h"
64#include "QtCore/qcoreapplication.h"
65#include "private/qobject_p.h"
66
67#include <algorithm>
68#include <atomic>
69
70#ifdef Q_OS_WINRT
71namespace ABI {
72 namespace Windows {
73 namespace Foundation {
74 struct IAsyncAction;
75 }
76 }
77}
78#endif // Q_OS_WINRT
79
80QT_BEGIN_NAMESPACE
81
82class QAbstractEventDispatcher;
83class QEventLoop;
84
85class QPostEvent
86{
87public:
88 QObject *receiver;
89 QEvent *event;
90 int priority;
91 inline QPostEvent()
92 : receiver(nullptr), event(nullptr), priority(0)
93 { }
94 inline QPostEvent(QObject *r, QEvent *e, int p)
95 : receiver(r), event(e), priority(p)
96 { }
97};
98Q_DECLARE_TYPEINFO(QPostEvent, Q_MOVABLE_TYPE);
99
100inline bool operator<(const QPostEvent &first, const QPostEvent &second)
101{
102 return first.priority > second.priority;
103}
104
105// This class holds the list of posted events.
106// The list has to be kept sorted by priority
107class QPostEventList : public QVector<QPostEvent>
108{
109public:
110 // recursion == recursion count for sendPostedEvents()
111 int recursion;
112
113 // sendOffset == the current event to start sending
114 int startOffset;
115 // insertionOffset == set by sendPostedEvents to tell postEvent() where to start insertions
116 int insertionOffset;
117
118 QMutex mutex;
119
120 inline QPostEventList()
121 : QVector<QPostEvent>(), recursion(0), startOffset(0), insertionOffset(0)
122 { }
123
124 void addEvent(const QPostEvent &ev) {
125 int priority = ev.priority;
126 if (isEmpty() ||
127 constLast().priority >= priority ||
128 insertionOffset >= size()) {
129 // optimization: we can simply append if the last event in
130 // the queue has higher or equal priority
131 append(t: ev);
132 } else {
133 // insert event in descending priority order, using upper
134 // bound for a given priority (to ensure proper ordering
135 // of events with the same priority)
136 QPostEventList::iterator at = std::upper_bound(first: begin() + insertionOffset, last: end(), val: ev);
137 insert(before: at, x: ev);
138 }
139 }
140private:
141 //hides because they do not keep that list sorted. addEvent must be used
142 using QVector<QPostEvent>::append;
143 using QVector<QPostEvent>::insert;
144};
145
146#if QT_CONFIG(thread)
147
148class Q_CORE_EXPORT QDaemonThread : public QThread
149{
150public:
151 QDaemonThread(QObject *parent = nullptr);
152 ~QDaemonThread();
153};
154
155class QThreadPrivate : public QObjectPrivate
156{
157 Q_DECLARE_PUBLIC(QThread)
158
159public:
160 QThreadPrivate(QThreadData *d = nullptr);
161 ~QThreadPrivate();
162
163 void setPriority(QThread::Priority prio);
164
165 mutable QMutex mutex;
166 QAtomicInt quitLockRef;
167
168 bool running;
169 bool finished;
170 bool isInFinish; //when in QThreadPrivate::finish
171 std::atomic<bool> interruptionRequested;
172
173 bool exited;
174 int returnCode;
175
176 uint stackSize;
177 std::underlying_type<QThread::Priority>::type priority;
178
179 static QThread *threadForId(int id);
180
181#ifdef Q_OS_UNIX
182 QWaitCondition thread_done;
183
184 static void *start(void *arg);
185 static void finish(void *);
186
187#endif // Q_OS_UNIX
188
189#ifdef Q_OS_WIN
190 static unsigned int __stdcall start(void *) noexcept;
191 static void finish(void *, bool lockAnyway=true) noexcept;
192
193 Qt::HANDLE handle;
194 unsigned int id;
195 int waiters;
196 bool terminationEnabled, terminatePending;
197#endif // Q_OS_WIN
198#ifdef Q_OS_WASM
199 static int idealThreadCount;
200#endif
201 QThreadData *data;
202
203 static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data);
204
205 void ref()
206 {
207 quitLockRef.ref();
208 }
209
210 void deref()
211 {
212 if (!quitLockRef.deref() && running) {
213 QCoreApplication::instance()->postEvent(receiver: q_ptr, event: new QEvent(QEvent::Quit));
214 }
215 }
216
217#ifndef Q_OS_INTEGRITY
218private:
219 // Used in QThread(Private)::start to avoid racy access to QObject::objectName,
220 // unset afterwards. On INTEGRITY we set the thread name before starting it.
221 QString objectName;
222#endif
223};
224
225#else // QT_CONFIG(thread)
226
227class QThreadPrivate : public QObjectPrivate
228{
229public:
230 QThreadPrivate(QThreadData *d = 0);
231 ~QThreadPrivate();
232
233 mutable QMutex mutex;
234 QThreadData *data;
235 bool running = false;
236
237 static void setCurrentThread(QThread*) {}
238 static QThread *threadForId(int) { return QThread::currentThread(); }
239 static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data);
240
241 void ref() {}
242 void deref() {}
243
244 Q_DECLARE_PUBLIC(QThread)
245};
246
247#endif // QT_CONFIG(thread)
248
249class QThreadData
250{
251public:
252 QThreadData(int initialRefCount = 1);
253 ~QThreadData();
254
255 static Q_AUTOTEST_EXPORT QThreadData *current(bool createIfNecessary = true);
256#ifdef Q_OS_WINRT
257 static void setMainThread();
258#endif
259 static void clearCurrentThreadData();
260 static QThreadData *get2(QThread *thread)
261 { Q_ASSERT_X(thread != nullptr, "QThread", "internal error"); return thread->d_func()->data; }
262
263
264 void ref();
265 void deref();
266 inline bool hasEventDispatcher() const
267 { return eventDispatcher.loadRelaxed() != nullptr; }
268 QAbstractEventDispatcher *createEventDispatcher();
269 QAbstractEventDispatcher *ensureEventDispatcher()
270 {
271 QAbstractEventDispatcher *ed = eventDispatcher.loadRelaxed();
272 if (Q_LIKELY(ed))
273 return ed;
274 return createEventDispatcher();
275 }
276
277 bool canWaitLocked()
278 {
279 QMutexLocker locker(&postEventList.mutex);
280 return canWait;
281 }
282
283 // This class provides per-thread (by way of being a QThreadData
284 // member) storage for qFlagLocation()
285 class FlaggedDebugSignatures
286 {
287 static const uint Count = 2;
288
289 uint idx;
290 const char* locations[Count];
291
292 public:
293 FlaggedDebugSignatures() : idx(0)
294 { std::fill_n(locations, Count, static_cast<char*>(nullptr)); }
295
296 void store(const char* method)
297 { locations[idx++ % Count] = method; }
298
299 bool contains(const char *method) const
300 { return std::find(first: locations, last: locations + Count, val: method) != locations + Count; }
301 };
302
303private:
304 QAtomicInt _ref;
305
306public:
307 int loopLevel;
308 int scopeLevel;
309
310 QStack<QEventLoop *> eventLoops;
311 QPostEventList postEventList;
312 QAtomicPointer<QThread> thread;
313 QAtomicPointer<void> threadId;
314 QAtomicPointer<QAbstractEventDispatcher> eventDispatcher;
315 QVector<void *> tls;
316 FlaggedDebugSignatures flaggedSignatures;
317
318 bool quitNow;
319 bool canWait;
320 bool isAdopted;
321 bool requiresCoreApplication;
322};
323
324class QScopedScopeLevelCounter
325{
326 QThreadData *threadData;
327public:
328 inline QScopedScopeLevelCounter(QThreadData *threadData)
329 : threadData(threadData)
330 { ++threadData->scopeLevel; }
331 inline ~QScopedScopeLevelCounter()
332 { --threadData->scopeLevel; }
333};
334
335// thread wrapper for the main() thread
336class QAdoptedThread : public QThread
337{
338 Q_DECLARE_PRIVATE(QThread)
339
340public:
341 QAdoptedThread(QThreadData *data = nullptr);
342 ~QAdoptedThread();
343 void init();
344
345private:
346#if QT_CONFIG(thread)
347 void run() override;
348#endif
349};
350
351QT_END_NAMESPACE
352
353#endif // QTHREAD_P_H
354

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