aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2021-08-16 15:02:40 +0200
committerUlf Hermann <ulf.hermann@qt.io>2021-08-20 09:17:02 +0200
commite6d106db2284d7eb50ca040b454109f686adf59e (patch)
treea3d2136876e96e289fac53bdeea2a0f8181b0ca8
parent45448222fc2a24f848effb6ed16c8c5adfab776a (diff)
QmlPreview: Protect QQmlPreviewFileLoader::load with another mutex
We can concurrently load multiple files from different threads, but the loader can only handle one such request at a time. Fixes: QTBUG-95825 Change-Id: I2b94d55f2cf0da6e84dabc47df5699cc57b903a6 Reviewed-by: Maximilian Goldstein <max.goldstein@qt.io> Reviewed-by: Knud Dollereder <knud.dollereder@qt.io> (cherry picked from commit a068fdc0b2cf7d4223d9ad15345fe9d345875936) Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp8
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp20
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h5
3 files changed, 22 insertions, 11 deletions
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp
index 620c1cf1ba..7b53402df9 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp
@@ -398,6 +398,14 @@ bool QQmlPreviewFileEngine::supportsExtension(Extension extension) const
void QQmlPreviewFileEngine::load() const
{
+ // We can get here from different threads on different instances of QQmlPreviewFileEngine.
+ // However, there is only one loader per QQmlPreviewFileEngineHandler and it is not thread-safe.
+ // Its content mutex doesn't help us here because we explicitly wait on it in load(), which
+ // causes it to be released. Therefore, lock the load mutex first.
+ // This doesn't cause any deadlocks because the only thread that wakes the loader on the content
+ // mutex never calls load(). It's the QML debug server thread that handles the debug protocol.
+ QMutexLocker loadLocker(m_loader->loadMutex());
+
m_result = m_loader->load(m_absolute);
switch (m_result) {
case QQmlPreviewFileLoader::File:
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
index 72abba6154..f97dcfc767 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
@@ -101,7 +101,7 @@ QQmlPreviewFileLoader::~QQmlPreviewFileLoader() {
QQmlPreviewFileLoader::Result QQmlPreviewFileLoader::load(const QString &path)
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
m_path = path;
auto fileIterator = m_fileCache.constFind(path);
@@ -124,19 +124,19 @@ QQmlPreviewFileLoader::Result QQmlPreviewFileLoader::load(const QString &path)
m_entries.clear();
m_contents.clear();
emit request(path);
- m_waitCondition.wait(&m_mutex);
+ m_waitCondition.wait(&m_contentMutex);
return m_result;
}
QByteArray QQmlPreviewFileLoader::contents()
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
return m_contents;
}
QStringList QQmlPreviewFileLoader::entries()
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
return m_entries;
}
@@ -144,20 +144,20 @@ void QQmlPreviewFileLoader::whitelist(const QUrl &url)
{
const QString path = QQmlFile::urlToLocalFileOrQrc(url);
if (!path.isEmpty()) {
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
m_blacklist.whitelist(path);
}
}
bool QQmlPreviewFileLoader::isBlacklisted(const QString &path)
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
return m_blacklist.isBlacklisted(path);
}
void QQmlPreviewFileLoader::file(const QString &path, const QByteArray &contents)
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
m_blacklist.whitelist(path);
m_fileCache[path] = contents;
if (path == m_path) {
@@ -169,7 +169,7 @@ void QQmlPreviewFileLoader::file(const QString &path, const QByteArray &contents
void QQmlPreviewFileLoader::directory(const QString &path, const QStringList &entries)
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
m_blacklist.whitelist(path);
m_directoryCache[path] = entries;
if (path == m_path) {
@@ -181,7 +181,7 @@ void QQmlPreviewFileLoader::directory(const QString &path, const QStringList &en
void QQmlPreviewFileLoader::error(const QString &path)
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
m_blacklist.blacklist(path);
if (path == m_path) {
m_result = Fallback;
@@ -191,7 +191,7 @@ void QQmlPreviewFileLoader::error(const QString &path)
void QQmlPreviewFileLoader::clearCache()
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
m_fileCache.clear();
m_directoryCache.clear();
}
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h
index 9c337935e3..e66294cb06 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h
@@ -79,7 +79,9 @@ public:
QQmlPreviewFileLoader(QQmlPreviewServiceImpl *service);
~QQmlPreviewFileLoader();
+ QMutex *loadMutex() { return &m_loadMutex; }
Result load(const QString &file);
+
QByteArray contents();
QStringList entries();
@@ -90,7 +92,8 @@ signals:
void request(const QString &file);
private:
- QMutex m_mutex;
+ QMutex m_loadMutex;
+ QMutex m_contentMutex;
QWaitCondition m_waitCondition;
QThread m_thread;