From 7d3d9cad322b7a92e139878dbcc127dab90efaf0 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Mon, 22 Feb 2010 16:00:47 +0100
Subject: [PATCH] Fix code model indexing crash on Mac.

Introduce multithread-locking to Core::MimeDatabase as it is
invoked from the indexer thread to sort apart headers and sources.
Add a convenience to operate on a sequence to avoid locking for each
file.
---
 src/plugins/coreplugin/mimedatabase.cpp  | 50 ++++++++++++----
 src/plugins/coreplugin/mimedatabase.h    | 24 +++++++-
 src/plugins/cpptools/cppmodelmanager.cpp | 72 +++++++++++++++---------
 3 files changed, 108 insertions(+), 38 deletions(-)

diff --git a/src/plugins/coreplugin/mimedatabase.cpp b/src/plugins/coreplugin/mimedatabase.cpp
index b39eed15183..155fc75544c 100644
--- a/src/plugins/coreplugin/mimedatabase.cpp
+++ b/src/plugins/coreplugin/mimedatabase.cpp
@@ -44,6 +44,7 @@
 #include <QtCore/QSharedPointer>
 #include <QtCore/QStringList>
 #include <QtCore/QTextStream>
+#include <QtCore/QMutexLocker>
 
 #include <QtXml/QXmlStreamReader>
 
@@ -1125,56 +1126,85 @@ MimeDatabase::~MimeDatabase()
 
 MimeType MimeDatabase::findByType(const QString &typeOrAlias) const
 {
-    return m_d->findByType(typeOrAlias);
+    m_mutex.lock();
+    const MimeType rc = m_d->findByType(typeOrAlias);
+    m_mutex.unlock();
+    return rc;
 }
 
-MimeType MimeDatabase::findByFile(const QFileInfo &f) const
+MimeType MimeDatabase::findByFileUnlocked(const QFileInfo &f) const
 {
     return m_d->findByFile(f);
 }
 
+MimeType MimeDatabase::findByFile(const QFileInfo &f) const
+{
+    m_mutex.lock();
+    const MimeType rc = findByFileUnlocked(f);
+    m_mutex.unlock();
+    return rc;
+}
+
 bool MimeDatabase::addMimeType(const  MimeType &mt)
 {
-    return m_d->addMimeType(mt);
+    m_mutex.lock();
+    const bool rc = m_d->addMimeType(mt);
+    m_mutex.unlock();
+    return rc;
 }
 
 bool MimeDatabase::addMimeTypes(const QString &fileName, QString *errorMessage)
 {
-    return m_d->addMimeTypes(fileName, errorMessage);
+    m_mutex.lock();
+    const bool rc = m_d->addMimeTypes(fileName, errorMessage);
+    m_mutex.unlock();
+    return rc;
 }
 
 bool MimeDatabase::addMimeTypes(QIODevice *device, QString *errorMessage)
 {
-    return m_d->addMimeTypes(device, errorMessage);
+    m_mutex.lock();
+    const bool rc = m_d->addMimeTypes(device, errorMessage);
+    m_mutex.unlock();
+    return rc;
 }
 
 QStringList MimeDatabase::suffixes() const
 {
-    return m_d->suffixes();
+    m_mutex.lock();
+    const QStringList rc = m_d->suffixes();
+    m_mutex.unlock();
+    return rc;
 }
 
 QStringList MimeDatabase::filterStrings() const
 {
-    return m_d->filterStrings();
+    m_mutex.lock();
+    const  QStringList rc = m_d->filterStrings();
+    m_mutex.unlock();
+    return rc;
 }
 
 QString MimeDatabase::preferredSuffixByType(const QString &type) const
 {
     if (const MimeType mt = findByType(type))
-        return mt.preferredSuffix();
+        return mt.preferredSuffix(); // already does Mutex locking
     return QString();
 }
 
 QString MimeDatabase::preferredSuffixByFile(const QFileInfo &f) const
 {
     if (const MimeType mt = findByFile(f))
-        return mt.preferredSuffix();
+        return mt.preferredSuffix(); // already does Mutex locking
     return QString();
 }
 
 bool MimeDatabase::setPreferredSuffix(const QString &typeOrAlias, const QString &suffix)
 {
-    return m_d->setPreferredSuffix(typeOrAlias, suffix);
+    m_mutex.lock();
+    const bool rc = m_d->setPreferredSuffix(typeOrAlias, suffix);
+    m_mutex.unlock();
+    return rc;
 }
 
 QDebug operator<<(QDebug d, const MimeDatabase &mt)
diff --git a/src/plugins/coreplugin/mimedatabase.h b/src/plugins/coreplugin/mimedatabase.h
index ed932a69c9c..a7397e6384d 100644
--- a/src/plugins/coreplugin/mimedatabase.h
+++ b/src/plugins/coreplugin/mimedatabase.h
@@ -35,6 +35,7 @@
 #include <QtCore/QSharedDataPointer>
 #include <QtCore/QSharedPointer>
 #include <QtCore/QByteArray>
+#include <QtCore/QMutex>
 
 QT_BEGIN_NAMESPACE
 class QIODevice;
@@ -186,7 +187,7 @@ private:
 /* A Mime data base to which the plugins can add the mime types they handle.
  * When adding a "text/plain" to it, the mimetype will receive a magic matcher
  * that checks for text files that do not match the globs by heuristics.
- *
+ * The class is protected by a QMutex and can therefore be accessed by threads.
  * A good testcase is to run it over '/usr/share/mime/<*>/<*>.xml' on Linux. */
 
 class CORE_EXPORT MimeDatabase
@@ -203,8 +204,15 @@ public:
 
     // Returns a mime type or Null one if none found
     MimeType findByType(const QString &type) const;
