AutoTest: Guard against concurrent access

While parsing for Qt Quick Tests it may happen that an internal
map is accessed concurrently by different threads.
Guard against this. Minor drive-by optimizations.

Change-Id: Ic3b62c27feddb9a5ac5588a6c9643fc0e623ce19
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Stenger
2023-09-27 09:57:59 +02:00
parent dda6d05282
commit 621a492b6a
2 changed files with 13 additions and 6 deletions

View File

@@ -261,7 +261,10 @@ bool QuickTestParser::handleQtQuickTest(QPromise<TestParseResultPtr> &promise,
return false; return false;
const FilePath cppFileName = document->filePath(); const FilePath cppFileName = document->filePath();
const FilePath proFile = FilePath::fromString(ppList.at(0)->projectFile); const FilePath proFile = FilePath::fromString(ppList.at(0)->projectFile);
{
QWriteLocker lock(&m_parseLock);
m_mainCppFiles.insert(cppFileName, proFile); m_mainCppFiles.insert(cppFileName, proFile);
}
const FilePath srcDir = FilePath::fromString(quickTestSrcDir(cppFileName)); const FilePath srcDir = FilePath::fromString(quickTestSrcDir(cppFileName));
if (srcDir.isEmpty()) if (srcDir.isEmpty())
return false; return false;
@@ -340,13 +343,13 @@ QuickTestParser::QuickTestParser(ITestFramework *framework)
void QuickTestParser::init(const QSet<FilePath> &filesToParse, bool fullParse) void QuickTestParser::init(const QSet<FilePath> &filesToParse, bool fullParse)
{ {
m_qmlSnapshot = QmlJSTools::Internal::ModelManager::instance()->snapshot(); m_qmlSnapshot = QmlJSTools::Internal::ModelManager::instance()->snapshot();
QWriteLocker lock(&m_parseLock); // should not be necessary
if (!fullParse) { if (!fullParse) {
// in a full parse we get the correct entry points by the respective main // in a full parse we get the correct entry points by the respective main
m_proFilesForQmlFiles = QuickTestUtils::proFilesForQmlFiles(framework(), filesToParse); m_proFilesForQmlFiles = QuickTestUtils::proFilesForQmlFiles(framework(), filesToParse);
// get rid of cached main cpp files that are going to get processed anyhow // get rid of cached main cpp files that are going to get processed anyhow
for (const FilePath &file : filesToParse) { for (const FilePath &file : filesToParse) {
if (m_mainCppFiles.contains(file)) { if (m_mainCppFiles.remove(file) == 1) {
m_mainCppFiles.remove(file);
if (m_mainCppFiles.isEmpty()) if (m_mainCppFiles.isEmpty())
break; break;
} }
@@ -355,6 +358,7 @@ void QuickTestParser::init(const QSet<FilePath> &filesToParse, bool fullParse)
// get rid of all cached main cpp files // get rid of all cached main cpp files
m_mainCppFiles.clear(); m_mainCppFiles.clear();
} }
lock.unlock();
m_checkForDerivedTests = theQtTestFramework().quickCheckForDerivedTests(); m_checkForDerivedTests = theQtTestFramework().quickCheckForDerivedTests();
@@ -399,9 +403,10 @@ bool QuickTestParser::processDocument(QPromise<TestParseResultPtr> &promise,
return handleQtQuickTest(promise, cppdoc, framework()); return handleQtQuickTest(promise, cppdoc, framework());
} }
FilePath QuickTestParser::projectFileForMainCppFile(const FilePath &fileName) const FilePath QuickTestParser::projectFileForMainCppFile(const FilePath &fileName)
{ {
return m_mainCppFiles.contains(fileName) ? m_mainCppFiles.value(fileName) : FilePath(); QReadLocker lock(&m_parseLock);
return m_mainCppFiles.value(fileName);
} }
} // namespace Autotest::Internal } // namespace Autotest::Internal

View File

@@ -8,6 +8,7 @@
#include <qmljs/qmljsdocument.h> #include <qmljs/qmljsdocument.h>
#include <QFileSystemWatcher> #include <QFileSystemWatcher>
#include <QReadWriteLock>
namespace Autotest { namespace Autotest {
namespace Internal { namespace Internal {
@@ -28,7 +29,7 @@ public:
void release() override; void release() override;
bool processDocument(QPromise<TestParseResultPtr> &promise, bool processDocument(QPromise<TestParseResultPtr> &promise,
const Utils::FilePath &fileName) override; const Utils::FilePath &fileName) override;
Utils::FilePath projectFileForMainCppFile(const Utils::FilePath &fileName) const; Utils::FilePath projectFileForMainCppFile(const Utils::FilePath &fileName);
QStringList supportedExtensions() const override { return {"qml"}; }; QStringList supportedExtensions() const override { return {"qml"}; };
private: private:
@@ -45,6 +46,7 @@ private:
QMap<QString, QMap<QString, QDateTime> > m_watchedFiles; QMap<QString, QMap<QString, QDateTime> > m_watchedFiles;
QMap<Utils::FilePath, Utils::FilePath> m_mainCppFiles; QMap<Utils::FilePath, Utils::FilePath> m_mainCppFiles;
QSet<Utils::FilePath> m_prefilteredFiles; QSet<Utils::FilePath> m_prefilteredFiles;
QReadWriteLock m_parseLock; // guard for m_mainCppFiles
bool m_checkForDerivedTests = false; bool m_checkForDerivedTests = false;
}; };