diff options
11 files changed, 276 insertions, 155 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; } diff --git a/src/declarative/debugger/qdeclarativedebugserver_p.h b/src/declarative/debugger/qdeclarativedebugserver_p.h index d80633cd7d..1333634446 100644 --- a/src/declarative/debugger/qdeclarativedebugserver_p.h +++ b/src/declarative/debugger/qdeclarativedebugserver_p.h @@ -80,19 +80,21 @@ public: QList<QDeclarativeDebugService*> services() const; QStringList serviceNames() const; + bool addService(QDeclarativeDebugService *service); bool removeService(QDeclarativeDebugService *service); - void sendMessage(QDeclarativeDebugService *service, const QByteArray &message); void receiveMessage(const QByteArray &message); bool waitForMessage(QDeclarativeDebugService *service); + void sendMessage(QDeclarativeDebugService *service, const QByteArray &message); private: friend class QDeclarativeDebugService; friend class QDeclarativeDebugServicePrivate; + friend class QDeclarativeDebugServerThread; QDeclarativeDebugServer(); - Q_PRIVATE_SLOT(d_func(), void _q_deliverMessage(QString, QByteArray)) + Q_PRIVATE_SLOT(d_func(), void _q_sendMessage(QByteArray)) }; QT_END_NAMESPACE diff --git a/src/declarative/debugger/qdeclarativeenginedebugservice.cpp b/src/declarative/debugger/qdeclarativeenginedebugservice.cpp index a1b02abe8e..ac188b0789 100644 --- a/src/declarative/debugger/qdeclarativeenginedebugservice.cpp +++ b/src/declarative/debugger/qdeclarativeenginedebugservice.cpp @@ -387,6 +387,11 @@ QDeclarativeEngineDebugService::objectData(QObject *object) void QDeclarativeEngineDebugService::messageReceived(const QByteArray &message) { + QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message)); +} + +void QDeclarativeEngineDebugService::processMessage(const QByteArray &message) +{ QDataStream ds(message); QByteArray type; diff --git a/src/declarative/debugger/qdeclarativeenginedebugservice_p.h b/src/declarative/debugger/qdeclarativeenginedebugservice_p.h index 3674b83fe7..d3e5c79297 100644 --- a/src/declarative/debugger/qdeclarativeenginedebugservice_p.h +++ b/src/declarative/debugger/qdeclarativeenginedebugservice_p.h @@ -104,6 +104,7 @@ protected: virtual void messageReceived(const QByteArray &); private Q_SLOTS: + void processMessage(const QByteArray &msg); void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value); private: diff --git a/src/declarative/debugger/qdeclarativeinspectorservice.cpp b/src/declarative/debugger/qdeclarativeinspectorservice.cpp index c3f90d2cab..90ab6ad6cb 100644 --- a/src/declarative/debugger/qdeclarativeinspectorservice.cpp +++ b/src/declarative/debugger/qdeclarativeinspectorservice.cpp @@ -133,6 +133,11 @@ void QDeclarativeInspectorService::updateStatus() void QDeclarativeInspectorService::messageReceived(const QByteArray &message) { + QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message)); +} + +void QDeclarativeInspectorService::processMessage(const QByteArray &message) +{ if (m_currentInspectorPlugin) m_currentInspectorPlugin->clientMessage(message); } diff --git a/src/declarative/debugger/qdeclarativeinspectorservice_p.h b/src/declarative/debugger/qdeclarativeinspectorservice_p.h index 9aa71ae953..6362f5b159 100644 --- a/src/declarative/debugger/qdeclarativeinspectorservice_p.h +++ b/src/declarative/debugger/qdeclarativeinspectorservice_p.h @@ -83,6 +83,9 @@ protected: virtual void statusChanged(Status status); virtual void messageReceived(const QByteArray &); +private slots: + void processMessage(const QByteArray &message); + private: void updateStatus(); void loadInspectorPlugins(); diff --git a/src/declarative/debugger/qv8debugservice.cpp b/src/declarative/debugger/qv8debugservice.cpp index 2f7ca348fd..f708f592b4 100644 --- a/src/declarative/debugger/qv8debugservice.cpp +++ b/src/declarative/debugger/qv8debugservice.cpp @@ -45,7 +45,6 @@ #include <private/qv8engine_p.h> #include <private/qdeclarativeengine_p.h> -#include <QtCore/QEventLoop> #include <QtCore/QHash> #include <QtCore/QFileInfo> @@ -72,12 +71,9 @@ void DebugMessageHandler(const v8::Debug::Message& message) message.GetJSON())); QV8DebugService *service = QV8DebugService::instance(); - service->debugMessageHandler(response); + service->debugMessageHandler(response, message.WillStartRunning()); - if ((event == v8::Break || event == v8::Exception) && - !message.WillStartRunning()) { - service->executionStopped(); - } else if (event == v8::AfterCompile) { + if (event == v8::AfterCompile) { service->appendSourcePath(response); } //TODO::v8::Exception } @@ -87,32 +83,41 @@ class QV8DebugServicePrivate : public QDeclarativeDebugServicePrivate public: QV8DebugServicePrivate() :initialized(false) + , scheduleBreak(false) + , debuggerThreadIsolate(0) + , debuggerThreadEngine(0) + , isRunning(true) { - //Create a new isolate - isolate = v8::Isolate::New(); - - //Enter the isolate and initialize - v8::Isolate::Scope i_scope(isolate); + //Create an isolate & engine in GUI thread + guiThreadIsolate = v8::Isolate::New(); + v8::Isolate::Scope i_scope(guiThreadIsolate); v8::V8::Initialize(); - - //Create an instance in the new isolate - engine = new QJSEngine(); + guiThreadEngine = new QJSEngine(); } ~QV8DebugServicePrivate() { - delete engine; - isolate->Dispose(); + delete debuggerThreadEngine; + if (debuggerThreadIsolate) + debuggerThreadIsolate->Dispose(); + delete guiThreadEngine; + if (guiThreadIsolate) + guiThreadIsolate->Dispose(); } void sendDebugMessage(const QString &message); static QByteArray packMessage(const QString &message); bool initialized; - QJSEngine *engine; - v8::Isolate *isolate; + bool scheduleBreak; + + v8::Isolate *debuggerThreadIsolate; + QJSEngine *debuggerThreadEngine; + v8::Isolate *guiThreadIsolate; + QJSEngine *guiThreadEngine; + QList<QDeclarativeEngine *> engines; - QEventLoop loop; + bool isRunning; QHash<QString, QString> sourcePath; QHash<QString, QString> requestCache; QHash<int, SignalHandlerData> handlersList; @@ -166,20 +171,18 @@ void QV8DebugService::removeEngine(QDeclarativeEngine *engine) d->engines.removeAll(engine); } -void QV8DebugService::debugMessageHandler(const QString &message) -{ - sendMessage(QV8DebugServicePrivate::packMessage(message)); -} - -void QV8DebugService::executionStopped() +void QV8DebugService::debugMessageHandler(const QString &message, bool willStartRunning) { Q_D(QV8DebugService); + d->isRunning = willStartRunning; - if (!d->loop.isRunning()) { - d->loop.exec(QEventLoop::ExcludeUserInputEvents); - } + if (d->scheduleBreak) + scheduledDebugBreak(); + + sendMessage(QV8DebugServicePrivate::packMessage(message)); } + void QV8DebugService::appendSourcePath(const QString &message) { Q_D(QV8DebugService); @@ -189,8 +192,8 @@ void QV8DebugService::appendSourcePath(const QString &message) This will ensure that the debug message handler does not receive any messages related to this operation */ { - v8::Isolate::Scope i_scope(d->isolate); - QJSValue parser = d->engine->evaluate(QLatin1String("JSON.parse")); + v8::Isolate::Scope scope(d->guiThreadIsolate); + QJSValue parser = d->guiThreadEngine->evaluate(QLatin1String("JSON.parse")); QJSValue out = parser.call(QJSValue(), QJSValueList() << QJSValue(message)); msgMap = out.toVariant().toMap(); } @@ -220,18 +223,26 @@ void QV8DebugService::signalEmitted(const QString &signal) //is no need for additional check. Q_D(QV8DebugService); - bool debugBreak = false; //Parse just the name and remove the class info //Normalize to Lower case. QString signalName = signal.left(signal.indexOf(QLatin1String("("))).toLower(); foreach (const SignalHandlerData &data, d->handlersList) { if (data.functionName == signalName && data.enabled) { - debugBreak = true; + d->scheduleBreak = true; } } - if (debugBreak) + if (d->scheduleBreak) + scheduledDebugBreak(); +} + +void QV8DebugService::scheduledDebugBreak() +{ + Q_D(QV8DebugService); + if (d->scheduleBreak) { v8::Debug::DebugBreak(); + d->scheduleBreak = false; + } } void QV8DebugService::messageReceived(const QByteArray &message) @@ -243,6 +254,16 @@ void QV8DebugService::messageReceived(const QByteArray &message) ds >> command; if (command == "V8DEBUG") { + + if (!d->debuggerThreadEngine) { + //Create an isolate & engine in debugger thread + d->debuggerThreadIsolate = v8::Isolate::New(); + v8::Isolate::Scope i_scope(d->debuggerThreadIsolate); + v8::V8::Initialize(); + d->debuggerThreadEngine = new QJSEngine(); + } + + QString request; { QByteArray requestArray; @@ -251,12 +272,9 @@ void QV8DebugService::messageReceived(const QByteArray &message) } QVariantMap reqMap; - /* Parse the byte string in a separate isolate - This will ensure that the debug message handler does not - receive any messages related to this operation */ { - v8::Isolate::Scope i_scope(d->isolate); - QJSValue parser = d->engine->evaluate(QLatin1String("JSON.parse")); + v8::Isolate::Scope i_scope(d->debuggerThreadIsolate); + QJSValue parser = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.parse")); QJSValue out = parser.call(QJSValue(), QJSValueList() << QJSValue(request)); reqMap = out.toVariant().toMap(); } @@ -276,9 +294,9 @@ void QV8DebugService::messageReceived(const QByteArray &message) // "success" : true // } { - v8::Isolate::Scope i_scope(d->isolate); const QString obj(QLatin1String("{}")); - QJSValue parser = d->engine->evaluate(QLatin1String("JSON.parse")); + v8::Isolate::Scope i_scope(d->debuggerThreadIsolate); + QJSValue parser = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.parse")); QJSValue jsonVal = parser.call(QJSValue(), QJSValueList() << obj); jsonVal.setProperty(QLatin1String("type"), QJSValue(QLatin1String("response"))); @@ -286,16 +304,14 @@ void QV8DebugService::messageReceived(const QByteArray &message) jsonVal.setProperty(QLatin1String("request_seq"), QJSValue(sequence)); jsonVal.setProperty(QLatin1String("command"), QJSValue(debugCommand)); jsonVal.setProperty(QLatin1String("success"), QJSValue(true)); - jsonVal.setProperty(QLatin1String("running"), QJSValue(!d->loop.isRunning())); + jsonVal.setProperty(QLatin1String("running"), QJSValue(d->isRunning)); - QJSValue stringify = d->engine->evaluate(QLatin1String("JSON.stringify")); + QJSValue stringify = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.stringify")); QJSValue json = stringify.call(QJSValue(), QJSValueList() << jsonVal); - debugMessageHandler(json.toString()); - + sendMessage(QV8DebugServicePrivate::packMessage(json.toString())); } } else if (debugCommand == QLatin1String("interrupt")) { - v8::Debug::DebugBreak(); //Prepare the response string //Create a json message using v8 debugging protocol //and send it to client @@ -307,9 +323,9 @@ void QV8DebugService::messageReceived(const QByteArray &message) // "success" : true // } { - v8::Isolate::Scope i_scope(d->isolate); const QString obj(QLatin1String("{}")); - QJSValue parser = d->engine->evaluate(QLatin1String("JSON.parse")); + v8::Isolate::Scope i_scope(d->debuggerThreadIsolate); + QJSValue parser = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.parse")); QJSValue jsonVal = parser.call(QJSValue(), QJSValueList() << obj); jsonVal.setProperty(QLatin1String("type"), QJSValue(QLatin1String("response"))); @@ -317,14 +333,15 @@ void QV8DebugService::messageReceived(const QByteArray &message) jsonVal.setProperty(QLatin1String("request_seq"), QJSValue(sequence)); jsonVal.setProperty(QLatin1String("command"), QJSValue(debugCommand)); jsonVal.setProperty(QLatin1String("success"), QJSValue(true)); - jsonVal.setProperty(QLatin1String("running"), QJSValue(!d->loop.isRunning())); + jsonVal.setProperty(QLatin1String("running"), QJSValue(d->isRunning)); - QJSValue stringify = d->engine->evaluate(QLatin1String("JSON.stringify")); + QJSValue stringify = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.stringify")); QJSValue json = stringify.call(QJSValue(), QJSValueList() << jsonVal); - debugMessageHandler(json.toString()); - + sendMessage(QV8DebugServicePrivate::packMessage(json.toString())); } - + // break has to be executed in gui thread + d->scheduleBreak = true; + QMetaObject::invokeMethod(this, "scheduledDebugBreak", Qt::QueuedConnection); } else { bool forwardRequestToV8 = true; @@ -363,9 +380,9 @@ void QV8DebugService::messageReceived(const QByteArray &message) // "success" : true // } { - v8::Isolate::Scope i_scope(d->isolate); const QString obj(QLatin1String("{}")); - QJSValue parser = d->engine->evaluate(QLatin1String("JSON.parse")); + v8::Isolate::Scope i_scope(d->debuggerThreadIsolate); + QJSValue parser = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.parse")); QJSValue jsonVal = parser.call(QJSValue(), QJSValueList() << obj); jsonVal.setProperty(QLatin1String("type"), QJSValue(QLatin1String("response"))); @@ -398,12 +415,11 @@ void QV8DebugService::messageReceived(const QByteArray &message) } - jsonVal.setProperty(QLatin1String("running"), QJSValue(!d->loop.isRunning())); + jsonVal.setProperty(QLatin1String("running"), QJSValue(d->isRunning)); - QJSValue stringify = d->engine->evaluate(QLatin1String("JSON.stringify")); + QJSValue stringify = d->debuggerThreadEngine->evaluate(QLatin1String("JSON.stringify")); QJSValue json = stringify.call(QJSValue(), QJSValueList() << jsonVal); - debugMessageHandler(json.toString()); - + sendMessage(QV8DebugServicePrivate::packMessage(json.toString())); } } } else if (debugCommand == QLatin1String("changebreakpoint")) { @@ -440,9 +456,6 @@ void QV8DebugService::messageReceived(const QByteArray &message) void QV8DebugServicePrivate::sendDebugMessage(const QString &message) { - if (loop.isRunning()) - loop.exit(); - v8::Debug::SendCommand(message.utf16(), message.size()); } diff --git a/src/declarative/debugger/qv8debugservice_p.h b/src/declarative/debugger/qv8debugservice_p.h index d8101ae3ff..9785bb9849 100644 --- a/src/declarative/debugger/qv8debugservice_p.h +++ b/src/declarative/debugger/qv8debugservice_p.h @@ -76,13 +76,15 @@ public: void addEngine(QDeclarativeEngine *); void removeEngine(QDeclarativeEngine *); - void debugMessageHandler(const QString &message); - void executionStopped(); + void debugMessageHandler(const QString &message, bool willStartRunning); void appendSourcePath(const QString &message); void signalEmitted(const QString &signal); +private slots: + void scheduledDebugBreak(); + protected: void messageReceived(const QByteArray &); diff --git a/src/declarative/debugger/qv8profilerservice.cpp b/src/declarative/debugger/qv8profilerservice.cpp index 48d2d1365d..807fe83b45 100644 --- a/src/declarative/debugger/qv8profilerservice.cpp +++ b/src/declarative/debugger/qv8profilerservice.cpp @@ -84,6 +84,7 @@ class QV8ProfilerServicePrivate : public QDeclarativeDebugServicePrivate public: QV8ProfilerServicePrivate() :initialized(false) + , isolate(0) { } @@ -96,6 +97,7 @@ public: bool initialized; QList<QDeclarativeEngine *> engines; + v8::Isolate *isolate; }; QV8ProfilerService::QV8ProfilerService(QObject *parent) @@ -146,6 +148,14 @@ void QV8ProfilerService::messageReceived(const QByteArray &message) QByteArray title; ds >> command >> option; + if (!d->isolate) { + d->isolate = v8::Isolate::New(); + v8::Isolate::Scope scope(d->isolate); + v8::V8::Initialize(); + } + + v8::Isolate::Scope scope(d->isolate); + if (command == "V8PROFILER") { ds >> title; if (option == "start") { diff --git a/tests/auto/declarative/debugger/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp b/tests/auto/declarative/debugger/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp index 82e25598e9..46a711ae78 100644 --- a/tests/auto/declarative/debugger/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp +++ b/tests/auto/declarative/debugger/qdeclarativedebugclient/tst_qdeclarativedebugclient.cpp @@ -80,11 +80,16 @@ void tst_QDeclarativeDebugClient::initTestCase() QDeclarativeDebugTestClient client("tst_QDeclarativeDebugClient::handshake()", m_conn); QDeclarativeDebugTestService service("tst_QDeclarativeDebugClient::handshake()"); - m_conn->connectToHost("127.0.0.1", PORT); - QTest::ignoreMessage(QtWarningMsg, "QDeclarativeDebugServer: Connection established"); - bool ok = m_conn->waitForConnected(); - QVERIFY(ok); + for (int i = 0; i < 50; ++i) { + // try for 5 seconds ... + m_conn->connectToHost("127.0.0.1", PORT); + if (m_conn->waitForConnected()) + break; + QTest::qSleep(100); + } + + QVERIFY(m_conn->isConnected()); QTRY_VERIFY(QDeclarativeDebugService::hasDebuggingClient()); QTRY_COMPARE(client.status(), QDeclarativeDebugClient::Enabled); diff --git a/tests/auto/declarative/debugger/qdeclarativedebugservice/tst_qdeclarativedebugservice.cpp b/tests/auto/declarative/debugger/qdeclarativedebugservice/tst_qdeclarativedebugservice.cpp index 8f829a6468..6063c1fdcb 100644 --- a/tests/auto/declarative/debugger/qdeclarativedebugservice/tst_qdeclarativedebugservice.cpp +++ b/tests/auto/declarative/debugger/qdeclarativedebugservice/tst_qdeclarativedebugservice.cpp @@ -53,6 +53,8 @@ #include "../../shared/util.h" #include "../shared/debugutil_p.h" +#define PORT 13769 +#define STR_PORT "13769" class tst_QDeclarativeDebugService : public QObject { @@ -73,15 +75,22 @@ private slots: void tst_QDeclarativeDebugService::initTestCase() { - QTest::ignoreMessage(QtWarningMsg, "QDeclarativeDebugServer: Waiting for connection on port 13769..."); + const QString waitingMsg = QString("QDeclarativeDebugServer: Waiting for connection on port %1...").arg(PORT); + QTest::ignoreMessage(QtWarningMsg, waitingMsg.toAscii().constData()); new QDeclarativeEngine(this); m_conn = new QDeclarativeDebugConnection(this); - m_conn->connectToHost("127.0.0.1", 13769); + QTest::ignoreMessage(QtWarningMsg, "QDeclarativeDebugServer: Connection established"); - bool ok = m_conn->waitForConnected(); - QVERIFY(ok); + for (int i = 0; i < 50; ++i) { + // try for 5 seconds ... + m_conn->connectToHost("127.0.0.1", PORT); + if (m_conn->waitForConnected()) + break; + QTest::qSleep(100); + } + QVERIFY(m_conn->isConnected()); QTRY_VERIFY(QDeclarativeDebugService::hasDebuggingClient()); } @@ -187,7 +196,7 @@ int main(int argc, char *argv[]) char **_argv = new char*[_argc]; for (int i = 0; i < argc; ++i) _argv[i] = argv[i]; - char arg[] = "-qmljsdebugger=port:13769"; + char arg[] = "-qmljsdebugger=port:" STR_PORT; _argv[_argc - 1] = arg; QGuiApplication app(_argc, _argv); |