aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKai Koehne <kai.koehne@nokia.com>2011-08-24 13:51:07 +0200
committerQt by Nokia <qt-info@nokia.com>2011-11-22 13:45:27 +0100
commit43e20d57011bbddd3beec773f6a8efb1269a8ead (patch)
treee07e5b858582e6d689a188073a82249687be4c0e /src
parent774eebf9978ac3bf68b124a9e88729cd21068433 (diff)
Debugger: Move server into it's own thread
So far the debugger infrastructure was running in the GUI thread, which required e.g. nested event loops to implement blocking behavior. The server and networking code are now running in their own thread, while the services are still running in the main thread. Because v8 isn't thread safe, we're adding two new JSEngines + isolates to qv8debugservice: One to decode JSON messages in the debugger thread, and one in the GUI thread. Change-Id: I746f5e203968f7bcc510fb66118c88ef0fd0cd14 Reviewed-by: Christiaan Janssen <christiaan.janssen@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/declarative/debugger/qdeclarativedebugserver.cpp228
-rw-r--r--src/declarative/debugger/qdeclarativedebugserver_p.h6
-rw-r--r--src/declarative/debugger/qdeclarativeenginedebugservice.cpp5
-rw-r--r--src/declarative/debugger/qdeclarativeenginedebugservice_p.h1
-rw-r--r--src/declarative/debugger/qdeclarativeinspectorservice.cpp5
-rw-r--r--src/declarative/debugger/qdeclarativeinspectorservice_p.h3
-rw-r--r--src/declarative/debugger/qv8debugservice.cpp135
-rw-r--r--src/declarative/debugger/qv8debugservice_p.h6
-rw-r--r--src/declarative/debugger/qv8profilerservice.cpp10
9 files changed, 253 insertions, 146 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") {