Fix a deadlock when closing Creator while loading a project

Replace the call to SynchronousProcess::run() by asynchronous
call that invokes a process.

This change may be tested by applying the additional patch
mentioned in QTCREATORBUG-25385 description.

Don't call the SynchronousProcess::run() from the main thread when
the Quit event was already scheduled for qApp, since the Quit event
will get removed from the awaiting queue by a call to
QEventLoop::exec().

Fixes: QTCREATORBUG-25385
Change-Id: I8af39552443bfa9b3af6e31ddce85a01b91bbbd8
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
Jarek Kobus
2021-02-25 12:53:41 +01:00
parent 2de66272e8
commit 675a72e296
2 changed files with 58 additions and 32 deletions

View File

@@ -39,6 +39,7 @@
#include <android/androidconstants.h>
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/reaper.h>
#include <cpptools/cppprojectupdater.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/generatedcodemodelsupport.h>
@@ -59,6 +60,7 @@
#include <utils/macroexpander.h>
#include <utils/mimetypes/mimetype.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h>
#include <QClipboard>
#include <QDir>
@@ -207,6 +209,7 @@ CMakeBuildSystem::CMakeBuildSystem(CMakeBuildConfiguration *bc)
CMakeBuildSystem::~CMakeBuildSystem()
{
m_futureSynchronizer.waitForFinished();
if (!m_treeScanner.isFinished()) {
auto future = m_treeScanner.future();
future.cancel();
@@ -576,7 +579,7 @@ void CMakeBuildSystem::combineScanAndParse()
emitBuildSystemUpdated();
QTimer::singleShot(0, this, &CMakeBuildSystem::runCTest);
runCTest();
}
void CMakeBuildSystem::checkAndReportError(QString &errorMessage)
@@ -921,19 +924,38 @@ void CMakeBuildSystem::runCTest()
}
qCDebug(cmakeBuildSystemLog) << "Requesting ctest run after cmake run";
BuildDirParameters parameters(cmakeBuildConfiguration());
const BuildDirParameters parameters(cmakeBuildConfiguration());
QTC_ASSERT(parameters.isValid(), return);
FilePath workingDirectory = workDirectory(parameters);
CommandLine cmd{m_ctestPath, {"-N", "--show-only=json-v1"}};
SynchronousProcess ctest;
ctest.setTimeoutS(1);
ctest.setEnvironment(cmakeBuildConfiguration()->environment().toStringList());
ctest.setWorkingDirectory(workingDirectory.toString());
const CommandLine cmd { m_ctestPath, { "-N", "--show-only=json-v1" } };
const QString workingDirectory = workDirectory(parameters).toString();
const QStringList environment = cmakeBuildConfiguration()->environment().toStringList();
const SynchronousProcessResponse response = ctest.run(cmd);
if (response.result == SynchronousProcessResponse::Finished) {
const QJsonDocument json = QJsonDocument::fromJson(response.allRawOutput());
auto future = Utils::runAsync([cmd, workingDirectory, environment]
(QFutureInterface<QByteArray> &futureInterface) {
QProcess process;
process.setEnvironment(environment);
process.setWorkingDirectory(workingDirectory);
process.start(cmd.executable().toString(), cmd.splitArguments(), QIODevice::ReadOnly);
if (!process.waitForStarted(1000) || !process.waitForFinished(1000)) {
if (process.state() == QProcess::NotRunning)
return;
process.terminate();
if (process.waitForFinished(1000))
return;
process.kill();
process.waitForFinished(1000);
return;
}
if (process.exitCode() || process.exitStatus() != QProcess::NormalExit)
return;
futureInterface.reportResult(process.readAllStandardOutput());
});
Utils::onFinished(future, this, [this](const QFuture<QByteArray> &future) {
if (future.resultCount()) {
const QJsonDocument json = QJsonDocument::fromJson(future.result());
if (!json.isEmpty() && json.isObject()) {
const QJsonObject jsonObj = json.object();
const QJsonObject btGraph = jsonObj.value("backtraceGraph").toObject();
@@ -949,14 +971,15 @@ void CMakeBuildSystem::runCTest()
int file = btRef.value("file").toInt(-1);
int line = btRef.value("line").toInt(-1);
QTC_ASSERT(file != -1 && line != -1, continue);
m_testNames.append({test.value("name").toString(),
FilePath::fromString(cmakelists.at(file).toString()),
line
});
m_testNames.append({ test.value("name").toString(),
FilePath::fromString(cmakelists.at(file).toString()), line });
}
}
}
emit testInformationUpdated();
});
m_futureSynchronizer.addFuture(future);
}
CMakeBuildConfiguration *CMakeBuildSystem::cmakeBuildConfiguration() const

View File

@@ -35,6 +35,8 @@
#include <utils/fileutils.h>
#include <utils/temporarydirectory.h>
#include <QFutureSynchronizer>
namespace ProjectExplorer { class ExtraCompiler; }
namespace CppTools {
@@ -181,6 +183,7 @@ private:
// CTest integration
QString m_ctestPath;
QList<ProjectExplorer::TestCaseInfo> m_testNames;
QFutureSynchronizer<QByteArray> m_futureSynchronizer;
};
} // namespace Internal