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