diff options
Diffstat (limited to 'src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp')
-rw-r--r-- | src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp | 767 |
1 files changed, 0 insertions, 767 deletions
diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp deleted file mode 100644 index 13d5292eb2..0000000000 --- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp +++ /dev/null @@ -1,767 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#include "qqmldebugserverfactory.h" - -#include <private/qqmldebugserver_p.h> -#include <private/qqmldebugserverconnection_p.h> -#include <private/qqmldebugservice_p.h> -#include <private/qjsengine_p.h> -#include <private/qqmlglobal_p.h> -#include <private/qqmldebugpluginmanager_p.h> -#include <private/qqmldebugserviceinterfaces_p.h> -#include <private/qpacketprotocol_p.h> -#include <private/qversionedpacket_p.h> - -#include <QtCore/QAtomicInt> -#include <QtCore/QDir> -#include <QtCore/QPluginLoader> -#include <QtCore/QStringList> -#include <QtCore/QVector> -#include <QtCore/qwaitcondition.h> - -QT_BEGIN_NAMESPACE - -/* - QQmlDebug Protocol (Version 1): - - handshake: - 1. Client sends - "QDeclarativeDebugServer" 0 version pluginNames [QDataStream version] - version: an int representing the highest protocol version the client knows - pluginNames: plugins available on client side - 2. Server sends - "QDeclarativeDebugClient" 0 version pluginNames pluginVersions [QDataStream version] - version: an int representing the highest protocol version the client & server know - pluginNames: plugins available on server side. plugins both in the client and server message are enabled. - client plugin advertisement - 1. Client sends - "QDeclarativeDebugServer" 1 pluginNames - server plugin advertisement (not implemented: all services are required to register before open()) - 1. Server sends - "QDeclarativeDebugClient" 1 pluginNames pluginVersions - plugin communication: - Everything send with a header different to "QDeclarativeDebugServer" is sent to the appropriate plugin. - */ - -Q_QML_DEBUG_PLUGIN_LOADER(QQmlDebugServerConnection) - -const int protocolVersion = 1; -using QQmlDebugPacket = QVersionedPacket<QQmlDebugConnector>; - -class QQmlDebugServerImpl; -class QQmlDebugServerThread : public QThread -{ -public: - QQmlDebugServerThread() : m_server(nullptr), m_portFrom(-1), m_portTo(-1) {} - - void setServer(QQmlDebugServerImpl *server) - { - m_server = server; - } - - void setPortRange(int portFrom, int portTo, const QString &hostAddress) - { - m_pluginName = QLatin1String("QTcpServerConnection"); - m_portFrom = portFrom; - m_portTo = portTo; - m_hostAddress = hostAddress; - } - - void setFileName(const QString &fileName) - { - m_pluginName = QLatin1String("QLocalClientConnection"); - m_fileName = fileName; - } - - const QString &pluginName() const - { - return m_pluginName; - } - - void run() override; - -private: - QQmlDebugServerImpl *m_server; - QString m_pluginName; - int m_portFrom; - int m_portTo; - QString m_hostAddress; - QString m_fileName; -}; - -class QQmlDebugServerImpl : public QQmlDebugServer -{ - Q_OBJECT -public: - QQmlDebugServerImpl(); - - bool blockingMode() const override; - - QQmlDebugService *service(const QString &name) const override; - - void addEngine(QJSEngine *engine) override; - void removeEngine(QJSEngine *engine) override; - bool hasEngine(QJSEngine *engine) const override; - - bool addService(const QString &name, QQmlDebugService *service) override; - bool removeService(const QString &name) override; - - bool open(const QVariantHash &configuration) override; - void setDevice(QIODevice *socket) override; - - void parseArguments(); - - static void cleanup(); - -private: - friend class QQmlDebugServerThread; - friend class QQmlDebugServerFactory; - - class EngineCondition { - public: - EngineCondition() : numServices(0), condition(new QWaitCondition) {} - - bool waitForServices(QMutex *locked, int numEngines); - bool isWaiting() const { return numServices > 0; } - - void wake(); - private: - int numServices; - - // shared pointer to allow for QHash-inflicted copying. - QSharedPointer<QWaitCondition> condition; - }; - - bool canSendMessage(const QString &name); - void doSendMessage(const QString &name, const QByteArray &message); - void wakeEngine(QJSEngine *engine); - void sendMessage(const QString &name, const QByteArray &message); - void sendMessages(const QString &name, const QList<QByteArray> &messages); - void changeServiceState(const QString &serviceName, QQmlDebugService::State state); - void removeThread(); - void receiveMessage(); - void protocolError(); - - QQmlDebugServerConnection *m_connection; - QHash<QString, QQmlDebugService *> m_plugins; - QStringList m_clientPlugins; - bool m_gotHello; - bool m_blockingMode; - - QHash<QJSEngine *, EngineCondition> m_engineConditions; - - mutable QMutex m_helloMutex; - QWaitCondition m_helloCondition; - QQmlDebugServerThread m_thread; - QPacketProtocol *m_protocol; - QAtomicInt m_changeServiceStateCalls; -}; - -void QQmlDebugServerImpl::cleanup() -{ - QQmlDebugServerImpl *server = static_cast<QQmlDebugServerImpl *>( - QQmlDebugConnector::instance()); - if (!server) - return; - - { - QObject signalSource; - for (QHash<QString, QQmlDebugService *>::ConstIterator i = server->m_plugins.constBegin(); - i != server->m_plugins.constEnd(); ++i) { - server->m_changeServiceStateCalls.ref(); - QString key = i.key(); - // Process this in the server's thread. - connect(&signalSource, &QObject::destroyed, server, [key, server](){ - server->changeServiceState(key, QQmlDebugService::NotConnected); - }, Qt::QueuedConnection); - } - } - - // Wait for changeServiceState calls to finish - // (while running an event loop because some services - // might again defer execution of stuff in the GUI thread) - QEventLoop loop; - while (!server->m_changeServiceStateCalls.testAndSetOrdered(0, 0)) - loop.processEvents(); - - // Stop the thread while the application is still there. - server->m_thread.exit(); - server->m_thread.wait(); -} - -void QQmlDebugServerThread::run() -{ - Q_ASSERT_X(m_server != nullptr, Q_FUNC_INFO, "There should always be a debug server available here."); - QQmlDebugServerConnection *connection = loadQQmlDebugServerConnection(m_pluginName); - if (connection) { - { - QMutexLocker connectionLocker(&m_server->m_helloMutex); - m_server->m_connection = connection; - connection->setServer(m_server); - m_server->m_helloCondition.wakeAll(); - } - - if (m_fileName.isEmpty()) { - if (!connection->setPortRange(m_portFrom, m_portTo, m_server->blockingMode(), - m_hostAddress)) - return; - } else if (!connection->setFileName(m_fileName, m_server->blockingMode())) { - return; - } - - if (m_server->blockingMode()) - connection->waitForConnection(); - } else { - qWarning() << "QML Debugger: Couldn't load plugin" << m_pluginName; - return; - } - - exec(); - - // make sure events still waiting are processed - QEventLoop eventLoop; - eventLoop.processEvents(QEventLoop::AllEvents); -} - -bool QQmlDebugServerImpl::blockingMode() const -{ - return m_blockingMode; -} - -static void cleanupOnShutdown() -{ - // We cannot do this in the destructor as the connection plugin will get unloaded before the - // server plugin and we need the connection to send any remaining data. This function is - // triggered before any plugins are unloaded. - QQmlDebugServerImpl::cleanup(); -} - -QQmlDebugServerImpl::QQmlDebugServerImpl() : - m_connection(nullptr), - m_gotHello(false), - m_blockingMode(false) -{ - static bool postRoutineAdded = false; - if (!postRoutineAdded) { - qAddPostRoutine(cleanupOnShutdown); - postRoutineAdded = true; - } - - // used in sendMessages - qRegisterMetaType<QList<QByteArray> >("QList<QByteArray>"); - // used in changeServiceState - qRegisterMetaType<QQmlDebugService::State>("QQmlDebugService::State"); - - m_thread.setServer(this); - moveToThread(&m_thread); - - // Remove the thread immmediately when it finishes, so that we don't have to wait for the - // event loop to signal that. - QObject::connect(&m_thread, &QThread::finished, this, &QQmlDebugServerImpl::removeThread, - Qt::DirectConnection); - m_thread.setObjectName(QStringLiteral("QQmlDebugServerThread")); - parseArguments(); -} - -bool QQmlDebugServerImpl::open(const QVariantHash &configuration = QVariantHash()) -{ - if (m_thread.isRunning()) - return false; - if (!configuration.isEmpty()) { - m_blockingMode = configuration[QLatin1String("block")].toBool(); - if (configuration.contains(QLatin1String("portFrom"))) { - int portFrom = configuration[QLatin1String("portFrom")].toInt(); - int portTo = configuration[QLatin1String("portTo")].toInt(); - m_thread.setPortRange(portFrom, portTo == -1 ? portFrom : portTo, - configuration[QLatin1String("hostAddress")].toString()); - } else if (configuration.contains(QLatin1String("fileName"))) { - m_thread.setFileName(configuration[QLatin1String("fileName")].toString()); - } else { - return false; - } - } - - if (m_thread.pluginName().isEmpty()) - return false; - - QMutexLocker locker(&m_helloMutex); - m_thread.start(); - m_helloCondition.wait(&m_helloMutex); // wait for connection - if (m_blockingMode && !m_gotHello) - m_helloCondition.wait(&m_helloMutex); // wait for hello - return true; -} - -void QQmlDebugServerImpl::parseArguments() -{ - // format: qmljsdebugger=port:<port_from>[,port_to],host:<ip address>][,block] - const QString args = commandLineArguments(); - if (args.isEmpty()) - return; // Manual initialization, through QQmlDebugServer::open() - - // ### remove port definition when protocol is changed - int portFrom = 0; - int portTo = 0; - bool block = false; - bool ok = false; - QString hostAddress; - QString fileName; - QStringList services; - - const auto lstjsDebugArguments = QStringView{args}.split(QLatin1Char(','), Qt::SkipEmptyParts); - for (auto argsIt = lstjsDebugArguments.begin(), argsItEnd = lstjsDebugArguments.end(); argsIt != argsItEnd; ++argsIt) { - const QStringView &strArgument = *argsIt; - if (strArgument.startsWith(QLatin1String("port:"))) { - portFrom = strArgument.mid(5).toInt(&ok); - portTo = portFrom; - const auto argsNext = argsIt + 1; - if (argsNext == argsItEnd) - break; - if (ok) { - portTo = argsNext->toString().toInt(&ok); - if (ok) { - ++argsIt; - } else { - portTo = portFrom; - ok = true; - } - } - } else if (strArgument.startsWith(QLatin1String("host:"))) { - hostAddress = strArgument.mid(5).toString(); - } else if (strArgument == QLatin1String("block")) { - block = true; - } else if (strArgument.startsWith(QLatin1String("file:"))) { - fileName = strArgument.mid(5).toString(); - ok = !fileName.isEmpty(); - } else if (strArgument.startsWith(QLatin1String("services:"))) { - services.append(strArgument.mid(9).toString()); - } else if (!services.isEmpty()) { - services.append(strArgument.toString()); - } else if (!strArgument.startsWith(QLatin1String("connector:"))) { - const QString message = tr("QML Debugger: Invalid argument \"%1\" detected." - " Ignoring the same.").arg(strArgument.toString()); - qWarning("%s", qPrintable(message)); - } - } - - if (ok) { - setServices(services); - m_blockingMode = block; - if (!fileName.isEmpty()) - m_thread.setFileName(fileName); - else - m_thread.setPortRange(portFrom, portTo, hostAddress); - } else { - QString usage; - QTextStream str(&usage); - str << tr("QML Debugger: Ignoring \"-qmljsdebugger=%1\".").arg(args) << '\n' - << tr("The format is \"-qmljsdebugger=[file:<file>|port:<port_from>][,<port_to>]" - "[,host:<ip address>][,block][,services:<service>][,<service>]*\"") << '\n' - << tr("\"file:\" can be used to specify the name of a file the debugger will try " - "to connect to using a QLocalSocket. If \"file:\" is given any \"host:\" and" - "\"port:\" arguments will be ignored.") << '\n' - << tr("\"host:\" and \"port:\" can be used to specify an address and a single " - "port or a range of ports the debugger will try to bind to with a " - "QTcpServer.") << '\n' - << tr("\"block\" makes the debugger and some services wait for clients to be " - "connected and ready before the first QML engine starts.") << '\n' - << tr("\"services:\" can be used to specify which debug services the debugger " - "should load. Some debug services interact badly with others. The V4 " - "debugger should not be loaded when using the QML profiler as it will force " - "any V4 engines to use the JavaScript interpreter rather than the JIT. The " - "following debug services are available by default:") << '\n' - << QQmlEngineDebugService::s_key << "\t- " << tr("The QML debugger") << '\n' - << QV4DebugService::s_key << "\t- " << tr("The V4 debugger") << '\n' - << QQmlInspectorService::s_key << "\t- " << tr("The QML inspector") << '\n' - << QQmlProfilerService::s_key << "\t- " << tr("The QML profiler") << '\n' - << QQmlEngineControlService::s_key << "\t- " - //: Please preserve the line breaks and formatting - << tr("Allows the client to delay the starting and stopping of\n" - "\t\t QML engines until other services are ready. QtCreator\n" - "\t\t uses this service with the QML profiler in order to\n" - "\t\t profile multiple QML engines at the same time.") - << '\n' << QDebugMessageService::s_key << "\t- " - //: Please preserve the line breaks and formatting - << tr("Sends qDebug() and similar messages over the QML debug\n" - "\t\t connection. QtCreator uses this for showing debug\n" - "\t\t messages in the debugger console.") << '\n' - << '\n' << QQmlDebugTranslationService::s_key << "\t- " - //: Please preserve the line breaks and formatting - << tr("helps to see if a translated text\n" - "\t\t will result in an elided text\n" - "\t\t in QML elements.") << '\n' - << tr("Other services offered by qmltooling plugins that implement " - "QQmlDebugServiceFactory and which can be found in the standard plugin " - "paths will also be available and can be specified. If no \"services\" " - "argument is given, all services found this way, including the default " - "ones, are loaded."); - qWarning("%s", qPrintable(usage)); - } -} - -void QQmlDebugServerImpl::receiveMessage() -{ - typedef QHash<QString, QQmlDebugService*>::const_iterator DebugServiceConstIt; - - // to be executed in debugger thread - Q_ASSERT(QThread::currentThread() == thread()); - - if (!m_protocol) - return; - - QQmlDebugPacket in(m_protocol->read()); - - QString name; - - in >> name; - if (name == QLatin1String("QDeclarativeDebugServer")) { - int op = -1; - in >> op; - if (op == 0) { - int version; - in >> version >> m_clientPlugins; - - //Get the supported QDataStream version - if (!in.atEnd()) { - in >> s_dataStreamVersion; - if (s_dataStreamVersion > QDataStream::Qt_DefaultCompiledVersion) - s_dataStreamVersion = QDataStream::Qt_DefaultCompiledVersion; - } - - bool clientSupportsMultiPackets = false; - if (!in.atEnd()) - in >> clientSupportsMultiPackets; - - // Send the hello answer immediately, since it needs to arrive before - // the plugins below start sending messages. - - QQmlDebugPacket out; - QStringList pluginNames; - QList<float> pluginVersions; - if (clientSupportsMultiPackets) { // otherwise, disable all plugins - const int count = m_plugins.count(); - pluginNames.reserve(count); - pluginVersions.reserve(count); - for (QHash<QString, QQmlDebugService *>::ConstIterator i = m_plugins.constBegin(); - i != m_plugins.constEnd(); ++i) { - pluginNames << i.key(); - pluginVersions << i.value()->version(); - } - } - - out << QString(QStringLiteral("QDeclarativeDebugClient")) << 0 << protocolVersion - << pluginNames << pluginVersions << dataStreamVersion(); - - m_protocol->send(out.data()); - m_connection->flush(); - - QMutexLocker helloLock(&m_helloMutex); - m_gotHello = true; - - for (DebugServiceConstIt iter = m_plugins.constBegin(), cend = m_plugins.constEnd(); iter != cend; ++iter) { - QQmlDebugService::State newState = QQmlDebugService::Unavailable; - if (m_clientPlugins.contains(iter.key())) - newState = QQmlDebugService::Enabled; - m_changeServiceStateCalls.ref(); - changeServiceState(iter.key(), newState); - } - - m_helloCondition.wakeAll(); - - } else if (op == 1) { - // Service Discovery - QStringList oldClientPlugins = m_clientPlugins; - in >> m_clientPlugins; - - for (DebugServiceConstIt iter = m_plugins.constBegin(), cend = m_plugins.constEnd(); iter != cend; ++iter) { - const QString &pluginName = iter.key(); - QQmlDebugService::State newState = QQmlDebugService::Unavailable; - if (m_clientPlugins.contains(pluginName)) - newState = QQmlDebugService::Enabled; - - if (oldClientPlugins.contains(pluginName) - != m_clientPlugins.contains(pluginName)) { - m_changeServiceStateCalls.ref(); - changeServiceState(iter.key(), newState); - } - } - - } else { - qWarning("QML Debugger: Invalid control message %d.", op); - protocolError(); - return; - } - - } else { - if (m_gotHello) { - QHash<QString, QQmlDebugService *>::Iterator iter = m_plugins.find(name); - if (iter == m_plugins.end()) { - qWarning() << "QML Debugger: Message received for missing plugin" << name << '.'; - } else { - QQmlDebugService *service = *iter; - QByteArray message; - while (!in.atEnd()) { - in >> message; - service->messageReceived(message); - } - } - } else { - qWarning("QML Debugger: Invalid hello message."); - } - - } -} - -void QQmlDebugServerImpl::changeServiceState(const QString &serviceName, - QQmlDebugService::State newState) -{ - // to be executed in debugger thread - Q_ASSERT(QThread::currentThread() == thread()); - - QQmlDebugService *service = m_plugins.value(serviceName); - if (service && service->state() != newState) { - service->stateAboutToBeChanged(newState); - service->setState(newState); - service->stateChanged(newState); - } - - m_changeServiceStateCalls.deref(); -} - -void QQmlDebugServerImpl::removeThread() -{ - Q_ASSERT(m_thread.isFinished()); - Q_ASSERT(QThread::currentThread() == thread()); - - QThread *parentThread = m_thread.thread(); - - delete m_connection; - m_connection = nullptr; - - // Move it back to the parent thread so that we can potentially restart it on a new thread. - moveToThread(parentThread); -} - -QQmlDebugService *QQmlDebugServerImpl::service(const QString &name) const -{ - return m_plugins.value(name); -} - -void QQmlDebugServerImpl::addEngine(QJSEngine *engine) -{ - // to be executed outside of debugger thread - Q_ASSERT(QThread::currentThread() != &m_thread); - - QMutexLocker locker(&m_helloMutex); - Q_ASSERT(!m_engineConditions.contains(engine)); - - for (QQmlDebugService *service : qAsConst(m_plugins)) - service->engineAboutToBeAdded(engine); - - m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.count()); - - for (QQmlDebugService *service : qAsConst(m_plugins)) - service->engineAdded(engine); -} - -void QQmlDebugServerImpl::removeEngine(QJSEngine *engine) -{ - // to be executed outside of debugger thread - Q_ASSERT(QThread::currentThread() != &m_thread); - - QMutexLocker locker(&m_helloMutex); - Q_ASSERT(m_engineConditions.contains(engine)); - - for (QQmlDebugService *service : qAsConst(m_plugins)) - service->engineAboutToBeRemoved(engine); - - m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.count()); - - for (QQmlDebugService *service : qAsConst(m_plugins)) - service->engineRemoved(engine); - - m_engineConditions.remove(engine); -} - -bool QQmlDebugServerImpl::hasEngine(QJSEngine *engine) const -{ - QMutexLocker locker(&m_helloMutex); - QHash<QJSEngine *, EngineCondition>::ConstIterator i = m_engineConditions.constFind(engine); - // if we're still waiting the engine isn't fully "there", yet, nor fully removed. - return i != m_engineConditions.constEnd() && !i.value().isWaiting(); -} - -bool QQmlDebugServerImpl::addService(const QString &name, QQmlDebugService *service) -{ - // to be executed before thread starts - Q_ASSERT(!m_thread.isRunning()); - - if (!service || m_plugins.contains(name)) - return false; - - connect(service, &QQmlDebugService::messageToClient, - this, &QQmlDebugServerImpl::sendMessage); - connect(service, &QQmlDebugService::messagesToClient, - this, &QQmlDebugServerImpl::sendMessages); - - connect(service, &QQmlDebugService::attachedToEngine, - this, &QQmlDebugServerImpl::wakeEngine, Qt::QueuedConnection); - connect(service, &QQmlDebugService::detachedFromEngine, - this, &QQmlDebugServerImpl::wakeEngine, Qt::QueuedConnection); - - service->setState(QQmlDebugService::Unavailable); - m_plugins.insert(name, service); - - return true; -} - -bool QQmlDebugServerImpl::removeService(const QString &name) -{ - // to be executed after thread ends - Q_ASSERT(!m_thread.isRunning()); - - QQmlDebugService *service = m_plugins.value(name); - if (!service) - return false; - - m_plugins.remove(name); - service->setState(QQmlDebugService::NotConnected); - - disconnect(service, &QQmlDebugService::detachedFromEngine, - this, &QQmlDebugServerImpl::wakeEngine); - disconnect(service, &QQmlDebugService::attachedToEngine, - this, &QQmlDebugServerImpl::wakeEngine); - - disconnect(service, &QQmlDebugService::messagesToClient, - this, &QQmlDebugServerImpl::sendMessages); - disconnect(service, &QQmlDebugService::messageToClient, - this, &QQmlDebugServerImpl::sendMessage); - - return true; -} - -bool QQmlDebugServerImpl::canSendMessage(const QString &name) -{ - // to be executed in debugger thread - Q_ASSERT(QThread::currentThread() == thread()); - return m_connection && m_connection->isConnected() && m_protocol && - m_clientPlugins.contains(name); -} - -void QQmlDebugServerImpl::doSendMessage(const QString &name, const QByteArray &message) -{ - QQmlDebugPacket out; - out << name << message; - m_protocol->send(out.data()); -} - -void QQmlDebugServerImpl::sendMessage(const QString &name, const QByteArray &message) -{ - if (canSendMessage(name)) { - doSendMessage(name, message); - m_connection->flush(); - } -} - -void QQmlDebugServerImpl::sendMessages(const QString &name, const QList<QByteArray> &messages) -{ - if (canSendMessage(name)) { - QQmlDebugPacket out; - out << name; - for (const QByteArray &message : messages) - out << message; - m_protocol->send(out.data()); - m_connection->flush(); - } -} - -void QQmlDebugServerImpl::wakeEngine(QJSEngine *engine) -{ - // to be executed in debugger thread - Q_ASSERT(QThread::currentThread() == thread()); - - QMutexLocker locker(&m_helloMutex); - m_engineConditions[engine].wake(); -} - -bool QQmlDebugServerImpl::EngineCondition::waitForServices(QMutex *locked, int num) -{ - Q_ASSERT_X(numServices == 0, Q_FUNC_INFO, "Request to wait again before previous wait finished"); - numServices = num; - return numServices > 0 ? condition->wait(locked) : true; -} - -void QQmlDebugServerImpl::EngineCondition::wake() -{ - if (--numServices == 0) - condition->wakeAll(); - Q_ASSERT_X(numServices >=0, Q_FUNC_INFO, "Woken more often than #services."); -} - -void QQmlDebugServerImpl::setDevice(QIODevice *socket) -{ - m_protocol = new QPacketProtocol(socket, this); - QObject::connect(m_protocol, &QPacketProtocol::readyRead, - this, &QQmlDebugServerImpl::receiveMessage); - QObject::connect(m_protocol, &QPacketProtocol::error, - this, &QQmlDebugServerImpl::protocolError); - - if (blockingMode()) - m_protocol->waitForReadyRead(-1); -} - -void QQmlDebugServerImpl::protocolError() -{ - qWarning("QML Debugger: A protocol error has occurred! Giving up ..."); - m_connection->disconnect(); - // protocol might still be processing packages at this point - m_protocol->deleteLater(); - m_protocol = nullptr; -} - -QQmlDebugConnector *QQmlDebugServerFactory::create(const QString &key) -{ - // Cannot parent it to this because it gets moved to another thread - return (key == QLatin1String("QQmlDebugServer") ? new QQmlDebugServerImpl : nullptr); -} - -QT_END_NAMESPACE - -#include "qqmldebugserver.moc" |