+
     // Returns a mime type or Null one if none found
     MimeType findByFile(const QFileInfo &f) const;
+    // Convenience that mutex-locks the DB and calls a function
+    // of the signature 'void f(const MimeType &, const QFileInfo &, const QString &)'
+    // for each filename of a sequence. This avoids locking the DB for each
+    // single file.
+    template <class Iterator, typename Function>
+        inline void findByFile(Iterator i1, const Iterator &i2, Function f) const;
 
     // Convenience
     QString preferredSuffixByType(const QString &type) const;
@@ -219,9 +227,23 @@ public:
     friend QDebug operator<<(QDebug d, const MimeDatabase &mt);
 
 private:
+    MimeType findByFileUnlocked(const QFileInfo &f) const;
+
     MimeDatabasePrivate *m_d;
+    mutable QMutex m_mutex;
 };
 
+template <class Iterator, typename Function>
+    void MimeDatabase::findByFile(Iterator i1, const Iterator &i2, Function f) const
+{
+    m_mutex.lock();
+    for ( ; i1 != i2; ++i1) {
+        const QFileInfo fi(*i1);
+        f(findByFileUnlocked(fi), fi, *i1);
+    }
+    m_mutex.unlock();
+}
+
 } // namespace Core
 
 #endif // MIMEDATABASE_H
diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp
index ffd8fdb0790..5d193738be5 100644
--- a/src/plugins/cpptools/cppmodelmanager.cpp
+++ b/src/plugins/cpptools/cppmodelmanager.cpp
@@ -1227,6 +1227,41 @@ void CppModelManager::updateIncludesInPaths(QFutureInterface<void> &future,
     future.reportFinished();
 }
 
+// Function that sorts headers and sources apart to be used for
+// MimeDB::findByFile() on a sequence of file names.
+class HeaderSourceSorter {
+public:
+    explicit HeaderSourceSorter(QStringList *sources, QStringList *headers);
+    void operator()(const Core::MimeType &, const QFileInfo &, const QString &);
+
+private:
+    QStringList m_sourceMimeTypes;
+    QStringList m_headerMimeTypes;
+
+    QStringList *m_sources;
+    QStringList *m_headers;
+};
+
+HeaderSourceSorter::HeaderSourceSorter(QStringList *sources, QStringList *headers) :
+        m_sources(sources),
+        m_headers(headers)
+{
+    m_headerMimeTypes << QLatin1String("text/x-hdr") << QLatin1String("text/x-c++hdr");
+    m_sourceMimeTypes << QLatin1String("text/x-csrc") << QLatin1String("text/x-c++src")
+                      << QLatin1String("text/x-objcsrc");
+}
+
+void HeaderSourceSorter::operator()(const Core::MimeType &mimeType, const QFileInfo &, const QString &name)
+{
+    if (mimeType) {
+        if (m_sourceMimeTypes.contains(mimeType.type())) {
+            m_sources->append(name);
+        } else if (m_headerMimeTypes.contains(mimeType.type())) {
+            m_headers->append(name);
+        }
+    }
+}
+
 void CppModelManager::parse(QFutureInterface<void> &future,
                             CppPreprocessor *preproc,
                             QStringList files)
@@ -1234,31 +1269,17 @@ void CppModelManager::parse(QFutureInterface<void> &future,
     if (files.isEmpty())
         return;
 
-    Core::MimeDatabase *db = Core::ICore::instance()->mimeDatabase();
-    QStringList headers, sources;
-    Core::MimeType cSourceTy = db->findByType(QLatin1String("text/x-csrc"));
-    Core::MimeType cppSourceTy = db->findByType(QLatin1String("text/x-c++src"));
-    Core::MimeType mSourceTy = db->findByType(QLatin1String("text/x-objcsrc"));
-
-    Core::MimeType cHeaderTy = db->findByType(QLatin1String("text/x-hdr"));
-    Core::MimeType cppHeaderTy = db->findByType(QLatin1String("text/x-c++hdr"));
-
-    foreach (const QString &file, files) {
-        const QFileInfo fileInfo(file);
-
-        if (cSourceTy.matchesFile(fileInfo) || cppSourceTy.matchesFile(fileInfo) || mSourceTy.matchesFile(fileInfo))
-            sources.append(file);
-
-        else if (cHeaderTy.matchesFile(fileInfo) || cppHeaderTy.matchesFile(fileInfo))
-            headers.append(file);
-    }
-
-    foreach (const QString &file, files) {
-        preproc->snapshot.remove(file);
-    }
+    QStringList sources;
+    QStringList headers;
+    const Core::MimeDatabase *mimeDb = Core::ICore::instance()->mimeDatabase();
+    mimeDb->findByFile(files.constBegin(), files.constEnd(),
+                       HeaderSourceSorter(&sources, &headers));
 
+    const int sourceCount = sources.size();
     files = sources;
     files += headers;
+    foreach (const QString &file, files)
+        preproc->snapshot.remove(file);
 
     preproc->setTodo(files);
 
@@ -1278,12 +1299,9 @@ void CppModelManager::parse(QFutureInterface<void> &future,
         // Change the priority of the background parser thread to idle.
         QThread::currentThread()->setPriority(QThread::IdlePriority);
 
-        QString fileName = files.at(i);
-
-        bool isSourceFile = false;
-        if (cppSourceTy.matchesFile(fileName) || cSourceTy.matchesFile(fileName))
-            isSourceFile = true;
+        const QString fileName = files.at(i);
 
+        const bool isSourceFile = i < sourceCount;
         if (isSourceFile)
             (void) preproc->run(conf);
 
-- 
GitLab