From e22e8035c65d06c61073a88f4e33d68d45b38db1 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen <oswald.buddenhagen@nokia.com> Date: Fri, 26 Feb 2010 12:53:30 +0100 Subject: [PATCH] make profile cache thread safe Reviewed-by: thiago --- .../qt4projectmanager/qt4projectmanager.pro | 1 + src/shared/proparser/profileevaluator.cpp | 93 +++++++++++++------ src/shared/proparser/profileevaluator.h | 51 ++++++---- src/shared/proparser/proitems.h | 20 +++- 4 files changed, 119 insertions(+), 46 deletions(-) diff --git a/src/plugins/qt4projectmanager/qt4projectmanager.pro b/src/plugins/qt4projectmanager/qt4projectmanager.pro index 399ef99b1cc..74aea3cdb5b 100644 --- a/src/plugins/qt4projectmanager/qt4projectmanager.pro +++ b/src/plugins/qt4projectmanager/qt4projectmanager.pro @@ -95,6 +95,7 @@ FORMS += makestep.ui \ wizards/testwizardpage.ui RESOURCES += qt4projectmanager.qrc \ wizards/wizards.qrc +DEFINES += PROPARSER_THREAD_SAFE include(../../shared/proparser/proparser.pri) include(qt-s60/qt-s60.pri) include(qt-maemo/qt-maemo.pri) diff --git a/src/shared/proparser/profileevaluator.cpp b/src/shared/proparser/profileevaluator.cpp index 4ad78d02e4c..57ade55616f 100644 --- a/src/shared/proparser/profileevaluator.cpp +++ b/src/shared/proparser/profileevaluator.cpp @@ -44,6 +44,9 @@ #include <QtCore/QString> #include <QtCore/QStringList> #include <QtCore/QTextStream> +#ifdef PROPARSER_THREAD_SAFE +# include <QtCore/QThreadPool> +#endif #ifdef Q_OS_UNIX #include <unistd.h> @@ -94,51 +97,42 @@ static void clearFunctions(ProFileEvaluator::FunctionDefs *defs) ProFileCache::~ProFileCache() { - foreach (ProFile *pro, parsed_files) - if (pro) - pro->deref(); + foreach (const Entry &ent, parsed_files) + if (ent.pro) + ent.pro->deref(); } void ProFileCache::discardFile(const QString &fileName) { - QHash<QString, ProFile *>::Iterator it = parsed_files.find(fileName); +#ifdef PROPARSER_THREAD_SAFE + QMutexLocker lck(&mutex); +#endif + QHash<QString, Entry>::Iterator it = parsed_files.find(fileName); if (it != parsed_files.end()) { - if (it.value()) - it.value()->deref(); + if (it->pro) + it->pro->deref(); parsed_files.erase(it); } } void ProFileCache::discardFiles(const QString &prefix) { - QHash<QString, ProFile *>::Iterator +#ifdef PROPARSER_THREAD_SAFE + QMutexLocker lck(&mutex); +#endif + QHash<QString, Entry>::Iterator it = parsed_files.begin(), end = parsed_files.end(); while (it != end) if (it.key().startsWith(prefix)) { - if (it.value()) - it.value()->deref(); + if (it->pro) + it->pro->deref(); it = parsed_files.erase(it); } else { ++it; } } -void ProFileCache::addFile(const QString &fileName, ProFile *pro) -{ - parsed_files[fileName] = pro; - if (pro) - pro->ref(); -} - -ProFile *ProFileCache::getFile(const QString &fileName) -{ - ProFile *pro = parsed_files.value(fileName); - if (pro) - pro->ref(); - return pro; -} - /////////////////////////////////////////////////////////////////////// // // ProFileOption @@ -3027,14 +3021,59 @@ ProFile *ProFileEvaluator::Private::parsedProFile(const QString &fileName, bool const QString &contents) { ProFile *pro; - if (!m_option->cache || !(pro = m_option->cache->getFile(fileName))) { + if (cache && m_option->cache) { + ProFileCache::Entry *ent; +#ifdef PROPARSER_THREAD_SAFE + QMutexLocker locker(&m_option->cache->mutex); +#endif + QHash<QString, ProFileCache::Entry>::Iterator it = + m_option->cache->parsed_files.find(fileName); + if (it != m_option->cache->parsed_files.end()) { + ent = &*it; +#ifdef PROPARSER_THREAD_SAFE + if (ent->locker) { + ++ent->locker->waiters; + QThreadPool::globalInstance()->releaseThread(); + ent->locker->cond.wait(locker.mutex()); + QThreadPool::globalInstance()->reserveThread(); + if (!--ent->locker->waiters) { + delete ent->locker; + ent->locker = 0; + } + } +#endif + if ((pro = ent->pro)) + pro->ref(); + } else { + ent = &m_option->cache->parsed_files[fileName]; +#ifdef PROPARSER_THREAD_SAFE + ent->locker = new ProFileCache::Entry::Locker; + locker.unlock(); +#endif + pro = new ProFile(fileName); + if (!(contents.isNull() ? read(pro) : read(pro, contents))) { + delete pro; + pro = 0; + } else { + pro->ref(); + } + ent->pro = pro; +#ifdef PROPARSER_THREAD_SAFE + locker.relock(); + if (ent->locker->waiters) { + ent->locker->cond.wakeAll(); + } else { + delete ent->locker; + ent->locker = 0; + } +#endif + } + } else { pro = new ProFile(fileName); if (!(contents.isNull() ? read(pro) : read(pro, contents))) { delete pro; pro = 0; } - if (m_option->cache && cache) - m_option->cache->addFile(fileName, pro); } return pro; } diff --git a/src/shared/proparser/profileevaluator.h b/src/shared/proparser/profileevaluator.h index 8834d543e8d..d7b6444a7d8 100644 --- a/src/shared/proparser/profileevaluator.h +++ b/src/shared/proparser/profileevaluator.h @@ -36,27 +36,15 @@ #include <QtCore/QHash> #include <QtCore/QStringList> #include <QtCore/QStack> +#ifdef PROPARSER_THREAD_SAFE +# include <QtCore/QMutex> +# include <QtCore/QWaitCondition> +#endif QT_BEGIN_NAMESPACE struct ProFileOption; -class ProFileCache -{ -public: - ProFileCache() {} - ~ProFileCache(); - - void addFile(const QString &fileName, ProFile *pro); - ProFile *getFile(const QString &fileName); - - void discardFile(const QString &fileName); - void discardFiles(const QString &prefix); - -private: - QHash<QString, ProFile *> parsed_files; -}; - class ProFileEvaluator { class Private; @@ -118,6 +106,37 @@ private: template<typename T> friend class QTypeInfo; friend struct ProFileOption; + friend class ProFileCache; +}; + +class ProFileCache +{ +public: + ProFileCache() {} + ~ProFileCache(); + + void discardFile(const QString &fileName); + void discardFiles(const QString &prefix); + +private: + struct Entry { + ProFile *pro; +#ifdef PROPARSER_THREAD_SAFE + struct Locker { + Locker() : waiters(0) {} + QWaitCondition cond; + int waiters; + }; + Locker *locker; +#endif + }; + + QHash<QString, Entry> parsed_files; +#ifdef PROPARSER_THREAD_SAFE + QMutex mutex; +#endif + + friend class ProFileEvaluator::Private; }; // This struct is from qmake, but we are not using everything. diff --git a/src/shared/proparser/proitems.h b/src/shared/proparser/proitems.h index 46d085f066f..108e1080963 100644 --- a/src/shared/proparser/proitems.h +++ b/src/shared/proparser/proitems.h @@ -35,6 +35,20 @@ QT_BEGIN_NAMESPACE +#ifdef PROPARSER_THREAD_SAFE +typedef QAtomicInt ProItemRefCount; +#else +class ProItemRefCount { +public: + ProItemRefCount() : m_cnt(0) {} + bool ref() { return ++m_cnt != 0; } + bool deref() { return --m_cnt != 0; } + ProItemRefCount &operator=(int value) { m_cnt = value; return *this; } +private: + int m_cnt; +}; +#endif + class ProItem { public: @@ -95,13 +109,13 @@ public: ProItem *items() const { return m_proitems; } ProItem **itemsRef() { return &m_proitems; } - void ref() { ++m_refCount; } - void deref() { if (!--m_refCount) delete this; } + void ref() { m_refCount.ref(); } + void deref() { if (!m_refCount.deref()) delete this; } private: ProItem *m_proitems; int m_blockKind; - int m_refCount; + ProItemRefCount m_refCount; }; class ProVariable : public ProItem -- GitLab