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(bool = false); // 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 = nullptr;
239 bool terminationEnabled = false; // enabled after start()
240 bool terminatePending = false;
241#endif // Q_OS_WIN
242#ifdef Q_OS_WASM
243 static int idealThreadCount;
244#endif
245 QThreadData *data;
246
247 static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data);
248
249 void ref()
250 {
251 quitLockRef.ref();
252 }
253
254 void deref()
255 {
256 if (!quitLockRef.deref() && threadState == Running) {
257 QCoreApplication::instance()->postEvent(q_ptr, new QEvent(QEvent::Quit));
258 }
259 }
260
261 QBindingStatus *bindingStatus();
262
263 /* Returns nullptr if the object has been added, or the binding status
264 if that one has been set in the meantime
265 */
266 QBindingStatus *addObjectWithPendingBindingStatusChange(QObject *obj);
267 void removeObjectWithPendingBindingStatusChange(QObject *obj);
268
269private:
270#ifdef Q_OS_INTEGRITY
271 // On INTEGRITY we set the thread name before starting it, so just fake a string
272 struct FakeString {
273 bool isEmpty() const { return true; }
274 const char *toLocal8Bit() const { return nullptr; }
275 } objectName;
276#else
277 // Used in QThread(Private)::start to avoid racy access to QObject::objectName,
278 // unset afterwards.
279 QString objectName;
280#endif
281};
282
283#else // QT_CONFIG(thread)
284
286{
287public:
288 QThreadPrivate(QThreadData *d = nullptr);
290
291 mutable QMutex mutex;
294 bool running = false;
295
296 QBindingStatus* bindingStatus() { return m_bindingStatus; }
299
300 static void setCurrentThread(QThread *) { }
301 static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data);
302
303 void ref() {}
304 void deref() {}
305
306 Q_DECLARE_PUBLIC(QThread)
307};
308
309#endif // QT_CONFIG(thread)
310
312{
313public:
314 QThreadData(int initialRefCount = 1)
316 {
317 // fprintf(stderr, "QThreadData %p created\n", this);
318 }
319 ~QThreadData();
320
322 {
323 if (QThreadData *data = currentThreadData()) Q_LIKELY_BRANCH
324 return data;
325 return createCurrentThreadData();
326 }
327 // non-creating version of current():
328 Q_DECL_PURE_FUNCTION static Q_AUTOTEST_EXPORT QThreadData *currentThreadData() noexcept;
329 static void clearCurrentThreadData();
330 static QThreadData *get2(QThread *thread)
331 { Q_ASSERT_X(thread != nullptr, "QThread", "internal error"); return thread->d_func()->data; }
332
333#if QT_CONFIG(thread)
334 void ref()
335 {
336 (void) _ref.ref();
337 Q_ASSERT(_ref.loadRelaxed() != 0);
338 }
339 void deref()
340 {
341 if (!_ref.deref())
342 delete this;
343 }
344#else
345 void ref() {}
346 void deref() {}
347#endif
348 inline bool hasEventDispatcher() const
349 { return eventDispatcher.loadRelaxed() != nullptr; }
350 QAbstractEventDispatcher *createEventDispatcher();
351 QAbstractEventDispatcher *ensureEventDispatcher()
352 {
353 QAbstractEventDispatcher *ed = eventDispatcher.loadRelaxed();
354 if (Q_LIKELY(ed))
355 return ed;
357 }
358
360 {
361 QMutexLocker locker(&postEventList.mutex);
362 return canWait;
363 }
364
365 void clearEvents();
366
368 {
369 auto status = m_statusOrPendingObjects.bindingStatus();
370 if (status)
371 QtPrivate::setBindingStatus(status, {});
372 }
373
379 QList<void *> tls;
380 // manipulating m_statusOrPendingObjects requires QTreadPrivate's mutex to be locked
382
383private:
384 QAtomicInt _ref;
385
386public:
387 int loopLevel = 0;
388 int scopeLevel = 0;
389
390 bool quitNow = false;
391 bool canWait = true;
392 bool isAdopted = false;
394
395private:
396 friend class QAbstractEventDispatcher;
397 friend class QBasicTimer;
398 static Q_AUTOTEST_EXPORT QThreadData *createCurrentThreadData();
399};
400
402{
403 QThreadData *threadData;
404public:
406 : threadData(threadData)
407 { ++threadData->scopeLevel; }
409 { --threadData->scopeLevel; }
410};
411
412// thread wrapper for the main() thread
414{
415 Q_DECLARE_PRIVATE(QThread)
416
417public:
420 void init();
421
422private:
423#if QT_CONFIG(thread)
424 void run() override;
425#endif
426};
427
428#if QT_CONFIG(thread)
429inline QBindingStatus *QThreadPrivate::bindingStatus()
430{
431 return data->m_statusOrPendingObjects.bindingStatus();
432}
433#endif
434
435QT_END_NAMESPACE
436
437#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:405
QStack< QEventLoop * > eventLoops
Definition qthread_p.h:374
QAtomicPointer< QAbstractEventDispatcher > eventDispatcher
Definition qthread_p.h:378
QtPrivate::BindingStatusOrList m_statusOrPendingObjects
Definition qthread_p.h:381
static QThreadData * current()
Definition qthread_p.h:321
void reuseBindingStatusForNewNativeThread()
Definition qthread_p.h:367
QThreadData(int initialRefCount=1)
Definition qthread_p.h:314
bool requiresCoreApplication
Definition qthread_p.h:393
void deref()
Definition qthread_p.h:346
static void clearCurrentThreadData()
Definition qthread.cpp:1205
bool isAdopted
Definition qthread_p.h:392
QAtomicPointer< void > threadId
Definition qthread_p.h:377
static QThreadData * get2(QThread *thread)
Definition qthread_p.h:330
QAbstractEventDispatcher * ensureEventDispatcher()
Definition qthread_p.h:351
QPostEventList postEventList
Definition qthread_p.h:375
bool canWaitLocked()
Definition qthread_p.h:359
bool hasEventDispatcher() const
Definition qthread_p.h:348
void ref()
Definition qthread_p.h:345
QAtomicPointer< QThread > thread
Definition qthread_p.h:376
void clearEvents()
Definition qthread.cpp:74
QList< void * > tls
Definition qthread_p.h:379
QAbstractEventDispatcher * createEventDispatcher()
Definition qthread.cpp:113
static void setCurrentThread(QThread *)
Definition qthread_p.h:300
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
QThreadPrivate(QThreadData *d=nullptr)
Definition qthread.cpp:1222
void removeObjectWithPendingBindingStatusChange(QObject *)
Definition qthread_p.h:298
QThreadData * data
Definition qthread_p.h:292
QBindingStatus * m_bindingStatus
Definition qthread_p.h:293
QBindingStatus * bindingStatus()
Definition qthread_p.h:296
QBindingStatus * addObjectWithPendingBindingStatusChange(QObject *)
Definition qthread_p.h:297
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:652
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