#include "qqmldebugservice_p_p.h"
#include <QDataStream>
+#include <QMutex>
QT_BEGIN_NAMESPACE
QMessageHandler oldMsgHandler;
QQmlDebugService::State prevState;
+ QMutex initMutex;
};
QDebugMessageService::QDebugMessageService(QObject *parent) :
{
Q_D(QDebugMessageService);
+ // don't execute stateChanged() in parallel
+ QMutexLocker lock(&d->initMutex);
registerService();
if (state() == Enabled) {
d->oldMsgHandler = qInstallMessageHandler(DebugMessageHandler);
void QDebugMessageService::stateChanged(State state)
{
Q_D(QDebugMessageService);
+ QMutexLocker lock(&d->initMutex);
if (state != Enabled && d->prevState == Enabled) {
QMessageHandler handler = qInstallMessageHandler(d->oldMsgHandler);
} else if (state == Enabled && d->prevState != Enabled) {
d->oldMsgHandler = qInstallMessageHandler(DebugMessageHandler);
-
}
d->prevState = state;
mutable QReadWriteLock pluginsLock;
QStringList clientPlugins;
bool gotHello;
+ bool blockingMode;
QMutex messageArrivedMutex;
QWaitCondition messageArrivedCondition;
QQmlDebugServerPrivate::QQmlDebugServerPrivate() :
connection(0),
gotHello(false),
+ blockingMode(false),
thread(0)
{
// used in _q_sendMessages
&& d->gotHello;
}
+bool QQmlDebugServer::blockingMode() const
+{
+ Q_D(const QQmlDebugServer);
+ return d->blockingMode;
+}
+
static QQmlDebugServer *qQmlDebugServer = 0;
thread->setPort(port, block, hostAddress);
QQmlDebugServerPrivate *d = qQmlDebugServer->d_func();
+ d->blockingMode = block;
+
QMutexLocker locker(&d->messageArrivedMutex);
thread->start();
- if (block)
+ if (d->blockingMode)
d->messageArrivedCondition.wait(&d->messageArrivedMutex);
} else {
Q_ARG(QList<QByteArray>, prefixedMessages));
}
-bool QQmlDebugServer::waitForMessage(QQmlDebugService *service)
-{
- // to be executed in GUI thread
- Q_ASSERT(QThread::currentThread() == QCoreApplication::instance()->thread());
-
- Q_D(QQmlDebugServer);
- QReadLocker lock(&d->pluginsLock);
-
- if (!service
- || !d->plugins.contains(service->name()))
- return false;
-
- d->messageArrivedMutex.lock();
- d->waitingForMessageNames << service->name();
- do {
- d->messageArrivedCondition.wait(&d->messageArrivedMutex);
- } while (d->waitingForMessageNames.contains(service->name()));
- d->messageArrivedMutex.unlock();
- return true;
-}
-
QT_END_NAMESPACE
#include "moc_qqmldebugserver_p.cpp"
void setConnection(QQmlDebugServerConnection *connection);
bool hasDebuggingClient() const;
+ bool blockingMode() const;
QList<QQmlDebugService*> services() const;
QStringList serviceNames() const;
void receiveMessage(const QByteArray &message);
- bool waitForMessage(QQmlDebugService *service);
void sendMessages(QQmlDebugService *service, const QList<QByteArray> &messages);
private:
&& QQmlDebugServer::instance()->hasDebuggingClient();
}
+bool QQmlDebugService::blockingMode()
+{
+ return QQmlDebugServer::instance() != 0
+ && QQmlDebugServer::instance()->blockingMode();
+}
+
QString QQmlDebugService::objectToString(QObject *obj)
{
if(!obj)
d->server->sendMessages(this, messages);
}
-bool QQmlDebugService::waitForMessage()
-{
- Q_D(QQmlDebugService);
-
- if (state() != Enabled)
- return false;
-
- return d->server->waitForMessage(this);
-}
-
void QQmlDebugService::stateAboutToBeChanged(State)
{
}
void sendMessage(const QByteArray &);
void sendMessages(const QList<QByteArray> &);
- bool waitForMessage();
static int idForObject(QObject *);
static QObject *objectForId(int);
static bool isDebuggingEnabled();
static bool hasDebuggingClient();
+ static bool blockingMode();
protected:
QQmlDebugService(QQmlDebugServicePrivate &dd, const QString &name, float version, QObject *parent = 0);
QQmlProfilerService::QQmlProfilerService()
: QQmlDebugService(QStringLiteral("CanvasFrameRate"), 1),
- m_enabled(false), m_messageReceived(false)
+ m_enabled(false)
{
m_timer.start();
- if (registerService() == Enabled) {
- // wait for first message indicating whether to trace or not
- while (!m_messageReceived)
- waitForMessage();
+ // don't execute stateAboutToBeChanged(), messageReceived() in parallel
+ QMutexLocker lock(&m_initializeMutex);
- QUnifiedTimer::instance()->registerProfilerCallback( &animationFrame );
+ if (registerService() == Enabled) {
+ QUnifiedTimer::instance()->registerProfilerCallback(&animationFrame);
+ if (blockingMode())
+ m_initializeCondition.wait(&m_initializeMutex);
}
}
*/
void QQmlProfilerService::processMessage(const QQmlProfilerData &message)
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_dataMutex);
m_data.append(message);
}
*/
void QQmlProfilerService::sendMessages()
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_dataMutex);
QList<QByteArray> messages;
for (int i = 0; i < m_data.count(); ++i)
messages << m_data.at(i).toByteArray();
void QQmlProfilerService::stateAboutToBeChanged(QQmlDebugService::State newState)
{
+ QMutexLocker lock(&m_initializeMutex);
+
if (state() == newState)
return;
stopProfilingImpl();
sendMessages();
}
+
+ if (state() != Enabled) {
+ // wake up constructor in blocking mode
+ // (we might got disabled before first message arrived)
+ m_initializeCondition.wakeAll();
+ }
}
void QQmlProfilerService::messageReceived(const QByteArray &message)
{
+ QMutexLocker lock(&m_initializeMutex);
+
QByteArray rwData = message;
QDataStream stream(&rwData, QIODevice::ReadOnly);
bool enabled;
stream >> enabled;
- m_messageReceived = true;
-
if (enabled) {
startProfilingImpl();
} else {
if (stopProfilingImpl())
sendMessages();
}
+
+ // wake up constructor in blocking mode
+ m_initializeCondition.wakeAll();
}
QT_END_NAMESPACE
#include <QtCore/qmutex.h>
#include <QtCore/qvector.h>
#include <QtCore/qstringbuilder.h>
+#include <QtCore/qwaitcondition.h>
QT_BEGIN_HEADER
private:
QElapsedTimer m_timer;
bool m_enabled;
- bool m_messageReceived;
QVector<QQmlProfilerData> m_data;
- QMutex m_mutex;
+ QMutex m_dataMutex;
+ QMutex m_initializeMutex;
+ QWaitCondition m_initializeCondition;
static QQmlProfilerService *instance;
#include <QtCore/QHash>
#include <QtCore/QFileInfo>
#include <QtCore/QMutex>
+#include <QtCore/QWaitCondition>
//V8 DEBUG SERVICE PROTOCOL
// <HEADER><COMMAND><DATA>
{
public:
QV8DebugServicePrivate()
- : connectReceived(false)
- , engine(0)
+ : engine(0)
{
}
static QByteArray packMessage(const QString &type, const QString &message = QString());
- bool connectReceived;
QMutex initializeMutex;
+ QWaitCondition initializeCondition;
QStringList breakOnSignals;
const QV8Engine *engine;
};
{
Q_D(QV8DebugService);
v8ServiceInstancePtr = this;
- // wait for stateChanged() -> initialize()
- d->initializeMutex.lock();
+ // don't execute stateChanged, messageReceived in parallel
+ QMutexLocker lock(&d->initializeMutex);
+
if (registerService() == Enabled) {
init();
- // ,block mode, client attached
- while (!d->connectReceived) {
- waitForMessage();
- }
- } else {
- d->initializeMutex.unlock();
+ if (blockingMode())
+ d->initializeCondition.wait(&d->initializeMutex);
}
}
// executed in the gui thread
void QV8DebugService::init()
{
- Q_D(QV8DebugService);
v8::Debug::SetMessageHandler2(DebugMessageHandler);
v8::Debug::SetDebugMessageDispatchHandler(DebugMessageDispatchHandler);
QV4Compiler::enableV4(false);
- d->initializeMutex.unlock();
}
// executed in the gui thread
void QV8DebugService::stateChanged(QQmlDebugService::State newState)
{
Q_D(QV8DebugService);
+ QMutexLocker lock(&d->initializeMutex);
+
if (newState == Enabled) {
- // execute in GUI thread
- d->initializeMutex.lock();
- QMetaObject::invokeMethod(this, "init", Qt::QueuedConnection);
+ // execute in GUI thread, bock to make sure messageReceived isn't called
+ // before it finished.
+ QMetaObject::invokeMethod(this, "init", Qt::BlockingQueuedConnection);
+ } else {
+ // wake up constructor in blocking mode
+ // (we might got disabled before first message arrived)
+ d->initializeCondition.wakeAll();
}
}
void QV8DebugService::messageReceived(const QByteArray &message)
{
Q_D(QV8DebugService);
+ QMutexLocker lock(&d->initializeMutex);
QDataStream ds(message);
QByteArray header;
ds >> command >> data;
if (command == V8_DEBUGGER_KEY_CONNECT) {
- QMutexLocker locker(&d->initializeMutex);
- d->connectReceived = true;
sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_CONNECT)));
-
+ // wake up constructor in blocking mode
+ d->initializeCondition.wakeAll();
} else if (command == V8_DEBUGGER_KEY_INTERRUPT) {
// break has to be executed in gui thread
QMetaObject::invokeMethod(this, "scheduledDebugBreak", Qt::QueuedConnection, Q_ARG(bool, true));
else
d->breakOnSignals.removeOne(signalName);
sendMessage(QV8DebugServicePrivate::packMessage(QLatin1String(V8_DEBUGGER_KEY_BREAK_ON_SIGNAL)));
-
}
}
}
#include <private/qv8profiler_p.h>
#include <QtCore/QHash>
+#include <QtCore/QMutex>
+#include <QtCore/QWaitCondition>
QT_BEGIN_NAMESPACE
QList<QV8ProfilerData> m_data;
bool initialized;
+ QMutex initializeMutex;
+ QWaitCondition initializeCondition;
QList<QString> m_ongoing;
};
{
Q_D(QV8ProfilerService);
- if (registerService() == Enabled) {
- // ,block mode, client attached
- while (!d->initialized)
- waitForMessage();
+ QMutexLocker lock(&d->initializeMutex);
+
+ if (registerService() == Enabled
+ && QQmlDebugService::blockingMode()) {
+ // let's wait for first message ...
+ d->initializeCondition.wait(&d->initializeMutex);
}
}
Q_ARG(QString, title));
}
QMetaObject::invokeMethod(this, "sendProfilingData", Qt::BlockingQueuedConnection);
+ } else {
+ // wake up constructor in blocking mode
+ // (we might got disabled before first message arrived)
+ d->initializeCondition.wakeAll();
}
}
QByteArray title;
ds >> command >> option;
+ QMutexLocker lock(&d->initializeMutex);
+
if (command == "V8PROFILER") {
ds >> title;
QString titleStr = QString::fromUtf8(title);
}
}
+ // wake up constructor in blocking mode
+ d->initializeCondition.wakeAll();
+
QQmlDebugService::messageReceived(message);
}