summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikolai Kosjar <nikolai.kosjar@digia.com>2014-03-04 15:01:57 -0300
committerNikolai Kosjar <nikolai.kosjar@digia.com>2014-03-05 13:16:27 +0100
commita723205f6c857290b56a0dbce3ee2bde85984474 (patch)
tree291a31bb375850775b869cf5ee71ebab813df348
parentcb66d1ec23dfb5313a6bad5bbb9bd398381dde83 (diff)
downloadqt-creator-a723205f6c857290b56a0dbce3ee2bde85984474.tar.gz
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>
-rw-r--r--src/plugins/clangcodemodel/pchmanager.cpp333
-rw-r--r--src/plugins/clangcodemodel/pchmanager.h17
2 files changed, 188 insertions, 162 deletions
diff --git a/src/plugins/clangcodemodel/pchmanager.cpp b/src/plugins/clangcodemodel/pchmanager.cpp
index dd81ebf94b..295cf4fc4e 100644
--- a/src/plugins/clangcodemodel/pchmanager.cpp
+++ b/src/plugins/clangcodemodel/pchmanager.cpp
@@ -34,6 +34,7 @@
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
+#include <utils/qtcassert.h>
#include <utils/runextensions.h>
#include <QFile>
@@ -153,14 +154,36 @@ void PchManager::updatePchInfo(ClangProjectSettings *cps,
const QList<ProjectPart::Ptr> &projectParts)
{
if (m_pchGenerationWatcher.isRunning()) {
-// m_pchGenerationWatcher.cancel();
m_pchGenerationWatcher.waitForFinished();
}
- QFuture<void> future = QtConcurrent::run(&PchManager::doPchInfoUpdate,
- cps->pchUsage(),
- cps->customPchFile(),
- projectParts);
+ const QString customPchFile = cps->customPchFile();
+ const ClangProjectSettings::PchUsage pchUsage = cps->pchUsage();
+
+ 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);
Core::ProgressManager::addTask(future, tr("Precompiling..."), "Key.Tmp.Precompiling");
}
@@ -214,183 +237,177 @@ CppTools::ProjectFile::Kind getPrefixFileKind(bool hasObjectiveC, bool hasCPlusP
}
-void PchManager::doPchInfoUpdate(QFutureInterface<void> &future,
- ClangProjectSettings::PchUsage pchUsage,
- const QString customPchFile,
- const QList<ProjectPart::Ptr> projectParts)
+void PchManager::doPchInfoUpdateNone(QFutureInterface<void> &future, const PchManager::UpdateParams &params)
{
- PchManager *pchManager = PchManager::instance();
+ future.setProgressRange(0, 1);
+ PchInfo::Ptr emptyPch = PchInfo::createEmpty();
+ PchManager::instance()->setPCHInfo(params.projectParts, emptyPch,
+ qMakePair(true, QStringList()));
+ future.setProgressValue(1);
+}
-// qDebug() << "switching to" << pchUsage;
+void PchManager::doPchInfoUpdateFuzzy(QFutureInterface<void> &future, const PchManager::UpdateParams &params)
+{
+ QHash<QString, QSet<QString> > includes, frameworks;
+ QHash<QString, QSet<QByteArray> > definesPerPCH;
+ QHash<QString, bool> objc;
+ QHash<QString, bool> cplusplus;
+ QHash<QString, ProjectPart::QtVersion> qtVersions;
+ QHash<QString, ProjectPart::CVersion> cVersions;
+ QHash<QString, ProjectPart::CXXVersion> cxxVersions;
+ QHash<QString, ProjectPart::CXXExtensions> cxxExtensionsMap;
+ QHash<QString, QList<ProjectPart::Ptr> > inputToParts;
+ foreach (const ProjectPart::Ptr &projectPart, params.projectParts) {
+ if (projectPart->precompiledHeaders.isEmpty())
+ continue;
+ const QString &pch = projectPart->precompiledHeaders.first(); // TODO: support more than 1 PCH file.
+ if (!QFile(pch).exists())
+ continue;
+ inputToParts[pch].append(projectPart);
+
+ includes[pch].unite(QSet<QString>::fromList(projectPart->includePaths));
+ frameworks[pch].unite(QSet<QString>::fromList(projectPart->frameworkPaths));
+ cVersions[pch] = std::max(cVersions.value(pch, ProjectPart::C89), projectPart->cVersion);
+ cxxVersions[pch] = std::max(cxxVersions.value(pch, ProjectPart::CXX98), projectPart->cxxVersion);
+ cxxExtensionsMap[pch] = cxxExtensionsMap[pch] | projectPart->cxxExtensions;
+
+ if (hasObjCFiles(projectPart))
+ objc[pch] = true;
+ if (hasCppFiles(projectPart))
+ cplusplus[pch] = true;
+
+ QSet<QByteArray> projectDefines = QSet<QByteArray>::fromList(projectPart->toolchainDefines.split('\n'));
+ QMutableSetIterator<QByteArray> iter(projectDefines);
+ while (iter.hasNext()){
+ QByteArray v = iter.next();
+ if (v.startsWith("#define _") || v.isEmpty()) // TODO: see ProjectPart::createClangOptions
+ iter.remove();
+ }
+ projectDefines.unite(QSet<QByteArray>::fromList(projectPart->projectDefines.split('\n')));
- 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();
- pchManager->setPCHInfo(projectParts, emptyPch, qMakePair(true, QStringList()));
- future.setProgressValue(1);
- } else if (pchUsage == ClangProjectSettings::PchUse_BuildSystem_Fuzzy) {
- Core::MessageManager::write(
- QLatin1String("updatePchInfo: switching to build system (fuzzy)"),
- Core::MessageManager::Silent);
- QHash<QString, QSet<QString> > includes, frameworks;
- QHash<QString, QSet<QByteArray> > definesPerPCH;
- QHash<QString, bool> objc;
- QHash<QString, bool> cplusplus;
- QHash<QString, ProjectPart::QtVersion> qtVersions;
- QHash<QString, ProjectPart::CVersion> cVersions;
- QHash<QString, ProjectPart::CXXVersion> cxxVersions;
- QHash<QString, ProjectPart::CXXExtensions> cxxExtensionsMap;
- QHash<QString, QList<ProjectPart::Ptr> > inputToParts;
- foreach (const ProjectPart::Ptr &projectPart, projectParts) {
- if (projectPart->precompiledHeaders.isEmpty())
- continue;
- const QString &pch = projectPart->precompiledHeaders.first(); // TODO: support more than 1 PCH file.
- if (!QFile(pch).exists())
- continue;
- inputToParts[pch].append(projectPart);
-
- includes[pch].unite(QSet<QString>::fromList(projectPart->includePaths));
- frameworks[pch].unite(QSet<QString>::fromList(projectPart->frameworkPaths));
- cVersions[pch] = std::max(cVersions.value(pch, ProjectPart::C89), projectPart->cVersion);
- cxxVersions[pch] = std::max(cxxVersions.value(pch, ProjectPart::CXX98), projectPart->cxxVersion);
- cxxExtensionsMap[pch] = cxxExtensionsMap[pch] | projectPart->cxxExtensions;
-
- if (hasObjCFiles(projectPart))
- objc[pch] = true;
- if (hasCppFiles(projectPart))
- cplusplus[pch] = true;
-
- QSet<QByteArray> projectDefines = QSet<QByteArray>::fromList(projectPart->toolchainDefines.split('\n'));
- QMutableSetIterator<QByteArray> iter(projectDefines);
- while (iter.hasNext()){
- QByteArray v = iter.next();
- if (v.startsWith("#define _") || v.isEmpty()) // TODO: see ProjectPart::createClangOptions
- iter.remove();
- }
- projectDefines.unite(QSet<QByteArray>::fromList(projectPart->projectDefines.split('\n')));
+ if (definesPerPCH.contains(pch)) {
+ definesPerPCH[pch].intersect(projectDefines);
+ } else {
+ definesPerPCH[pch] = projectDefines;
+ }
- if (definesPerPCH.contains(pch)) {
- definesPerPCH[pch].intersect(projectDefines);
- } else {
- definesPerPCH[pch] = projectDefines;
- }
+ qtVersions[pch] = projectPart->qtVersion;
+ }
- qtVersions[pch] = projectPart->qtVersion;
- }
+ future.setProgressRange(0, definesPerPCH.size() + 1);
+ future.setProgressValue(0);
- future.setProgressRange(0, definesPerPCH.size() + 1);
- future.setProgressValue(0);
-
- foreach (const QString &pch, inputToParts.keys()) {
- if (future.isCanceled())
- return;
- ProjectPart::Ptr projectPart(new ProjectPart);
- projectPart->qtVersion = qtVersions[pch];
- projectPart->cVersion = cVersions[pch];
- projectPart->cxxVersion = cxxVersions[pch];
- projectPart->cxxExtensions = cxxExtensionsMap[pch];
- projectPart->includePaths = includes[pch].toList();
- projectPart->frameworkPaths = frameworks[pch].toList();
-
- QList<QByteArray> defines = definesPerPCH[pch].toList();
- if (!defines.isEmpty()) {
- projectPart->projectDefines = defines[0];
- for (int i = 1; i < defines.size(); ++i) {
- projectPart->projectDefines += '\n';
- projectPart->projectDefines += defines[i];
- }
+ foreach (const QString &pch, inputToParts.keys()) {
+ if (future.isCanceled())
+ return;
+ ProjectPart::Ptr projectPart(new ProjectPart);
+ projectPart->qtVersion = qtVersions[pch];
+ projectPart->cVersion = cVersions[pch];
+ projectPart->cxxVersion = cxxVersions[pch];
+ projectPart->cxxExtensions = cxxExtensionsMap[pch];
+ projectPart->includePaths = includes[pch].toList();
+ projectPart->frameworkPaths = frameworks[pch].toList();
+
+ QList<QByteArray> defines = definesPerPCH[pch].toList();
+ if (!defines.isEmpty()) {
+ projectPart->projectDefines = defines[0];
+ for (int i = 1; i < defines.size(); ++i) {
+ projectPart->projectDefines += '\n';
+ projectPart->projectDefines += defines[i];
}
+ }
- CppTools::ProjectFile::Kind prefixFileKind =
- getPrefixFileKind(objc.value(pch, false), cplusplus.value(pch, false));
+ CppTools::ProjectFile::Kind prefixFileKind =
+ getPrefixFileKind(objc.value(pch, false), cplusplus.value(pch, false));
- QStringList options = Utils::createClangOptions(projectPart, prefixFileKind);
- projectPart.reset();
+ QStringList options = Utils::createClangOptions(projectPart, prefixFileKind);
+ projectPart.reset();
- PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, true);
- QPair<bool, QStringList> msgs = qMakePair(true, QStringList());
- if (pchInfo.isNull()) {
+ PchManager *pchManager = PchManager::instance();
+ PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, true);
+ QPair<bool, QStringList> msgs = qMakePair(true, QStringList());
+ if (pchInfo.isNull()) {
- pchInfo = PchInfo::createWithFileName(pch, options, objc[pch]);
- msgs = precompile(pchInfo);
- }
- pchManager->setPCHInfo(inputToParts[pch], pchInfo, msgs);
- future.setProgressValue(future.progressValue() + 1);
+ pchInfo = PchInfo::createWithFileName(pch, options, objc[pch]);
+ msgs = precompile(pchInfo);
}
- } else if (pchUsage == ClangProjectSettings::PchUse_BuildSystem_Exact) {
- future.setProgressRange(0, projectParts.size() + 1);
- future.setProgressValue(0);
- Core::MessageManager::write(
- QLatin1String("updatePchInfo: switching to build system (exact)"),
- Core::MessageManager::Silent);
- foreach (const ProjectPart::Ptr &projectPart, projectParts) {
- if (future.isCanceled())
- return;
- if (projectPart->precompiledHeaders.isEmpty())
- continue;
- const QString &pch = projectPart->precompiledHeaders.first(); // TODO: support more than 1 PCH file.
- if (!QFile(pch).exists())
- continue;
+ pchManager->setPCHInfo(inputToParts[pch], pchInfo, msgs);
+ future.setProgressValue(future.progressValue() + 1);
+ }
- const bool hasObjC = hasObjCFiles(projectPart);
- QStringList options = Utils::createClangOptions(
- projectPart, getPrefixFileKind(hasObjC, hasCppFiles(projectPart)));
+ future.setProgressValue(future.progressValue() + 1);
+}
- PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, false);
- QPair<bool, QStringList> msgs = qMakePair(true, QStringList());
- if (pchInfo.isNull()) {
- pchInfo = PchInfo::createWithFileName(pch, options, hasObjC);
- msgs = precompile(pchInfo);
- }
- pchManager->setPCHInfo(QList<ProjectPart::Ptr>() << projectPart,
- pchInfo, msgs);
- future.setProgressValue(future.progressValue() + 1);
- }
- } else if (pchUsage == ClangProjectSettings::PchUse_Custom) {
- future.setProgressRange(0, 2);
- future.setProgressValue(0);
- Core::MessageManager::write(
- QLatin1String("updatePchInfo: switching to custom") + customPchFile,
- Core::MessageManager::Silent);
-
- QSet<QString> includes, frameworks;
- bool objc = false;
- bool cplusplus = false;
- ProjectPart::Ptr united(new ProjectPart());
- united->cxxVersion = ProjectPart::CXX98;
- foreach (const ProjectPart::Ptr &projectPart, projectParts) {
- includes.unite(QSet<QString>::fromList(projectPart->includePaths));
- frameworks.unite(QSet<QString>::fromList(projectPart->frameworkPaths));
- united->cVersion = std::max(united->cVersion, projectPart->cVersion);
- united->cxxVersion = std::max(united->cxxVersion, projectPart->cxxVersion);
- united->qtVersion = std::max(united->qtVersion, projectPart->qtVersion);
- objc |= hasObjCFiles(projectPart);
- cplusplus |= hasCppFiles(projectPart);
- }
- united->frameworkPaths = frameworks.toList();
- united->includePaths = includes.toList();
- QStringList opts = Utils::createClangOptions(
- united, getPrefixFileKind(objc, cplusplus));
- united.clear();
-
- PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(customPchFile, opts, true);
- QPair<bool, QStringList> msgs = qMakePair(true, QStringList());;
+void PchManager::doPchInfoUpdateExact(QFutureInterface<void> &future, const PchManager::UpdateParams &params)
+{
+ future.setProgressRange(0, params.projectParts.size() + 1);
+ future.setProgressValue(0);
+ foreach (const ProjectPart::Ptr &projectPart, params.projectParts) {
if (future.isCanceled())
return;
+ if (projectPart->precompiledHeaders.isEmpty())
+ continue;
+ const QString &pch = projectPart->precompiledHeaders.first(); // TODO: support more than 1 PCH file.
+ if (!QFile(pch).exists())
+ continue;
+
+ const bool hasObjC = hasObjCFiles(projectPart);
+ QStringList options = Utils::createClangOptions(
+ projectPart, getPrefixFileKind(hasObjC, hasCppFiles(projectPart)));
+
+ PchManager *pchManager = PchManager::instance();
+ PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(pch, options, false);
+ QPair<bool, QStringList> msgs = qMakePair(true, QStringList());
if (pchInfo.isNull()) {
- pchInfo = PchInfo::createWithFileName(customPchFile, opts, objc);
+ pchInfo = PchInfo::createWithFileName(pch, options, hasObjC);
msgs = precompile(pchInfo);
}
- pchManager->setPCHInfo(projectParts, pchInfo, msgs);
- future.setProgressValue(1);
+ pchManager->setPCHInfo(QList<ProjectPart::Ptr>() << projectPart,
+ pchInfo, msgs);
+ future.setProgressValue(future.progressValue() + 1);
}
future.setProgressValue(future.progressValue() + 1);
}
+void PchManager::doPchInfoUpdateCustom(QFutureInterface<void> &future, const PchManager::UpdateParams &params)
+{
+ future.setProgressRange(0, 1);
+ future.setProgressValue(0);
+
+ QSet<QString> includes, frameworks;
+ bool objc = false;
+ bool cplusplus = false;
+ ProjectPart::Ptr united(new ProjectPart());
+ united->cxxVersion = ProjectPart::CXX98;
+ foreach (const ProjectPart::Ptr &projectPart, params.projectParts) {
+ includes.unite(QSet<QString>::fromList(projectPart->includePaths));
+ frameworks.unite(QSet<QString>::fromList(projectPart->frameworkPaths));
+ united->cVersion = std::max(united->cVersion, projectPart->cVersion);
+ united->cxxVersion = std::max(united->cxxVersion, projectPart->cxxVersion);
+ united->qtVersion = std::max(united->qtVersion, projectPart->qtVersion);
+ objc |= hasObjCFiles(projectPart);
+ cplusplus |= hasCppFiles(projectPart);
+ }
+ united->frameworkPaths = frameworks.toList();
+ united->includePaths = includes.toList();
+ QStringList opts = Utils::createClangOptions(
+ united, getPrefixFileKind(objc, cplusplus));
+ united.clear();
+
+ PchManager *pchManager = PchManager::instance();
+ PchInfo::Ptr pchInfo = pchManager->findMatchingPCH(params.customPchFile, opts, true);
+ QPair<bool, QStringList> msgs = qMakePair(true, QStringList());;
+ if (future.isCanceled())
+ return;
+ if (pchInfo.isNull()) {
+ pchInfo = PchInfo::createWithFileName(params.customPchFile, opts, objc);
+ msgs = precompile(pchInfo);
+ }
+ pchManager->setPCHInfo(params.projectParts, pchInfo, msgs);
+ future.setProgressValue(1);
+}
+
PchInfo::Ptr PchManager::findMatchingPCH(const QString &inputFileName,
const QStringList &options,
bool fuzzyMatching) const
diff --git a/src/plugins/clangcodemodel/pchmanager.h b/src/plugins/clangcodemodel/pchmanager.h
index 2c79554dc0..263258f916 100644
--- a/src/plugins/clangcodemodel/pchmanager.h
+++ b/src/plugins/clangcodemodel/pchmanager.h
@@ -75,12 +75,21 @@ private slots:
void updateActivePchFiles();
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,
const QList<ProjectPart::Ptr> &projectParts);
- static void doPchInfoUpdate(QFutureInterface<void> &future,
- ClangProjectSettings::PchUsage pchUsage,
- const QString customPchFile,
- const QList<ProjectPart::Ptr> projectParts);
+
+ static void doPchInfoUpdateNone(QFutureInterface<void> &future, const UpdateParams &params);
+ static void doPchInfoUpdateFuzzy(QFutureInterface<void> &future, const UpdateParams &params);
+ 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,
const PchInfo::Ptr &pchInfo,
const QPair<bool, QStringList> &msgs);