forked from qt-creator/qt-creator
AutoTest: Avoid dead-lock of file system watcher
Calling addPath() on the watcher could dead-lock on some operating systems as we were in an asynchronous process. Avoid calling addPath() from inside an asynchronous process and perform this call from synchronous context. Change-Id: I94cd401e12ccbb3526b8cc4232a9cff7ed552bbb Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -37,13 +37,9 @@
|
|||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QFileSystemWatcher>
|
|
||||||
|
|
||||||
namespace Autotest {
|
namespace Autotest {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
static QFileSystemWatcher s_directoryWatcher;
|
|
||||||
|
|
||||||
TestTreeItem *QuickTestParseResult::createTestTreeItem() const
|
TestTreeItem *QuickTestParseResult::createTestTreeItem() const
|
||||||
{
|
{
|
||||||
if (itemType == TestTreeItem::Root || itemType == TestTreeItem::TestDataTag)
|
if (itemType == TestTreeItem::Root || itemType == TestTreeItem::TestDataTag)
|
||||||
@@ -126,7 +122,7 @@ static QString quickTestName(const CPlusPlus::Document::Ptr &doc)
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
static QList<QmlJS::Document::Ptr> scanDirectoryForQuickTestQmlFiles(const QString &srcDir)
|
QList<QmlJS::Document::Ptr> QuickTestParser::scanDirectoryForQuickTestQmlFiles(const QString &srcDir) const
|
||||||
{
|
{
|
||||||
QStringList dirs(srcDir);
|
QStringList dirs(srcDir);
|
||||||
QmlJS::ModelManagerInterface *qmlJsMM = QmlJSTools::Internal::ModelManager::instance();
|
QmlJS::ModelManagerInterface *qmlJsMM = QmlJSTools::Internal::ModelManager::instance();
|
||||||
@@ -142,9 +138,9 @@ static QList<QmlJS::Document::Ptr> scanDirectoryForQuickTestQmlFiles(const QStri
|
|||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
it.next();
|
it.next();
|
||||||
QFileInfo fi(it.fileInfo().canonicalFilePath());
|
QFileInfo fi(it.fileInfo().canonicalFilePath());
|
||||||
dirs << fi.filePath();
|
dirs.append(fi.filePath());
|
||||||
}
|
}
|
||||||
s_directoryWatcher.addPaths(dirs);
|
emit updateWatchPaths(dirs);
|
||||||
|
|
||||||
QList<QmlJS::Document::Ptr> foundDocs;
|
QList<QmlJS::Document::Ptr> foundDocs;
|
||||||
|
|
||||||
@@ -211,9 +207,9 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface,
|
bool QuickTestParser::handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface,
|
||||||
CPlusPlus::Document::Ptr document,
|
CPlusPlus::Document::Ptr document,
|
||||||
const Core::Id &id)
|
const Core::Id &id) const
|
||||||
{
|
{
|
||||||
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
|
const CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance();
|
||||||
if (quickTestName(document).isEmpty())
|
if (quickTestName(document).isEmpty())
|
||||||
@@ -229,32 +225,35 @@ static bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterfa
|
|||||||
if (srcDir.isEmpty())
|
if (srcDir.isEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (futureInterface.isCanceled())
|
||||||
|
return false;
|
||||||
const QList<QmlJS::Document::Ptr> qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir);
|
const QList<QmlJS::Document::Ptr> qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir);
|
||||||
bool result = false;
|
bool result = false;
|
||||||
for (const QmlJS::Document::Ptr &qmlJSDoc : qmlDocs)
|
for (const QmlJS::Document::Ptr &qmlJSDoc : qmlDocs) {
|
||||||
|
if (futureInterface.isCanceled())
|
||||||
|
break;
|
||||||
result |= checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, id, proFile);
|
result |= checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, id, proFile);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QuickTestParser::QuickTestParser()
|
QuickTestParser::QuickTestParser()
|
||||||
: CppParser()
|
: CppParser()
|
||||||
{
|
{
|
||||||
QObject::connect(ProjectExplorer::SessionManager::instance(),
|
connect(ProjectExplorer::SessionManager::instance(),
|
||||||
&ProjectExplorer::SessionManager::startupProjectChanged, [] {
|
&ProjectExplorer::SessionManager::startupProjectChanged, [this] {
|
||||||
const QStringList &dirs = s_directoryWatcher.directories();
|
const QStringList &dirs = m_directoryWatcher.directories();
|
||||||
if (!dirs.isEmpty())
|
if (!dirs.isEmpty())
|
||||||
s_directoryWatcher.removePaths(dirs);
|
m_directoryWatcher.removePaths(dirs);
|
||||||
});
|
});
|
||||||
QObject::connect(&s_directoryWatcher, &QFileSystemWatcher::directoryChanged,
|
connect(&m_directoryWatcher, &QFileSystemWatcher::directoryChanged,
|
||||||
[this] { TestTreeModel::instance()->parser()->emitUpdateTestTree(this); });
|
[this] { TestTreeModel::instance()->parser()->emitUpdateTestTree(this); });
|
||||||
|
connect(this, &QuickTestParser::updateWatchPaths,
|
||||||
|
&m_directoryWatcher, &QFileSystemWatcher::addPaths, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
QuickTestParser::~QuickTestParser()
|
QuickTestParser::~QuickTestParser()
|
||||||
{
|
{
|
||||||
QObject::disconnect(&s_directoryWatcher, 0, 0, 0);
|
|
||||||
const QStringList &dirs = s_directoryWatcher.directories();
|
|
||||||
if (!dirs.isEmpty())
|
|
||||||
s_directoryWatcher.removePaths(dirs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuickTestParser::init(const QStringList &filesToParse)
|
void QuickTestParser::init(const QStringList &filesToParse)
|
||||||
|
|||||||
@@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
#include <qmljs/qmljsdocument.h>
|
#include <qmljs/qmljsdocument.h>
|
||||||
|
|
||||||
|
#include <QFileSystemWatcher>
|
||||||
|
|
||||||
namespace Autotest {
|
namespace Autotest {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -39,8 +41,9 @@ public:
|
|||||||
TestTreeItem *createTestTreeItem() const override;
|
TestTreeItem *createTestTreeItem() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QuickTestParser : public CppParser
|
class QuickTestParser : public QObject, public CppParser
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
QuickTestParser();
|
QuickTestParser();
|
||||||
virtual ~QuickTestParser();
|
virtual ~QuickTestParser();
|
||||||
@@ -48,9 +51,15 @@ public:
|
|||||||
void release() override;
|
void release() override;
|
||||||
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
|
bool processDocument(QFutureInterface<TestParseResultPtr> futureInterface,
|
||||||
const QString &fileName) override;
|
const QString &fileName) override;
|
||||||
|
signals:
|
||||||
|
void updateWatchPaths(const QStringList &directories) const;
|
||||||
private:
|
private:
|
||||||
|
bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface,
|
||||||
|
CPlusPlus::Document::Ptr document, const Core::Id &id) const;
|
||||||
|
QList<QmlJS::Document::Ptr> scanDirectoryForQuickTestQmlFiles(const QString &srcDir) const;
|
||||||
QmlJS::Snapshot m_qmlSnapshot;
|
QmlJS::Snapshot m_qmlSnapshot;
|
||||||
QHash<QString, QString> m_proFilesForQmlFiles;
|
QHash<QString, QString> m_proFilesForQmlFiles;
|
||||||
|
QFileSystemWatcher m_directoryWatcher;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
Reference in New Issue
Block a user