aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/ftw/qqmlthread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/ftw/qqmlthread.cpp')
-rw-r--r--src/qml/qml/ftw/qqmlthread.cpp167
1 files changed, 65 insertions, 102 deletions
diff --git a/src/qml/qml/ftw/qqmlthread.cpp b/src/qml/qml/ftw/qqmlthread.cpp
index e961ed3d0d..57f91b6b4d 100644
--- a/src/qml/qml/ftw/qqmlthread.cpp
+++ b/src/qml/qml/ftw/qqmlthread.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qqmlthread_p.h"
@@ -47,6 +11,8 @@
#include <QtCore/qwaitcondition.h>
#include <QtCore/qcoreapplication.h>
+#include <QtCore/private/qthread_p.h>
+
QT_BEGIN_NAMESPACE
class QQmlThreadPrivate : public QThread
@@ -55,19 +21,16 @@ public:
QQmlThreadPrivate(QQmlThread *);
QQmlThread *q;
- void run() override;
-
inline QMutex &mutex() { return _mutex; }
inline void lock() { _mutex.lock(); }
inline void unlock() { _mutex.unlock(); }
inline void wait() { _wait.wait(&_mutex); }
inline void wakeOne() { _wait.wakeOne(); }
- inline void wakeAll() { _wait.wakeAll(); }
- quint32 m_threadProcessing:1; // Set when the thread is processing messages
- quint32 m_mainProcessing:1; // Set when the main thread is processing messages
- quint32 m_shutdown:1; // Set by main thread to request a shutdown
- quint32 m_mainThreadWaiting:1; // Set by main thread if it is waiting for the message queue to empty
+ bool m_threadProcessing; // Set when the thread is processing messages
+ bool m_mainProcessing; // Set when the main thread is processing messages
+ bool m_shutdown; // Set by main thread to request a shutdown
+ bool m_mainThreadWaiting; // Set by main thread if it is waiting for the message queue to empty
typedef QFieldList<QQmlThread::Message, &QQmlThread::Message::next> MessageList;
MessageList threadList;
@@ -131,6 +94,9 @@ QQmlThreadPrivate::QQmlThreadPrivate(QQmlThread *q)
m_mainThreadWaiting(false), mainSync(nullptr), m_mainObject(this)
{
setObjectName(QStringLiteral("QQmlThread"));
+ // This size is aligned with the recursion depth limits in the parser/codegen. In case of
+ // absurd content we want to hit the recursion checks instead of running out of stack.
+ setStackSize(8 * 1024 * 1024);
}
bool QQmlThreadPrivate::event(QEvent *e)
@@ -140,19 +106,6 @@ bool QQmlThreadPrivate::event(QEvent *e)
return QThread::event(e);
}
-void QQmlThreadPrivate::run()
-{
- lock();
-
- wakeOne();
-
- unlock();
-
- q->startupThread();
- exec();
- q->shutdownThread();
-}
-
void QQmlThreadPrivate::mainEvent()
{
lock();
@@ -185,13 +138,7 @@ void QQmlThreadPrivate::threadEvent()
lock();
for (;;) {
- if (m_shutdown) {
- quit();
- wakeOne();
- unlock();
-
- return;
- } else if (!threadList.isEmpty()) {
+ if (!threadList.isEmpty()) {
m_threadProcessing = true;
QQmlThread::Message *message = threadList.first();
@@ -203,6 +150,12 @@ void QQmlThreadPrivate::threadEvent()
lock();
delete threadList.takeFirst();
+ } else if (m_shutdown) {
+ quit();
+ wakeOne();
+ unlock();
+
+ return;
} else {
wakeOne();
@@ -225,12 +178,13 @@ QQmlThread::~QQmlThread()
delete d;
}
+/*!
+ \internal
+ Starts the actual worker thread.
+ */
void QQmlThread::startup()
{
- d->lock();
d->start();
- d->wait();
- d->unlock();
d->moveToThread(d);
}
@@ -239,28 +193,19 @@ void QQmlThread::shutdown()
d->lock();
Q_ASSERT(!d->m_shutdown);
- for (;;) {
- if (d->mainSync || !d->mainList.isEmpty()) {
- d->unlock();
- d->mainEvent();
- d->lock();
- } else if (!d->threadList.isEmpty()) {
- d->wait();
- } else {
- break;
- }
- }
-
d->m_shutdown = true;
- if (QCoreApplication::closingDown()) {
+
+ if (QCoreApplication::closingDown())
d->quit();
- } else {
+ else
d->triggerThreadEvent();
- d->wait();
- }
d->unlock();
d->QThread::wait();
+
+ // Discard all remaining messages.
+ // We don't need the lock anymore because the thread is dead.
+ discardMessages();
}
bool QQmlThread::isShutdown() const
@@ -288,11 +233,6 @@ void QQmlThread::wakeOne()
d->wakeOne();
}
-void QQmlThread::wakeAll()
-{
- d->wakeAll();
-}
-
void QQmlThread::wait()
{
d->wait();
@@ -300,7 +240,7 @@ void QQmlThread::wait()
bool QQmlThread::isThisThread() const
{
- return QThread::currentThread() == d;
+ return QThread::currentThreadId() == static_cast<QThreadPrivate *>(QObjectPrivate::get(d))->threadData.loadRelaxed()->threadId.loadRelaxed();
}
QThread *QQmlThread::thread() const
@@ -308,16 +248,6 @@ QThread *QQmlThread::thread() const
return const_cast<QThread *>(static_cast<const QThread *>(d));
}
-// Called when the thread starts. Do startup stuff in here.
-void QQmlThread::startupThread()
-{
-}
-
-// Called when the thread shuts down. Do cleanup in here.
-void QQmlThread::shutdownThread()
-{
-}
-
void QQmlThread::internalCallMethodInThread(Message *message)
{
#if !QT_CONFIG(thread)
@@ -355,6 +285,13 @@ void QQmlThread::internalCallMethodInThread(Message *message)
d->unlock();
}
+/*!
+ \internal
+ \note This method needs to run in the worker/QQmlThread
+
+ This runs \a message in the main thread, and blocks the
+ worker thread until the call has completed
+ */
void QQmlThread::internalCallMethodInMain(Message *message)
{
#if !QT_CONFIG(thread)
@@ -418,12 +355,22 @@ void QQmlThread::internalPostMethodToMain(Message *message)
d->unlock();
}
+/*!
+ \internal
+ \note This method must be called in the main thread
+ \warning This method requires that the lock is held!
+
+ A call to this method will either:
+ - run a message requested to run synchronously on the main thread if there is one
+ (and return afterrwards),
+ - wait for the worker thread to notify it if the worker thread has pending work,
+ - or simply return if neither of the conditions above hold
+ */
void QQmlThread::waitForNextMessage()
{
#if QT_CONFIG(thread)
Q_ASSERT(!isThisThread());
#endif
- d->lock();
Q_ASSERT(d->m_mainThreadWaiting == false);
d->m_mainThreadWaiting = true;
@@ -443,8 +390,24 @@ void QQmlThread::waitForNextMessage()
}
d->m_mainThreadWaiting = false;
- d->unlock();
}
+/*!
+ \internal
+ \note This method must be called in the main thread
+ \warning This method requires that the lock is held!
+
+ Clear all pending events, for either thread.
+*/
+void QQmlThread::discardMessages()
+{
+ Q_ASSERT(!isThisThread());
+ if (Message *mainSync = std::exchange(d->mainSync, nullptr))
+ delete mainSync;
+ while (!d->mainList.isEmpty())
+ delete d->mainList.takeFirst();
+ while (!d->threadList.isEmpty())
+ delete d->threadList.takeFirst();
+}
QT_END_NAMESPACE