diff options
Diffstat (limited to 'src/declarative/debugger/qdeclarativedebugserver.cpp')
-rw-r--r-- | src/declarative/debugger/qdeclarativedebugserver.cpp | 228 |
1 files changed, 147 insertions, 81 deletions
diff --git a/src/declarative/debugger/qdeclarativedebugserver.cpp b/src/declarative/debugger/qdeclarativedebugserver.cpp index 5c86c45116..b8963d24f3 100644 --- a/src/declarative/debugger/qdeclarativedebugserver.cpp +++ b/src/declarative/debugger/qdeclarativedebugserver.cpp @@ -47,6 +47,7 @@ #include <QtCore/QDir> #include <QtCore/QPluginLoader> #include <QtCore/QStringList> +#include <QtCore/qwaitcondition.h> #include <private/qobject_p.h> #include <private/qcoreapplication_p.h> @@ -80,6 +81,8 @@ const int protocolVersion = 1; // print detailed information about loading of plugins DEFINE_BOOL_CONFIG_OPTION(qmlDebugVerbose, QML_DEBUGGER_VERBOSE) +class QDeclarativeDebugServerThread; + class QDeclarativeDebugServerPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QDeclarativeDebugServer) @@ -87,30 +90,56 @@ public: QDeclarativeDebugServerPrivate(); void advertisePlugins(); + QDeclarativeDebugServerConnection *loadConnectionPlugin(const QString &pluginName); QDeclarativeDebugServerConnection *connection; QHash<QString, QDeclarativeDebugService *> plugins; + mutable QReadWriteLock pluginsLock; QStringList clientPlugins; bool gotHello; - QString waitingForMsgFromService; - bool waitingForMsgSucceeded; + + QMutex messageArrivedMutex; + QWaitCondition messageArrivedCondition; + QStringList waitingForMessageNames; + QDeclarativeDebugServerThread *thread; + QPluginLoader loader; private: // private slot - void _q_deliverMessage(const QString &serviceName, const QByteArray &message); - static QDeclarativeDebugServerConnection *loadConnectionPlugin(QPluginLoader *loader, const QString &pluginName); + void _q_sendMessage(const QByteArray &message); +}; +class QDeclarativeDebugServerThread : public QThread +{ +public: + void setPluginName(const QString &pluginName) { + m_pluginName = pluginName; + } + + void setPort(int port, bool block) { + m_port = port; + m_block = block; + } + + void run(); + +private: + QString m_pluginName; + int m_port; + bool m_block; }; QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate() : connection(0), gotHello(false), - waitingForMsgSucceeded(false) + thread(0) { } void QDeclarativeDebugServerPrivate::advertisePlugins() { + Q_Q(QDeclarativeDebugServer); + if (!gotHello) return; @@ -119,11 +148,12 @@ void QDeclarativeDebugServerPrivate::advertisePlugins() QDataStream out(&message, QIODevice::WriteOnly); out << QString(QLatin1String("QDeclarativeDebugClient")) << 1 << plugins.keys(); } - connection->send(message); + + QMetaObject::invokeMethod(q, "_q_sendMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message)); } QDeclarativeDebugServerConnection *QDeclarativeDebugServerPrivate::loadConnectionPlugin( - QPluginLoader *loader, const QString &pluginName) + const QString &pluginName) { #ifndef QT_NO_LIBRARY QStringList pluginCandidates; @@ -143,14 +173,13 @@ QDeclarativeDebugServerConnection *QDeclarativeDebugServerPrivate::loadConnectio if (qmlDebugVerbose()) qDebug() << "QDeclarativeDebugServer: Trying to load plugin " << pluginPath << "..."; - loader->setFileName(pluginPath); - if (!loader->load()) { + loader.setFileName(pluginPath); + if (!loader.load()) { if (qmlDebugVerbose()) - qDebug() << "QDeclarativeDebugServer: Error while loading: " << loader->errorString(); + qDebug() << "QDeclarativeDebugServer: Error while loading: " << loader.errorString(); continue; } - QDeclarativeDebugServerConnection *connection = 0; - if (QObject *instance = loader->instance()) + if (QObject *instance = loader.instance()) connection = qobject_cast<QDeclarativeDebugServerConnection*>(instance); if (connection) { @@ -163,12 +192,29 @@ QDeclarativeDebugServerConnection *QDeclarativeDebugServerPrivate::loadConnectio if (qmlDebugVerbose()) qDebug() << "QDeclarativeDebugServer: Plugin does not implement interface QDeclarativeDebugServerConnection."; - loader->unload(); + loader.unload(); } #endif return 0; } +void QDeclarativeDebugServerThread::run() +{ + QDeclarativeDebugServer *server = QDeclarativeDebugServer::instance(); + QDeclarativeDebugServerConnection *connection + = server->d_func()->loadConnectionPlugin(m_pluginName); + if (connection) { + connection->setServer(QDeclarativeDebugServer::instance()); + connection->setPort(m_port, m_block); + } else { + QCoreApplicationPrivate *appD = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp)); + qWarning() << QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". " + "Remote debugger plugin has not been found.").arg(appD->qmljsDebugArgumentsString()); + } + + exec(); +} + bool QDeclarativeDebugServer::hasDebuggingClient() const { Q_D(const QDeclarativeDebugServer); @@ -177,10 +223,11 @@ bool QDeclarativeDebugServer::hasDebuggingClient() const && d->gotHello; } +static QDeclarativeDebugServer *qDeclarativeDebugServer = 0; + QDeclarativeDebugServer *QDeclarativeDebugServer::instance() { static bool commandLineTested = false; - static QDeclarativeDebugServer *server = 0; if (!commandLineTested) { commandLineTested = true; @@ -215,20 +262,22 @@ QDeclarativeDebugServer *QDeclarativeDebugServer::instance() block = appD->qmljsDebugArgumentsString().contains(QLatin1String("block")); if (ok) { - server = new QDeclarativeDebugServer(); - QPluginLoader *loader = new QPluginLoader(server); - QDeclarativeDebugServerConnection *connection - = QDeclarativeDebugServerPrivate::loadConnectionPlugin(loader, pluginName); - if (connection) { - server->d_func()->connection = connection; - - connection->setServer(server); - connection->setPort(port, block); - } else { - qWarning() << QString::fromLatin1( - "QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". " - "Remote debugger plugin has not been found.").arg( - appD->qmljsDebugArgumentsString()); + qDeclarativeDebugServer = new QDeclarativeDebugServer(); + + QDeclarativeDebugServerThread *thread = new QDeclarativeDebugServerThread; + + qDeclarativeDebugServer = new QDeclarativeDebugServer(); + qDeclarativeDebugServer->d_func()->thread = thread; + qDeclarativeDebugServer->moveToThread(thread); + thread->setPluginName(pluginName); + thread->setPort(port, block); + thread->start(); + + if (block) { + QDeclarativeDebugServerPrivate *d = qDeclarativeDebugServer->d_func(); + d->messageArrivedMutex.lock(); + d->messageArrivedCondition.wait(&d->messageArrivedMutex); + d->messageArrivedMutex.unlock(); } } else { @@ -248,7 +297,7 @@ QDeclarativeDebugServer *QDeclarativeDebugServer::instance() #endif } - return server; + return qDeclarativeDebugServer; } QDeclarativeDebugServer::QDeclarativeDebugServer() @@ -261,6 +310,7 @@ void QDeclarativeDebugServer::receiveMessage(const QByteArray &message) Q_D(QDeclarativeDebugServer); QDataStream in(message); + QString name; in >> name; @@ -282,8 +332,9 @@ void QDeclarativeDebugServer::receiveMessage(const QByteArray &message) d->gotHello = true; - QHash<QString, QDeclarativeDebugService*>::Iterator iter = d->plugins.begin(); - for (; iter != d->plugins.end(); ++iter) { + QReadLocker(&d->pluginsLock); + QHash<QString, QDeclarativeDebugService*>::ConstIterator iter = d->plugins.constBegin(); + for (; iter != d->plugins.constEnd(); ++iter) { QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable; if (d->clientPlugins.contains(iter.key())) newStatus = QDeclarativeDebugService::Enabled; @@ -292,6 +343,7 @@ void QDeclarativeDebugServer::receiveMessage(const QByteArray &message) } qWarning("QDeclarativeDebugServer: Connection established"); + d->messageArrivedCondition.wakeAll(); } else if (op == 1) { @@ -299,8 +351,9 @@ void QDeclarativeDebugServer::receiveMessage(const QByteArray &message) QStringList oldClientPlugins = d->clientPlugins; in >> d->clientPlugins; - QHash<QString, QDeclarativeDebugService*>::Iterator iter = d->plugins.begin(); - for (; iter != d->plugins.end(); ++iter) { + QReadLocker(&d->pluginsLock); + QHash<QString, QDeclarativeDebugService*>::ConstIterator iter = d->plugins.constBegin(); + for (; iter != d->plugins.constEnd(); ++iter) { const QString pluginName = iter.key(); QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable; if (d->clientPlugins.contains(pluginName)) @@ -324,18 +377,15 @@ void QDeclarativeDebugServer::receiveMessage(const QByteArray &message) QByteArray message; in >> message; - if (d->waitingForMsgFromService == name) { - // deliver directly so that it is delivered before waitForMessage is returning. - d->_q_deliverMessage(name, message); - d->waitingForMsgSucceeded = true; + QReadLocker(&d->pluginsLock); + QHash<QString, QDeclarativeDebugService *>::Iterator iter = d->plugins.find(name); + if (iter == d->plugins.end()) { + qWarning() << "QDeclarativeDebugServer: Message received for missing plugin" << name; } else { - // deliver message in next event loop run. - // Fixes the case that the service does start it's own event loop ..., - // but the networking code doesn't deliver any new messages because readyRead - // hasn't returned. - QMetaObject::invokeMethod(this, "_q_deliverMessage", Qt::QueuedConnection, - Q_ARG(QString, name), - Q_ARG(QByteArray, message)); + (*iter)->messageReceived(message); + + if (d->waitingForMessageNames.removeOne(name)) + d->messageArrivedCondition.wakeAll(); } } else { qWarning("QDeclarativeDebugServer: Invalid hello message"); @@ -344,89 +394,105 @@ void QDeclarativeDebugServer::receiveMessage(const QByteArray &message) } } -void QDeclarativeDebugServerPrivate::_q_deliverMessage(const QString &serviceName, const QByteArray &message) +void QDeclarativeDebugServerPrivate::_q_sendMessage(const QByteArray &message) { - QHash<QString, QDeclarativeDebugService *>::Iterator iter = plugins.find(serviceName); - if (iter == plugins.end()) { - qWarning() << "QDeclarativeDebugServer: Message received for missing plugin" << serviceName; - } else { - (*iter)->messageReceived(message); - } + if (connection) + connection->send(message); } QList<QDeclarativeDebugService*> QDeclarativeDebugServer::services() const { const Q_D(QDeclarativeDebugServer); + QReadLocker(&d->pluginsLock); return d->plugins.values(); } QStringList QDeclarativeDebugServer::serviceNames() const { const Q_D(QDeclarativeDebugServer); + QReadLocker(&d->pluginsLock); return d->plugins.keys(); } bool QDeclarativeDebugServer::addService(QDeclarativeDebugService *service) { Q_D(QDeclarativeDebugServer); - if (!service || d->plugins.contains(service->name())) - return false; - - d->plugins.insert(service->name(), service); - d->advertisePlugins(); - - QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable; - if (d->clientPlugins.contains(service->name())) - newStatus = QDeclarativeDebugService::Enabled; - service->d_func()->status = newStatus; - service->statusChanged(newStatus); + { + QWriteLocker(&d->pluginsLock); + if (!service || d->plugins.contains(service->name())) + return false; + d->plugins.insert(service->name(), service); + } + { + QReadLocker(&d->pluginsLock); + d->advertisePlugins(); + QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable; + if (d->clientPlugins.contains(service->name())) + newStatus = QDeclarativeDebugService::Enabled; + service->d_func()->status = newStatus; + } return true; } bool QDeclarativeDebugServer::removeService(QDeclarativeDebugService *service) { Q_D(QDeclarativeDebugServer); - if (!service || !d->plugins.contains(service->name())) - return false; - - d->plugins.remove(service->name()); - d->advertisePlugins(); + { + QWriteLocker(&d->pluginsLock); + if (!service || !d->plugins.contains(service->name())) + return false; + d->plugins.remove(service->name()); + } + { + QReadLocker(&d->pluginsLock); + d->advertisePlugins(); + QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::NotConnected; + service->d_func()->server = 0; + service->d_func()->status = newStatus; + service->statusChanged(newStatus); + + // Last service? Then stop thread & delete instance + if (d->plugins.isEmpty()) { + d->thread->exit(); + d->thread->wait(); + delete d->thread; + delete d->connection; + + qDeclarativeDebugServer = 0; + deleteLater(); + } + } - QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::NotConnected; - service->d_func()->server = 0; - service->d_func()->status = newStatus; - service->statusChanged(newStatus); return true; } void QDeclarativeDebugServer::sendMessage(QDeclarativeDebugService *service, const QByteArray &message) { - Q_D(QDeclarativeDebugServer); QByteArray msg; { QDataStream out(&msg, QIODevice::WriteOnly); out << service->name() << message; } - d->connection->send(msg); + + QMetaObject::invokeMethod(this, "_q_sendMessage", Qt::QueuedConnection, Q_ARG(QByteArray, msg)); } bool QDeclarativeDebugServer::waitForMessage(QDeclarativeDebugService *service) { Q_D(QDeclarativeDebugServer); + QReadLocker(&d->pluginsLock); if (!service - || !d->plugins.contains(service->name()) - || !d->waitingForMsgFromService.isEmpty()) + || !d->plugins.contains(service->name())) return false; - d->waitingForMsgSucceeded = false; - d->waitingForMsgFromService = service->name(); - + d->messageArrivedMutex.lock(); + d->waitingForMessageNames << service->name(); do { - d->connection->waitForMessage(); - } while (!d->waitingForMsgSucceeded); - d->waitingForMsgFromService.clear(); + d->messageArrivedCondition.wait(&d->messageArrivedMutex); + } while (d->waitingForMessageNames.contains(service->name())); + d->messageArrivedMutex.unlock(); return true; } |