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
268private:
269#ifdef Q_OS_INTEGRITY
270 // On INTEGRITY we set the thread name before starting it, so just fake a string
271 struct FakeString {
272 bool isEmpty() const { return true; }
273 const char *toLocal8Bit() const { return nullptr; }
274 } objectName;
275#else
276 // Used in QThread(Private)::start to avoid racy access to QObject::objectName,
277 // unset afterwards.
278 QString objectName;
279#endif
280};
281
282#else // QT_CONFIG(thread)
283
285{
286public:
287 QThreadPrivate(QThreadData *d = nullptr);
289
290 mutable QMutex mutex;
293 bool running = false;
294
295 QBindingStatus* bindingStatus() { return m_bindingStatus; }
298
299 static void setCurrentThread(QThread *) { }
300 static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data);
301
302 void ref() {}
303 void deref() {}
304
305 Q_DECLARE_PUBLIC(QThread)
306};
307
308#endif // QT_CONFIG(thread)
309
311{
312public:
313 QThreadData(int initialRefCount = 1)
315 {
316 // fprintf(stderr, "QThreadData %p created\n", this);
317 }
318 ~QThreadData();
319
321 {
322 if (QThreadData *data = currentThreadData()) Q_LIKELY_BRANCH
323 return data;
324 return createCurrentThreadData();
325 }
326 static void clearCurrentThreadData();
327 static QThreadData *get2(QThread *thread)
328 { Q_ASSERT_X(thread != nullptr, "QThread", "internal error"); return thread->d_func()->data; }
329
330#if QT_CONFIG(thread)
331 void ref()
332 {
333 (void) _ref.ref();
334 Q_ASSERT(_ref.loadRelaxed() != 0);
335 }
336 void deref()
337 {
338 if (!_ref.deref())
339 delete this;
340 }
341#else
342 void ref() {}
343 void deref() {}
344#endif
345 inline bool hasEventDispatcher() const
346 { return eventDispatcher.loadRelaxed() != nullptr; }
347 QAbstractEventDispatcher *createEventDispatcher();
348 QAbstractEventDispatcher *ensureEventDispatcher()
349 {
350 QAbstractEventDispatcher *ed = eventDispatcher.loadRelaxed();
351 if (Q_LIKELY(ed))
352 return ed;
354 }
355
357 {
358 QMutexLocker locker(&postEventList.mutex);
359 return canWait;
360 }
361
362 void clearEvents();
363
365 {
366 auto status = m_statusOrPendingObjects.bindingStatus();
367 if (status)
368 QtPrivate::setBindingStatus(status, {});
369 }
370
376 QList<void *> tls;
377 // manipulating m_statusOrPendingObjects requires QTreadPrivate's mutex to be locked
379
380private:
381 QAtomicInt _ref;
382
383public:
384 int loopLevel = 0;
385 int scopeLevel = 0;
386
387 bool quitNow = false;
388 bool canWait = true;
389 bool isAdopted = false;
391
392private:
393 friend class QAbstractEventDispatcher;
394 friend class QBasicTimer;
395 Q_DECL_PURE_FUNCTION static Q_AUTOTEST_EXPORT QThreadData *currentThreadData() noexcept;
396 static Q_AUTOTEST_EXPORT QThreadData *createCurrentThreadData();
397};
398
400{
401 QThreadData *threadData;
402public:
404 : threadData(threadData)
405 { ++threadData->scopeLevel; }
407 { --threadData->scopeLevel; }
408};
409
410// thread wrapper for the main() thread
412{
413 Q_DECLARE_PRIVATE(QThread)
414
415public:
418 void init();
419
420private:
421#if QT_CONFIG(thread)
422 void run() override;
423#endif
424};
425
426#if QT_CONFIG(thread)
427inline QBindingStatus *QThreadPrivate::bindingStatus()
428{
429 return data->m_statusOrPendingObjects.bindingStatus();
430}
431#endif
432
433QT_END_NAMESPACE
434
435#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:403
QStack< QEventLoop * > eventLoops
Definition qthread_p.h:371
QAtomicPointer< QAbstractEventDispatcher > eventDispatcher
Definition qthread_p.h:375
QtPrivate::BindingStatusOrList m_statusOrPendingObjects
Definition qthread_p.h:378
static QThreadData * current()
Definition qthread_p.h:320
void reuseBindingStatusForNewNativeThread()
Definition qthread_p.h:364
QThreadData(int initialRefCount=1)
Definition qthread_p.h:313
bool requiresCoreApplication
Definition qthread_p.h:390
void deref()
Definition qthread_p.h:343
static void clearCurrentThreadData()
Definition qthread.cpp:1184
bool isAdopted
Definition qthread_p.h:389
QAtomicPointer< void > threadId
Definition qthread_p.h:374
static QThreadData * get2(QThread *thread)
Definition qthread_p.h:327
QAbstractEventDispatcher * ensureEventDispatcher()
Definition qthread_p.h:348
QPostEventList postEventList
Definition qthread_p.h:372
bool canWaitLocked()
Definition qthread_p.h:356
bool hasEventDispatcher() const
Definition qthread_p.h:345
void ref()
Definition qthread_p.h:342
QAtomicPointer< QThread > thread
Definition qthread_p.h:373
void clearEvents()
Definition qthread.cpp:74
QList< void * > tls
Definition qthread_p.h:376
QAbstractEventDispatcher * createEventDispatcher()
Definition qthread.cpp:86
static void setCurrentThread(QThread *)
Definition qthread_p.h:299
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
QThreadPrivate(QThreadData *d=nullptr)
Definition qthread.cpp:1201
void removeObjectWithPendingBindingStatusChange(QObject *)
Definition qthread_p.h:297
QThreadData * data
Definition qthread_p.h:291
QBindingStatus * m_bindingStatus
Definition qthread_p.h:292
QBindingStatus * bindingStatus()
Definition qthread_p.h:295
QBindingStatus * addObjectWithPendingBindingStatusChange(QObject *)
Definition qthread_p.h:296
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
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:56