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