diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2017-09-04 18:21:41 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@qt.io> | 2017-09-07 07:53:36 +0000 |
commit | cf3b1bbd9ee048a28b58a55d76504b1c01e34811 (patch) | |
tree | 920fdef22725390389a8687bc3717c5e5220e32c | |
parent | a8cff0a4dea4c5041854f9200b110e19af210a0f (diff) |
QmlProfiler: Avoid race conditions in QQmlTypeLoader
We have to make sure all profiler calls to one adapter are done from the
same thread.
It turns out that all the calls from QQmlTypeLoader are done from the
type loader thread. By using a separate adapter for that, we avoid any
extra locking.
Task-number: QTBUG-62987
Change-Id: Ice400b1c3b7bd920d855ceb1ba0d46417f50348d
(cherry picked from commit 4578a92744d447222f5e22851433d5dbecc51855)
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r-- | src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp | 29 | ||||
-rw-r--r-- | src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h | 2 | ||||
-rw-r--r-- | src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp | 9 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 20 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader_p.h | 17 |
5 files changed, 62 insertions, 15 deletions
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp index 245900abae..b3fa8e26f2 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp @@ -37,19 +37,32 @@ QT_BEGIN_NAMESPACE QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine) : - QQmlAbstractProfilerAdapter(service), next(0) + QQmlAbstractProfilerAdapter(service) { engine->enableProfiler(); - connect(this, SIGNAL(profilingEnabled(quint64)), engine->profiler, SLOT(startProfiling(quint64))); + init(engine->profiler); +} + +QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlTypeLoader *loader) : + QQmlAbstractProfilerAdapter(service) +{ + loader->enableProfiler(); + init(loader->profiler()); +} + +void QQmlProfilerAdapter::init(QQmlProfiler *profiler) +{ + next = 0; + connect(this, SIGNAL(profilingEnabled(quint64)), profiler, SLOT(startProfiling(quint64))); connect(this, SIGNAL(profilingEnabledWhileWaiting(quint64)), - engine->profiler, SLOT(startProfiling(quint64)), Qt::DirectConnection); - connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling())); + profiler, SLOT(startProfiling(quint64)), Qt::DirectConnection); + connect(this, SIGNAL(profilingDisabled()), profiler, SLOT(stopProfiling())); connect(this, SIGNAL(profilingDisabledWhileWaiting()), - engine->profiler, SLOT(stopProfiling()), Qt::DirectConnection); - connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData())); + profiler, SLOT(stopProfiling()), Qt::DirectConnection); + connect(this, SIGNAL(dataRequested()), profiler, SLOT(reportData())); connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), - engine->profiler, SLOT(setTimer(QElapsedTimer))); - connect(engine->profiler, SIGNAL(dataReady(QVector<QQmlProfilerData>)), + profiler, SLOT(setTimer(QElapsedTimer))); + connect(profiler, SIGNAL(dataReady(QVector<QQmlProfilerData>)), this, SLOT(receiveData(QVector<QQmlProfilerData>))); } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h index eceb58ce3a..8eb61f9744 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h @@ -54,12 +54,14 @@ class QQmlProfilerAdapter : public QQmlAbstractProfilerAdapter { Q_OBJECT public: QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine); + QQmlProfilerAdapter(QQmlProfilerService *service, QQmlTypeLoader *loader); qint64 sendMessages(qint64 until, QList<QByteArray> &messages); public slots: void receiveData(const QVector<QQmlProfilerData> &new_data); private: + void init(QQmlProfiler *profiler); QVector<QQmlProfilerData> data; int next; }; diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp index a5ee494ced..930a5d37d8 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp @@ -98,9 +98,14 @@ void QQmlProfilerServiceImpl::engineAboutToBeAdded(QQmlEngine *engine) "QML profilers have to be added from the engine thread"); QMutexLocker lock(&m_configMutex); - QQmlProfilerAdapter *qmlAdapter = new QQmlProfilerAdapter(this, QQmlEnginePrivate::get(engine)); - QV4ProfilerAdapter *v4Adapter = new QV4ProfilerAdapter(this, QV8Engine::getV4(engine->handle())); + QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); + QQmlProfilerAdapter *qmlAdapter = new QQmlProfilerAdapter(this, enginePrivate); + QQmlProfilerAdapter *compileAdapter + = new QQmlProfilerAdapter(this, &(enginePrivate->typeLoader)); + QV4ProfilerAdapter *v4Adapter + = new QV4ProfilerAdapter(this, QV8Engine::getV4(engine->handle())); addEngineProfiler(qmlAdapter, engine); + addEngineProfiler(compileAdapter, engine); addEngineProfiler(v4Adapter, engine); QQmlConfigurableDebugService<QQmlProfilerService>::engineAboutToBeAdded(engine); } diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 6480420212..074f760a36 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -647,8 +647,7 @@ void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob) { Q_ASSERT(m_waitingFor.contains(blob)); Q_ASSERT(blob->status() == Error || blob->status() == Complete); - QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, - blob->url()); + QQmlCompilingProfiler prof(typeLoader()->profiler(), blob->url()); m_inCallback = true; @@ -901,6 +900,12 @@ void QQmlTypeLoader::invalidate() m_networkReplies.clear(); } +void QQmlTypeLoader::enableProfiler() +{ + Q_ASSERT(!m_profiler); + m_profiler = new QQmlProfiler; +} + void QQmlTypeLoader::lock() { m_thread->lock(); @@ -1216,7 +1221,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, QQmlFile *file) void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d) { QML_MEMORY_SCOPE_URL(blob->url()); - QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob->url()); + QQmlCompilingProfiler prof(profiler(), blob->url()); blob->m_inCallback = true; @@ -1236,7 +1241,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d) void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit) { QML_MEMORY_SCOPE_URL(blob->url()); - QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob->url()); + QQmlCompilingProfiler prof(profiler(), blob->url()); blob->m_inCallback = true; @@ -1594,6 +1599,9 @@ Constructs a new type loader that uses the given \a engine. */ QQmlTypeLoader::QQmlTypeLoader(QQmlEngine *engine) : m_engine(engine), m_thread(new QQmlTypeLoaderThread(this)), +#ifndef QT_NO_QML_DEBUGGER + m_profiler(0), +#endif m_typeCacheTrimThreshold(TYPELOADER_MINIMUM_TRIM_THRESHOLD) { } @@ -1610,6 +1618,10 @@ QQmlTypeLoader::~QQmlTypeLoader() clearCache(); invalidate(); + +#ifndef QT_NO_QML_DEBUGGER + delete m_profiler; +#endif } QQmlImportDatabase *QQmlTypeLoader::importDatabase() diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index f565bcd31f..5095aa6bcf 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -74,6 +74,7 @@ class QQmlComponentPrivate; class QQmlTypeData; class QQmlTypeLoader; class QQmlExtensionInterface; +class QQmlProfiler; namespace QmlIR { struct Document; @@ -211,7 +212,7 @@ private: class QQmlTypeLoaderThread; -class Q_AUTOTEST_EXPORT QQmlTypeLoader +class Q_QML_PRIVATE_EXPORT QQmlTypeLoader { Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader) public: @@ -311,6 +312,15 @@ public: void initializeEngine(QQmlExtensionInterface *, const char *); void invalidate(); +#ifdef QT_NO_QML_DEBUGGER + QQmlProfiler *profiler() const { return 0; } + void enableProfiler() {} +#else + QQmlProfiler *profiler() const { return m_profiler; } + void enableProfiler(); +#endif // QT_NO_QML_DEBUGGER + + private: friend class QQmlDataBlob; friend class QQmlTypeLoaderThread; @@ -356,6 +366,11 @@ private: QQmlEngine *m_engine; QQmlTypeLoaderThread *m_thread; + +#ifndef QT_NO_QML_DEBUGGER + QQmlProfiler *m_profiler; +#endif + NetworkReplies m_networkReplies; TypeCache m_typeCache; int m_typeCacheTrimThreshold; |