Clang: Do not use Core::MessageManager from worker thread

...since that's not thread-safe and thus leads to crashes from time to
time.

Change-Id: I907ae8b5c4d60bfc82bc97b55cc5d62d8bbeae04
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
Nikolai Kosjar
2014-03-04 15:01:57 -03:00
parent cb66d1ec23
commit a723205f6c
2 changed files with 192 additions and 166 deletions

View File

@@ -34,6 +34,7 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/progressmanager/progressmanager.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h> #include <utils/runextensions.h>
#include <QFile> #include <QFile>
@@ -153,14 +154,36 @@ void PchManager::updatePchInfo(ClangProjectSettings *cps,
const QList<ProjectPart::Ptr> &projectParts) const QList<ProjectPart::Ptr> &projectParts)
{ {
if (m_pchGenerationWatcher.isRunning()) { if (m_pchGenerationWatcher.isRunning()) {
// m_pchGenerationWatcher.cancel();
m_pchGenerationWatcher.waitForFinished(); m_pchGenerationWatcher.waitForFinished();
} }
QFuture<void> future = QtConcurrent::run(&PchManager::doPchInfoUpdate, const QString customPchFile = cps->customPchFile();
cps->pchUsage(), const ClangProjectSettings::PchUsage pchUsage = cps->pchUsage();
cps->customPchFile(),
projectParts); void (*updateFunction)(QFutureInterface<void> &future,
const PchManager::UpdateParams &params) = 0;
QString message;
if (pchUsage == ClangProjectSettings::PchUse_None
|| (pchUsage == ClangProjectSettings::PchUse_Custom && customPchFile.isEmpty())) {
updateFunction = &PchManager::doPchInfoUpdateNone;
message = QLatin1String("updatePchInfo: switching to none");
} else if (pchUsage == ClangProjectSettings::PchUse_BuildSystem_Fuzzy) {
updateFunction = &PchManager::doPchInfoUpdateFuzzy;
message = QLatin1String("updatePchInfo: switching to build system (fuzzy)");
} else if (pchUsage == ClangProjectSettings::PchUse_BuildSystem_Exact) {
updateFunction = &PchManager::doPchInfoUpdateExact;
message = QLatin1String("updatePchInfo: switching to build system (exact)");
} else if (pchUsage == ClangProjectSettings::PchUse_Custom) {
updateFunction = &PchManager::doPchInfoUpdateCustom;
message = QLatin1String("updatePchInfo: switching to custom") + customPchFile;
}
QTC_ASSERT(updateFunction && !message.isEmpty(), return);
Core::MessageManager::write(message, Core::MessageManager::Silent);
const UpdateParams updateParams = UpdateParams(customPchFile, projectParts);
QFuture<void> future
= QtConcurrent::run<void, const UpdateParams &>(updateFunction, updateParams);
m_pchGenerationWatcher.setFuture(future); m_pchGenerationWatcher.setFuture(future);
Core::ProgressManager::addTask(future, tr("Precompiling..."), "Key.Tmp.Precompiling"); Core::ProgressManager::addTask(future, tr("Precompiling..."), "Key.Tmp.Precompiling");
} }
@@ -214,27 +237,17 @@ CppTools::ProjectFile::Kind getPrefixFileKind(bool hasObjectiveC, bool hasCPlusP
} }
void PchManager::doPchInfoUpdate(QFutureInterface<void> &future, void PchManager::doPchInfoUpdateNone(QFutureInterface<void> &future, const PchManager::UpdateParams &params)
ClangProjectSettings::PchUsage pchUsage,
const QString customPchFile,
const QList<ProjectPart::Ptr> projectParts)
{ {
PchManager *pchManager = PchManager::instance(); future.setProgressRange(0, 1);
// qDebug() << "switching to" << pchUsage;
if (pchUsage == ClangProjectSettings::PchUse_None
|| (pchUsage == ClangProjectSettings::PchUse_Custom && customPchFile.isEmpty())) {
future.setProgressRange(0, 2);
Core::MessageManager::write(QLatin1String("updatePchInfo: switching to none"),
Core::MessageManager::Silent);
PchInfo::Ptr emptyPch = PchInfo::createEmpty(); PchInfo::Ptr emptyPch = PchInfo::createEmpty();
pchManager->setPCHInfo(projectParts, emptyPch, qMakePair(true, QStringList())); PchManager::instance()->setPCHInfo(params.projectParts, emptyPch,
qMakePair(true, QStringList()));
future.setProgressValue(1); future.setProgressValue(1);
} else if (pchUsage == ClangProjectSettings::PchUse_BuildSystem_Fuzzy) { }
Core::MessageManager::write(
QLatin1String("updatePchInfo: switching to build system (fuzzy)"), void PchManager::doPchInfoUpdateFuzzy(QFutureInterface<void> &future, const PchManager::UpdateParams &params)
Core::MessageManager::Silent); {
QHash<QString, QSet<QString> > includes, frameworks; QHash<QString, QSet<QString> > includes, frameworks;
QHash<QString, QSet<QByteArray> > definesPerPCH; QHash<QString, QSet<QByteArray> > definesPerPCH;
QHash<QString, bool> objc; QHash<QString, bool> objc;
@@ -244,7 +257,7 @@ void PchManager::doPchInfoUpdate(QFutureInterface<void> &future,
QHash<QString, ProjectPart::CXXVersion> cxxVersions; QHash<QString, ProjectPart::CXXVersion> cxxVersions;
QHash<QString, ProjectPart::CXXExtensions> cxxExtensionsMap; QHash<QString, ProjectPart::CXXExtensions> cxxExtensionsMap;
QHash<QString, QList<ProjectPart::Ptr> > inputToParts; QHash<QString, QList<ProjectPart::Ptr> > inputToParts;
foreach (const ProjectPart::Ptr &projectPart, projectParts) { foreach (const ProjectPart::Ptr &projectPart, params.projectParts) {
if (projectPart->precompiledHeaders.isEmpty()) if (projectPart->precompiledHeaders.isEmpty())
continue; continue;
const QString &pch = projectPart->precompiledHeaders.first(); // TODO: support more than 1 PCH file. const QString &pch = projectPart->precompiledHeaders.first(); // TODO: support more than 1 PCH file.
@@ -310,6 +323,7 @@ void PchManager::doPchInfoUpdate(QFutureInterface<void> &future,
QStringList options = Utils::createClangOptions(projectPart, prefixFileKind); QStringList options = Utils::createClangOptions(projectPart, prefixFileKind);
projectPart.reset(); projectPart.reset();
PchManager *pchManager = PchManager::instance();
PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, true); PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, true);
QPair<bool, QStringList> msgs = qMakePair(true, QStringList()); QPair<bool, QStringList> msgs = qMakePair(true, QStringList());
if (pchInfo.isNull()) { if (pchInfo.isNull()) {
@@ -320,13 +334,15 @@ void PchManager::doPchInfoUpdate(QFutureInterface<void> &future,
pchManager->setPCHInfo(inputToParts[pch], pchInfo, msgs); pchManager->setPCHInfo(inputToParts[pch], pchInfo, msgs);
future.setProgressValue(future.progressValue() + 1); future.setProgressValue(future.progressValue() + 1);
} }
} else if (pchUsage == ClangProjectSettings::PchUse_BuildSystem_Exact) {
future.setProgressRange(0, projectParts.size() + 1); future.setProgressValue(future.progressValue() + 1);
}
void PchManager::doPchInfoUpdateExact(QFutureInterface<void> &future, const PchManager::UpdateParams &params)
{
future.setProgressRange(0, params.projectParts.size() + 1);
future.setProgressValue(0); future.setProgressValue(0);
Core::MessageManager::write( foreach (const ProjectPart::Ptr &projectPart, params.projectParts) {
QLatin1String("updatePchInfo: switching to build system (exact)"),
Core::MessageManager::Silent);
foreach (const ProjectPart::Ptr &projectPart, projectParts) {
if (future.isCanceled()) if (future.isCanceled())
return; return;
if (projectPart->precompiledHeaders.isEmpty()) if (projectPart->precompiledHeaders.isEmpty())
@@ -339,6 +355,7 @@ void PchManager::doPchInfoUpdate(QFutureInterface<void> &future,
QStringList options = Utils::createClangOptions( QStringList options = Utils::createClangOptions(
projectPart, getPrefixFileKind(hasObjC, hasCppFiles(projectPart))); projectPart, getPrefixFileKind(hasObjC, hasCppFiles(projectPart)));
PchManager *pchManager = PchManager::instance();
PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, false); PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, false);
QPair<bool, QStringList> msgs = qMakePair(true, QStringList()); QPair<bool, QStringList> msgs = qMakePair(true, QStringList());
if (pchInfo.isNull()) { if (pchInfo.isNull()) {
@@ -349,19 +366,21 @@ void PchManager::doPchInfoUpdate(QFutureInterface<void> &future,
pchInfo, msgs); pchInfo, msgs);
future.setProgressValue(future.progressValue() + 1); future.setProgressValue(future.progressValue() + 1);
} }
} else if (pchUsage == ClangProjectSettings::PchUse_Custom) {
future.setProgressRange(0, 2); future.setProgressValue(future.progressValue() + 1);
}
void PchManager::doPchInfoUpdateCustom(QFutureInterface<void> &future, const PchManager::UpdateParams &params)
{
future.setProgressRange(0, 1);
future.setProgressValue(0); future.setProgressValue(0);
Core::MessageManager::write(
QLatin1String("updatePchInfo: switching to custom") + customPchFile,
Core::MessageManager::Silent);
QSet<QString> includes, frameworks; QSet<QString> includes, frameworks;
bool objc = false; bool objc = false;
bool cplusplus = false; bool cplusplus = false;
ProjectPart::Ptr united(new ProjectPart()); ProjectPart::Ptr united(new ProjectPart());
united->cxxVersion = ProjectPart::CXX98; united->cxxVersion = ProjectPart::CXX98;
foreach (const ProjectPart::Ptr &projectPart, projectParts) { foreach (const ProjectPart::Ptr &projectPart, params.projectParts) {
includes.unite(QSet<QString>::fromList(projectPart->includePaths)); includes.unite(QSet<QString>::fromList(projectPart->includePaths));
frameworks.unite(QSet<QString>::fromList(projectPart->frameworkPaths)); frameworks.unite(QSet<QString>::fromList(projectPart->frameworkPaths));
united->cVersion = std::max(united->cVersion, projectPart->cVersion); united->cVersion = std::max(united->cVersion, projectPart->cVersion);
@@ -376,19 +395,17 @@ void PchManager::doPchInfoUpdate(QFutureInterface<void> &future,
united, getPrefixFileKind(objc, cplusplus)); united, getPrefixFileKind(objc, cplusplus));
united.clear(); united.clear();
PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(customPchFile, opts, true); PchManager *pchManager = PchManager::instance();
PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(params.customPchFile, opts, true);
QPair<bool, QStringList> msgs = qMakePair(true, QStringList());; QPair<bool, QStringList> msgs = qMakePair(true, QStringList());;
if (future.isCanceled()) if (future.isCanceled())
return; return;
if (pchInfo.isNull()) { if (pchInfo.isNull()) {
pchInfo = PchInfo::createWithFileName(customPchFile, opts, objc); pchInfo = PchInfo::createWithFileName(params.customPchFile, opts, objc);
msgs = precompile(pchInfo); msgs = precompile(pchInfo);
} }
pchManager->setPCHInfo(projectParts, pchInfo, msgs); pchManager->setPCHInfo(params.projectParts, pchInfo, msgs);
future.setProgressValue(1); future.setProgressValue(1);
}
future.setProgressValue(future.progressValue() + 1);
} }
PchInfo::Ptr PchManager::findMatchingPCH(const QString &inputFileName, PchInfo::Ptr PchManager::findMatchingPCH(const QString &inputFileName,

View File

@@ -75,12 +75,21 @@ private slots:
void updateActivePchFiles(); void updateActivePchFiles();
private: private:
struct UpdateParams {
UpdateParams(const QString &customPchFile, const QList<ProjectPart::Ptr> &projectParts)
: customPchFile(customPchFile) , projectParts(projectParts) {}
const QString customPchFile;
const QList<ProjectPart::Ptr> projectParts;
};
void updatePchInfo(ClangProjectSettings *cps, void updatePchInfo(ClangProjectSettings *cps,
const QList<ProjectPart::Ptr> &projectParts); const QList<ProjectPart::Ptr> &projectParts);
static void doPchInfoUpdate(QFutureInterface<void> &future,
ClangProjectSettings::PchUsage pchUsage, static void doPchInfoUpdateNone(QFutureInterface<void> &future, const UpdateParams &params);
const QString customPchFile, static void doPchInfoUpdateFuzzy(QFutureInterface<void> &future, const UpdateParams &params);
const QList<ProjectPart::Ptr> projectParts); static void doPchInfoUpdateExact(QFutureInterface<void> &future, const UpdateParams &params);
static void doPchInfoUpdateCustom(QFutureInterface<void> &future, const UpdateParams &params);
void setPCHInfo(const QList<ProjectPart::Ptr> &projectParts, void setPCHInfo(const QList<ProjectPart::Ptr> &projectParts,
const PchInfo::Ptr &pchInfo, const PchInfo::Ptr &pchInfo,
const QPair<bool, QStringList> &msgs); const QPair<bool, QStringList> &msgs);