make profile cache thread safe

Reviewed-by: thiago
This commit is contained in:
Oswald Buddenhagen
2010-02-26 12:53:30 +01:00
parent 66780cf198
commit e22e8035c6
4 changed files with 119 additions and 46 deletions

View File

@@ -95,6 +95,7 @@ FORMS += makestep.ui \
wizards/testwizardpage.ui wizards/testwizardpage.ui
RESOURCES += qt4projectmanager.qrc \ RESOURCES += qt4projectmanager.qrc \
wizards/wizards.qrc wizards/wizards.qrc
DEFINES += PROPARSER_THREAD_SAFE
include(../../shared/proparser/proparser.pri) include(../../shared/proparser/proparser.pri)
include(qt-s60/qt-s60.pri) include(qt-s60/qt-s60.pri)
include(qt-maemo/qt-maemo.pri) include(qt-maemo/qt-maemo.pri)

View File

@@ -44,6 +44,9 @@
#include <QtCore/QString> #include <QtCore/QString>
#include <QtCore/QStringList> #include <QtCore/QStringList>
#include <QtCore/QTextStream> #include <QtCore/QTextStream>
#ifdef PROPARSER_THREAD_SAFE
# include <QtCore/QThreadPool>
#endif
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
#include <unistd.h> #include <unistd.h>
@@ -94,51 +97,42 @@ static void clearFunctions(ProFileEvaluator::FunctionDefs *defs)
ProFileCache::~ProFileCache() ProFileCache::~ProFileCache()
{ {
foreach (ProFile *pro, parsed_files) foreach (const Entry &ent, parsed_files)
if (pro) if (ent.pro)
pro->deref(); ent.pro->deref();
} }
void ProFileCache::discardFile(const QString &fileName) 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 != parsed_files.end()) {
if (it.value()) if (it->pro)
it.value()->deref(); it->pro->deref();
parsed_files.erase(it); parsed_files.erase(it);
} }
} }
void ProFileCache::discardFiles(const QString &prefix) 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(), it = parsed_files.begin(),
end = parsed_files.end(); end = parsed_files.end();
while (it != end) while (it != end)
if (it.key().startsWith(prefix)) { if (it.key().startsWith(prefix)) {
if (it.value()) if (it->pro)
it.value()->deref(); it->pro->deref();
it = parsed_files.erase(it); it = parsed_files.erase(it);
} else { } else {
++it; ++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 // ProFileOption
@@ -3027,14 +3021,59 @@ ProFile *ProFileEvaluator::Private::parsedProFile(const QString &fileName, bool
const QString &contents) const QString &contents)
{ {
ProFile *pro; 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); pro = new ProFile(fileName);
if (!(contents.isNull() ? read(pro) : read(pro, contents))) { if (!(contents.isNull() ? read(pro) : read(pro, contents))) {
delete pro; delete pro;
pro = 0; pro = 0;
} }
if (m_option->cache && cache)
m_option->cache->addFile(fileName, pro);
} }
return pro; return pro;
} }

View File

@@ -36,27 +36,15 @@
#include <QtCore/QHash> #include <QtCore/QHash>
#include <QtCore/QStringList> #include <QtCore/QStringList>
#include <QtCore/QStack> #include <QtCore/QStack>
#ifdef PROPARSER_THREAD_SAFE
# include <QtCore/QMutex>
# include <QtCore/QWaitCondition>
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
struct ProFileOption; 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 ProFileEvaluator
{ {
class Private; class Private;
@@ -118,6 +106,37 @@ private:
template<typename T> friend class QTypeInfo; template<typename T> friend class QTypeInfo;
friend struct ProFileOption; 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. // This struct is from qmake, but we are not using everything.

View File

@@ -35,6 +35,20 @@
QT_BEGIN_NAMESPACE 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 class ProItem
{ {
public: public:
@@ -95,13 +109,13 @@ public:
ProItem *items() const { return m_proitems; } ProItem *items() const { return m_proitems; }
ProItem **itemsRef() { return &m_proitems; } ProItem **itemsRef() { return &m_proitems; }
void ref() { ++m_refCount; } void ref() { m_refCount.ref(); }
void deref() { if (!--m_refCount) delete this; } void deref() { if (!m_refCount.deref()) delete this; }
private: private:
ProItem *m_proitems; ProItem *m_proitems;
int m_blockKind; int m_blockKind;
int m_refCount; ProItemRefCount m_refCount;
}; };
class ProVariable : public ProItem class ProVariable : public ProItem