Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmlthread.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qqmlthread_p.h"
5
6#include <private/qfieldlist_p.h>
7
8#include <QtCore/qmutex.h>
9#include <QtCore/qthread.h>
10#include <QtCore/qcoreevent.h>
11#include <QtCore/qwaitcondition.h>
12#include <QtCore/qcoreapplication.h>
13
14#include <QtCore/private/qthread_p.h>
15
17
19{
20public:
23
24 inline QMutex &mutex() { return _mutex; }
25 inline void lock() { _mutex.lock(); }
26 inline void unlock() { _mutex.unlock(); }
27 inline void wait() { _wait.wait(&_mutex); }
28 inline void wakeOne() { _wait.wakeOne(); }
29
30 bool m_threadProcessing; // Set when the thread is processing messages
31 bool m_mainProcessing; // Set when the main thread is processing messages
32 bool m_shutdown; // Set by main thread to request a shutdown
33 bool m_mainThreadWaiting; // Set by main thread if it is waiting for the message queue to empty
34
35 typedef QFieldList<QQmlThread::Message, &QQmlThread::Message::next> MessageList;
38
39 QQmlThread::Message *mainSync;
40
41 void triggerMainEvent();
42 void triggerThreadEvent();
43
44 void mainEvent();
45 void threadEvent();
46
47protected:
48 bool event(QEvent *) override;
49
50private:
51 struct MainObject : public QObject {
52 MainObject(QQmlThreadPrivate *p);
53 bool event(QEvent *e) override;
55 };
56 MainObject m_mainObject;
57
58 QMutex _mutex;
59 QWaitCondition _wait;
60};
61
62QQmlThreadPrivate::MainObject::MainObject(QQmlThreadPrivate *p)
63: p(p)
64{
65}
66
67// Trigger mainEvent in main thread. Must be called from thread.
69{
70#if QT_CONFIG(thread)
71 Q_ASSERT(q->isThisThread());
72#endif
74}
75
76// Trigger even in thread. Must be called from main thread.
78{
79#if QT_CONFIG(thread)
80 Q_ASSERT(!q->isThisThread());
81#endif
83}
84
85bool QQmlThreadPrivate::MainObject::event(QEvent *e)
86{
87 if (e->type() == QEvent::User)
88 p->mainEvent();
89 return QObject::event(e);
90}
91
95{
96 setObjectName(QStringLiteral("QQmlThread"));
97 // This size is aligned with the recursion depth limits in the parser/codegen. In case of
98 // absurd content we want to hit the recursion checks instead of running out of stack.
99 setStackSize(8 * 1024 * 1024);
100}
101
103{
104 if (e->type() == QEvent::User)
105 threadEvent();
106 return QThread::event(e);
107}
108
110{
111 lock();
112
113 m_mainProcessing = true;
114
115 while (!mainList.isEmpty() || mainSync) {
116 bool isSync = mainSync != nullptr;
117 QQmlThread::Message *message = isSync?mainSync:mainList.takeFirst();
118 unlock();
119
120 message->call(q);
121 delete message;
122
123 lock();
124
125 if (isSync) {
126 mainSync = nullptr;
127 wakeOne();
128 }
129 }
130
131 m_mainProcessing = false;
132
133 unlock();
134}
135
137{
138 lock();
139
140 for (;;) {
141 if (!threadList.isEmpty()) {
142 m_threadProcessing = true;
143
144 QQmlThread::Message *message = threadList.first();
145
146 unlock();
147
148 message->call(q);
149
150 lock();
151
152 delete threadList.takeFirst();
153 } else if (m_shutdown) {
154 quit();
155 wakeOne();
156 unlock();
157
158 return;
159 } else {
160 wakeOne();
161
162 m_threadProcessing = false;
163
164 unlock();
165
166 return;
167 }
168 }
169}
170
175
177{
178 delete d;
179}
180
186{
187 d->start();
188 d->moveToThread(d);
189}
190
192{
193 d->lock();
194 Q_ASSERT(!d->m_shutdown);
195
196 d->m_shutdown = true;
197
199 d->quit();
200 else
202
203 d->unlock();
204 d->QThread::wait();
205
206 // Discard all remaining messages.
207 // We don't need the lock anymore because the thread is dead.
209}
210
212{
213 return d->m_shutdown;
214}
215
217{
218 return d->mutex();
219}
220
222{
223 d->lock();
224}
225
227{
228 d->unlock();
229}
230
232{
233 d->wakeOne();
234}
235
237{
238 d->wait();
239}
240
242{
243 return QThread::currentThreadId() == static_cast<QThreadPrivate *>(QObjectPrivate::get(d))->threadData.loadRelaxed()->threadId.loadRelaxed();
244}
245
247{
248 return const_cast<QThread *>(static_cast<const QThread *>(d));
249}
250
251void QQmlThread::internalCallMethodInThread(Message *message)
252{
253#if !QT_CONFIG(thread)
254 message->call(this);
255 delete message;
256 return;
257#endif
258
260 d->lock();
261 Q_ASSERT(d->m_mainThreadWaiting == false);
262
263 bool wasEmpty = d->threadList.isEmpty();
265 if (wasEmpty && d->m_threadProcessing == false)
267
268 d->m_mainThreadWaiting = true;
269
270 do {
271 if (d->mainSync) {
272 QQmlThread::Message *message = d->mainSync;
273 unlock();
274 message->call(this);
275 delete message;
276 lock();
277 d->mainSync = nullptr;
278 wakeOne();
279 } else {
280 d->wait();
281 }
282 } while (d->mainSync || !d->threadList.isEmpty());
283
284 d->m_mainThreadWaiting = false;
285 d->unlock();
286}
287
295void QQmlThread::internalCallMethodInMain(Message *message)
296{
297#if !QT_CONFIG(thread)
298 message->call(this);
299 delete message;
300 return;
301#endif
302
304
305 d->lock();
306
307 Q_ASSERT(d->mainSync == nullptr);
308 d->mainSync = message;
309
310 if (d->m_mainThreadWaiting) {
311 d->wakeOne();
312 } else if (d->m_mainProcessing) {
313 // Do nothing - it is already looping
314 } else {
315 d->triggerMainEvent();
316 }
317
318 while (d->mainSync) {
319 if (d->m_shutdown) {
320 delete d->mainSync;
321 d->mainSync = nullptr;
322 break;
323 }
324 d->wait();
325 }
326
327 d->unlock();
328}
329
330void QQmlThread::internalPostMethodToThread(Message *message)
331{
332#if !QT_CONFIG(thread)
333 internalPostMethodToMain(message);
334 return;
335#endif
337 d->lock();
338 bool wasEmpty = d->threadList.isEmpty();
340 if (wasEmpty && d->m_threadProcessing == false)
342 d->unlock();
343}
344
345void QQmlThread::internalPostMethodToMain(Message *message)
346{
347#if QT_CONFIG(thread)
349#endif
350 d->lock();
351 bool wasEmpty = d->mainList.isEmpty();
353 if (wasEmpty && d->m_mainProcessing == false)
354 d->triggerMainEvent();
355 d->unlock();
356}
357
370{
371#if QT_CONFIG(thread)
373#endif
374 Q_ASSERT(d->m_mainThreadWaiting == false);
375
376 d->m_mainThreadWaiting = true;
377
378 if (d->mainSync || !d->threadList.isEmpty()) {
379 if (d->mainSync) {
380 QQmlThread::Message *message = d->mainSync;
381 unlock();
382 message->call(this);
383 delete message;
384 lock();
385 d->mainSync = nullptr;
386 wakeOne();
387 } else {
388 d->wait();
389 }
390 }
391
392 d->m_mainThreadWaiting = false;
393}
394
403{
405 if (Message *mainSync = std::exchange(d->mainSync, nullptr))
406 delete mainSync;
407 while (!d->mainList.isEmpty())
408 delete d->mainList.takeFirst();
409 while (!d->threadList.isEmpty())
410 delete d->threadList.takeFirst();
411}
412
[custom type definition]
static bool closingDown()
Returns true if the application objects are being destroyed; otherwise returns false.
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
\inmodule QtCore
Definition qcoreevent.h:45
Type type() const
Returns the event type.
Definition qcoreevent.h:304
N * first() const
void append(N *)
bool isEmpty() const
N * takeFirst()
\inmodule QtCore
Definition qmutex.h:281
void unlock() noexcept
Unlocks the mutex.
Definition qmutex.h:289
void lock() noexcept
Locks the mutex.
Definition qmutex.h:286
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1389
bool moveToThread(QThread *thread QT6_DECL_NEW_OVERLOAD_TAIL)
Changes the thread affinity for this object and its children and returns true on success.
Definition qobject.cpp:1643
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
Definition qobject.h:127
QQmlThreadPrivate(QQmlThread *)
void triggerThreadEvent()
QQmlThread * q
MessageList threadList
MessageList mainList
QFieldList< QQmlThread::Message, &QQmlThread::Message::next > MessageList
bool event(QEvent *) override
This virtual function receives events to an object and should return true if the event e was recogniz...
QQmlThread::Message * mainSync
QThread * thread() const
void discardMessages()
void unlock()
bool isThisThread() const
void shutdown()
void waitForNextMessage()
bool isShutdown() const
void wakeOne()
QMutex & mutex()
void startup()
virtual ~QQmlThread()
void start(Priority=InheritPriority)
Definition qthread.cpp:996
bool event(QEvent *event) override
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qthread.cpp:1029
static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION
Definition qthread.h:149
void setStackSize(uint stackSize)
Definition qthread.cpp:1130
void quit()
Definition qthread.cpp:1008
bool wait(QMutex *, QDeadlineTimer=QDeadlineTimer(QDeadlineTimer::Forever))
#define this
Definition dialogs.cpp:9
Combined button and popup list for selecting options.
GLuint GLsizei const GLchar * message
struct _cl_event * event
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
QObject::connect nullptr