Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qthread_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QTHREAD_P_H
6#define QTHREAD_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists purely as an
13// implementation detail. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18//
19
20#include "qplatformdefs.h"
21#include "QtCore/qthread.h"
22#include "QtCore/qmutex.h"
23#include "QtCore/qstack.h"
24#if QT_CONFIG(thread)
25#include "QtCore/qwaitcondition.h"
26#endif
27#include "QtCore/qmap.h"
28#include "QtCore/qcoreapplication.h"
29#include "private/qobject_p.h"
30
31#include <algorithm>
32#include <atomic>
33
34QT_BEGIN_NAMESPACE
35
36class QAbstractEventDispatcher;
37class QEventLoop;
38
40{
41public:
45 inline QPostEvent()
46 : receiver(nullptr), event(nullptr), priority(0)
47 { }
48 inline QPostEvent(QObject *r, QEvent *e, int p)
49 : receiver(r), event(e), priority(p)
50 { }
51};
53
54inline bool operator<(const QPostEvent &first, const QPostEvent &second)
55{
56 return first.priority > second.priority;
57}
58
59// This class holds the list of posted events.
60// The list has to be kept sorted by priority
61// ### Qt7 remove the next line
62// It's used in a virtual in QCoreApplication, so ELFVERSION:ignore-next
64{
65public:
66 // recursion == recursion count for sendPostedEvents()
68
69 // sendOffset == the current event to start sending
71 // insertionOffset == set by sendPostedEvents to tell postEvent() where to start insertions
73
75
77
78 void addEvent(const QPostEvent &ev);
79
80private:
81 //hides because they do not keep that list sorted. addEvent must be used
82 using QList<QPostEvent>::append;
83 using QList<QPostEvent>::insert;
84};
85
86namespace QtPrivate {
87
88/* BindingStatusOrList is basically a QBiPointer (as found in declarative)
89 with some helper methods to manipulate the list. BindingStatusOrList starts
90 its life in a null state and supports the following transitions
91
92 0 state (initial)
93 / \
94 / \
95 v v
96 pending object list----------->binding status
97 Note that binding status is the final state, and we never transition away
98 from it
99*/
101{
103public:
104 using List = std::vector<QObject *>;
105
106 constexpr BindingStatusOrList() noexcept : data(0) {}
107 explicit BindingStatusOrList(QBindingStatus *status) noexcept :
109 explicit BindingStatusOrList(List *list) noexcept : data(encodeList(list)) {}
110
111 // requires external synchronization:
113 void removeObject(QObject *object);
114 void setStatusAndClearList(QBindingStatus *status) noexcept;
115
116
117 static bool isBindingStatus(quintptr data) noexcept
118 {
119 return !isNull(data) && !isList(data);
120 }
121 static bool isList(quintptr data) noexcept { return data & 1; }
122 static bool isNull(quintptr data) noexcept { return data == 0; }
123
124 // thread-safe:
126 {
127 // synchronizes-with the store-release in setStatusAndClearList():
128 const auto d = data.load(std::memory_order_acquire);
129 if (isBindingStatus(d))
130 return reinterpret_cast<QBindingStatus *>(d);
131 else
132 return nullptr;
133 }
134
135 // requires external synchronization:
136 List *list() const noexcept
137 {
138 return decodeList(data.load(std::memory_order_relaxed));
139 }
140
141private:
142 static List *decodeList(quintptr ptr) noexcept
143 {
144 if (isList(ptr))
145 return reinterpret_cast<List *>(ptr & ~1);
146 else
147 return nullptr;
148 }
149
150 static quintptr encodeBindingStatus(QBindingStatus *status) noexcept
151 {
152 return quintptr(status);
153 }
154
155 static quintptr encodeList(List *list) noexcept
156 {
157 return quintptr(list) | 1;
158 }
159
160 std::atomic<quintptr> data;
161};
162
163} // namespace QtPrivate
164
165#if QT_CONFIG(thread)
166
167class Q_CORE_EXPORT QDaemonThread : public QThread
168{
169public:
170 QDaemonThread(QObject *parent = nullptr);
171 ~QDaemonThread();
172};
173
174class Q_AUTOTEST_EXPORT QThreadPrivate : public QObjectPrivate
175{
176 Q_DECLARE_PUBLIC(QThread)
177
178public:
179 QThreadPrivate(QThreadData *d = nullptr);
180 ~QThreadPrivate();
181
182 void setPriority(QThread::Priority prio);
183 Qt::HANDLE threadId() const noexcept;
184
185 mutable QMutex mutex;
186 QAtomicInt quitLockRef;
187
188 enum State : quint8 {
189 // All state changes are imprecise
190 NotStarted = 0, // before start() or if failed to start
191 Running = 1, // in run()
192 Finishing = 2, // in QThreadPrivate::finish()
193 Finished = 3, // QThreadPrivate::finish() or cleanup() is done
194 // or, if using pthread_join, joining is done
195 };
196
197 State threadState = NotStarted;
198 bool exited = false;
199 std::atomic<bool> interruptionRequested = false;
200#ifdef Q_OS_UNIX
201 bool terminated = false; // when (the first) terminate has been called
202#endif
203
204 int waiters = 0;
205 int returnCode = -1;
206
207 uint stackSize = 0;
208 std::underlying_type_t<QThread::Priority> priority = QThread::InheritPriority;
209
210 bool wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline);
211
212 QThread::QualityOfService serviceLevel = QThread::QualityOfService::Auto;
213 void setQualityOfServiceLevel(QThread::QualityOfService qosLevel);
214#ifdef Q_OS_DARWIN
215 qos_class_t nativeQualityOfServiceClass() const;
216#endif
217
218#ifdef Q_OS_UNIX
219 QWaitCondition thread_done;
220
221 void wakeAll();
222 static void *start(void *arg);
223 void finish(); // happens early (before thread-local dtors)
224 void cleanup(); // happens late (as a thread-local dtor, if possible)
225#endif // Q_OS_UNIX
226
227#ifdef Q_OS_WIN
228 static unsigned int __stdcall start(void *) noexcept;
229 void finish(bool lockAnyway = true) noexcept;
230
231 Qt::HANDLE handle;
232 bool terminationEnabled, terminatePending;
233#endif // Q_OS_WIN
234#ifdef Q_OS_WASM
235 static int idealThreadCount;
236#endif
237 QThreadData *data;
238
239 static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data);
240
241 void ref()
242 {
243 quitLockRef.ref();
244 }
245
246 void deref()
247 {
248 if (!quitLockRef.deref() && threadState == Running) {
249 QCoreApplication::instance()->postEvent(q_ptr, new QEvent(QEvent::Quit));
250 }
251 }
252
253 QBindingStatus *bindingStatus()
254 {
255 return m_statusOrPendingObjects.bindingStatus();
256 }
257
258 /* Returns nullptr if the object has been added, or the binding status
259 if that one has been set in the meantime
260 */
261 QBindingStatus *addObjectWithPendingBindingStatusChange(QObject *obj);
262 void removeObjectWithPendingBindingStatusChange(QObject *obj);
263
264 // manipulating m_statusOrPendingObjects requires mutex to be locked
265 QtPrivate::BindingStatusOrList m_statusOrPendingObjects = {};
266#ifndef Q_OS_INTEGRITY
267private:
268 // Used in QThread(Private)::start to avoid racy access to QObject::objectName,
269 // unset afterwards. On INTEGRITY we set the thread name before starting it.
270 QString objectName;
271#endif
272};
273
274#else // QT_CONFIG(thread)
275
277{
278public:
279 QThreadPrivate(QThreadData *d = nullptr);
281
282 mutable QMutex mutex;
285 bool running = false;
286
287 QBindingStatus* bindingStatus() { return m_bindingStatus; }
290
291 static void setCurrentThread(QThread *) { }
292 static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data);
293
294 void ref() {}
295 void deref() {}
296
297 Q_DECLARE_PUBLIC(QThread)
298};
299
300#endif // QT_CONFIG(thread)
301
303{
304public:
305 QThreadData(int initialRefCount = 1)
307 {
308 // fprintf(stderr, "QThreadData %p created\n", this);
309 }
310 ~QThreadData();
311
313 {
314 if (QThreadData *data = currentThreadData()) Q_LIKELY_BRANCH
315 return data;
316 return createCurrentThreadData();
317 }
318 static void clearCurrentThreadData();
319 static QThreadData *get2(QThread *thread)
320 { Q_ASSERT_X(thread != nullptr, "QThread", "internal error"); return thread->d_func()->data; }
321
322#if QT_CONFIG(thread)
323 void ref()
324 {
325 (void) _ref.ref();
326 Q_ASSERT(_ref.loadRelaxed() != 0);
327 }
328 void deref()
329 {
330 if (!_ref.deref())
331 delete this;
332 }
333#else
334 void ref() {}
335 void deref() {}
336#endif
337 inline bool hasEventDispatcher() const
338 { return eventDispatcher.loadRelaxed() != nullptr; }
339 QAbstractEventDispatcher *createEventDispatcher();
340 QAbstractEventDispatcher *ensureEventDispatcher()
341 {
342 QAbstractEventDispatcher *ed = eventDispatcher.loadRelaxed();
343 if (Q_LIKELY(ed))
344 return ed;
346 }
347
349 {
350 QMutexLocker locker(&postEventList.mutex);
351 return canWait;
352 }
353
359 QList<void *> tls;
360
361private:
362 QAtomicInt _ref;
363
364public:
365 int loopLevel = 0;
366 int scopeLevel = 0;
367
368 bool quitNow = false;
369 bool canWait = true;
370 bool isAdopted = false;
372
373private:
374 static Q_AUTOTEST_EXPORT QThreadData *currentThreadData() noexcept Q_DECL_PURE_FUNCTION;
375 static Q_AUTOTEST_EXPORT QThreadData *createCurrentThreadData();
376};
377
379{
380 QThreadData *threadData;
381public:
383 : threadData(threadData)
384 { ++threadData->scopeLevel; }
386 { --threadData->scopeLevel; }
387};
388
389// thread wrapper for the main() thread
391{
392 Q_DECLARE_PRIVATE(QThread)
393
394public:
397 void init();
398
399private:
400#if QT_CONFIG(thread)
401 void run() override;
402#endif
403};
404
405QT_END_NAMESPACE
406
407#endif // QTHREAD_P_H
void addEvent(const QPostEvent &ev)
Definition qthread.cpp:22
qsizetype startOffset
Definition qthread_p.h:70
qsizetype insertionOffset
Definition qthread_p.h:72
QObject * receiver
Definition qthread_p.h:42
QPostEvent(QObject *r, QEvent *e, int p)
Definition qthread_p.h:48
QEvent * event
Definition qthread_p.h:43
int priority
Definition qthread_p.h:44
QScopedScopeLevelCounter(QThreadData *threadData)
Definition qthread_p.h:382
QStack< QEventLoop * > eventLoops
Definition qthread_p.h:354
QAtomicPointer< QAbstractEventDispatcher > eventDispatcher
Definition qthread_p.h:358
static QThreadData * current()
Definition qthread_p.h:312
QThreadData(int initialRefCount=1)
Definition qthread_p.h:305
bool requiresCoreApplication
Definition qthread_p.h:371
void deref()
Definition qthread_p.h:335
static void clearCurrentThreadData()
Definition qthread.cpp:1141
bool isAdopted
Definition qthread_p.h:370
QAtomicPointer< void > threadId
Definition qthread_p.h:357
static QThreadData * get2(QThread *thread)
Definition qthread_p.h:319
QAbstractEventDispatcher * ensureEventDispatcher()
Definition qthread_p.h:340
QPostEventList postEventList
Definition qthread_p.h:355
bool canWaitLocked()
Definition qthread_p.h:348
bool hasEventDispatcher() const
Definition qthread_p.h:337
void ref()
Definition qthread_p.h:334
QAtomicPointer< QThread > thread
Definition qthread_p.h:356
QList< void * > tls
Definition qthread_p.h:359
QAbstractEventDispatcher * createEventDispatcher()
Definition qthread.cpp:80
static void setCurrentThread(QThread *)
Definition qthread_p.h:291
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
QThreadPrivate(QThreadData *d=nullptr)
Definition qthread.cpp:1158
void removeObjectWithPendingBindingStatusChange(QObject *)
Definition qthread_p.h:289
QThreadData * data
Definition qthread_p.h:283
QBindingStatus * m_bindingStatus
Definition qthread_p.h:284
QBindingStatus * bindingStatus()
Definition qthread_p.h:287
QBindingStatus * addObjectWithPendingBindingStatusChange(QObject *)
Definition qthread_p.h:288
List * list() const noexcept
Definition qthread_p.h:136
static bool isBindingStatus(quintptr data) noexcept
Definition qthread_p.h:117
static bool isNull(quintptr data) noexcept
Definition qthread_p.h:122
void removeObject(QObject *object)
void setStatusAndClearList(QBindingStatus *status) noexcept
constexpr BindingStatusOrList() noexcept
Definition qthread_p.h:106
QBindingStatus * addObjectUnlessAlreadyStatus(QObject *object)
BindingStatusOrList(QBindingStatus *status) noexcept
Definition qthread_p.h:107
QBindingStatus * bindingStatus() const noexcept
Definition qthread_p.h:125
static bool isList(quintptr data) noexcept
Definition qthread_p.h:121
Combined button and popup list for selecting options.
Q_DECLARE_TYPEINFO(QPostEvent, Q_RELOCATABLE_TYPE)
bool operator<(const QPostEvent &first, const QPostEvent &second)
Definition qthread_p.h:54