forked from qt-creator/qt-creator
make profile cache thread safe
Reviewed-by: thiago
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user