Qt 6.x
The Qt SDK
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
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
93: q(q), m_threadProcessing(false), m_mainProcessing(false), m_shutdown(false),
94 m_mainThreadWaiting(false), mainSync(nullptr), m_mainObject(this)
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
173{
174}
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 for (;;) {
198 if (d->mainSync || !d->mainList.isEmpty()) {
199 d->unlock();
200 d->mainEvent();
201 d->lock();
202 } else if (!d->threadList.isEmpty()) {
203 d->wait();
204 } else {
205 break;
206 }
207 }
208
210 d->quit();
211 else
213
214 d->unlock();
215 d->QThread::wait();
216}
217
219{
220 return d->m_shutdown;
221}
222
224{
225 return d->mutex();
226}
227
229{
230 d->lock();
231}
232
234{
235 d->unlock();
236}
237
239{
240 d->wakeOne();
241}
242
244{
245 d->wait();
246}
247
249{
250 return QThread::currentThreadId() == static_cast<QThreadPrivate *>(QObjectPrivate::get(d))->threadData.loadRelaxed()->threadId.loadRelaxed();
251}
252
254{
255 return const_cast<QThread *>(static_cast<const QThread *>(d));
256}
257
258void QQmlThread::internalCallMethodInThread(Message *message)
259{
260#if !QT_CONFIG(thread)
261 message->call(this);
262 delete message;
263 return;
264#endif
265
267 d->lock();
268 Q_ASSERT(d->m_mainThreadWaiting == false);
269
270 bool wasEmpty = d->threadList.isEmpty();
272 if (wasEmpty && d->m_threadProcessing == false)
274
275 d->m_mainThreadWaiting = true;
276
277 do {
278 if (d->mainSync) {
279 QQmlThread::Message *message = d->mainSync;
280 unlock();
281 message->call(this);
282 delete message;
283 lock();
284 d->mainSync = nullptr;
285 wakeOne();
286 } else {
287 d->wait();
288 }
289 } while (d->mainSync || !d->threadList.isEmpty());
290
291 d->m_mainThreadWaiting = false;
292 d->unlock();
293}
294
302void QQmlThread::internalCallMethodInMain(Message *message)
303{
304#if !QT_CONFIG(thread)
305 message->call(this);
306 delete message;
307 return;
308#endif
309
311
312 d->lock();
313
314 Q_ASSERT(d->mainSync == nullptr);
315 d->mainSync = message;
316
317 if (d->m_mainThreadWaiting) {
318 d->wakeOne();
319 } else if (d->m_mainProcessing) {
320 // Do nothing - it is already looping
321 } else {
322 d->triggerMainEvent();
323 }
324
325 while (d->mainSync) {
326 if (d->m_shutdown) {
327 delete d->mainSync;
328 d->mainSync = nullptr;
329 break;
330 }
331 d->wait();
332 }
333
334 d->unlock();
335}
336
337void QQmlThread::internalPostMethodToThread(Message *message)
338{
339#if !QT_CONFIG(thread)
340 internalPostMethodToMain(message);
341 return;
342#endif
344 d->lock();
345 bool wasEmpty = d->threadList.isEmpty();
347 if (wasEmpty && d->m_threadProcessing == false)
349 d->unlock();
350}
351
352void QQmlThread::internalPostMethodToMain(Message *message)
353{
354#if QT_CONFIG(thread)
356#endif
357 d->lock();
358 bool wasEmpty = d->mainList.isEmpty();
360 if (wasEmpty && d->m_mainProcessing == false)
361 d->triggerMainEvent();
362 d->unlock();
363}
364
377{
378#if QT_CONFIG(thread)
380#endif
381 Q_ASSERT(d->m_mainThreadWaiting == false);
382
383 d->m_mainThreadWaiting = true;
384
385 if (d->mainSync || !d->threadList.isEmpty()) {
386 if (d->mainSync) {
387 QQmlThread::Message *message = d->mainSync;
388 unlock();
389 message->call(this);
390 delete message;
391 lock();
392 d->mainSync = nullptr;
393 wakeOne();
394 } else {
395 d->wait();
396 }
397 }
398
399 d->m_mainThreadWaiting = false;
400}
401
402
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
N * first() const
void append(N *)
bool isEmpty() const
N * takeFirst()
\inmodule QtCore
Definition qmutex.h:285
void unlock() noexcept
Unlocks the mutex.
Definition qmutex.h:293
void lock() noexcept
Locks the mutex.
Definition qmutex.h:290
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:153
\inmodule QtCore
Definition qobject.h:90
void moveToThread(QThread *thread)
Changes the thread affinity for this object and its children.
Definition qobject.cpp:1606
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:1363
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
Definition qobject.h:114
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 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:923
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:956
static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION
Definition qthread.h:154
void setStackSize(uint stackSize)
Definition qthread.cpp:1046
void quit()
Definition qthread.cpp:935
bool wait(QMutex *, QDeadlineTimer=QDeadlineTimer(QDeadlineTimer::Forever))
#define this
Definition dialogs.cpp:9
double e
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