Make KSharedConfig thread-safe

... by having a different list of shareable objects per thread.

REVIEW: 118739
wilder
David Faure 12 years ago
parent e782f0adc9
commit fdbcede38d
  1. 28
      src/core/ksharedconfig.cpp
  2. 8
      src/core/ksharedconfig.h

@ -24,6 +24,8 @@
#include "kconfiggroup.h" #include "kconfiggroup.h"
#include "kconfig_p.h" #include "kconfig_p.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QThread>
#include <QThreadStorage>
void _k_globalMainConfigSync(); void _k_globalMainConfigSync();
@ -32,24 +34,38 @@ class GlobalSharedConfigList : public QList<KSharedConfig *>
public: public:
GlobalSharedConfigList() GlobalSharedConfigList()
{ {
if (!qApp || QThread::currentThread() == qApp->thread()) {
// We want to force the sync() before the QCoreApplication // We want to force the sync() before the QCoreApplication
// instance is gone. Otherwise we trigger a QLockFile::lock() // instance is gone. Otherwise we trigger a QLockFile::lock()
// after QCoreApplication is gone, calling qAppName() for a non // after QCoreApplication is gone, calling qAppName() for a non
// existent app... // existent app...
qAddPostRoutine(&_k_globalMainConfigSync); qAddPostRoutine(&_k_globalMainConfigSync);
} }
}
// in addition to the list, we need to hold the main config, // in addition to the list, we need to hold the main config,
// so that it's not created and destroyed all the time. // so that it's not created and destroyed all the time.
KSharedConfigPtr mainConfig; KSharedConfigPtr mainConfig;
}; };
Q_GLOBAL_STATIC(GlobalSharedConfigList, globalSharedConfigList) static QThreadStorage<GlobalSharedConfigList *> s_storage;
template <typename T>
T * perThreadGlobalStatic()
{
if (!s_storage.hasLocalData()) {
s_storage.setLocalData(new T);
}
return s_storage.localData();
};
// Q_GLOBAL_STATIC(GlobalSharedConfigList, globalSharedConfigList), but per thread:
static GlobalSharedConfigList *globalSharedConfigList() { return perThreadGlobalStatic<GlobalSharedConfigList>(); }
void _k_globalMainConfigSync() void _k_globalMainConfigSync()
{ {
if (globalSharedConfigList->mainConfig) { KSharedConfigPtr mainConfig = globalSharedConfigList()->mainConfig;
globalSharedConfigList->mainConfig->sync(); if (mainConfig) {
mainConfig->sync();
} }
} }
@ -64,7 +80,7 @@ KSharedConfigPtr KSharedConfig::openConfig(const QString &_fileName,
fileName = KConfig::mainConfigName(); fileName = KConfig::mainConfigName();
} }
static bool wasTestModeEnabled = false; static QBasicAtomicInt wasTestModeEnabled = Q_BASIC_ATOMIC_INITIALIZER(false);
if (!wasTestModeEnabled && QStandardPaths::isTestModeEnabled()) { if (!wasTestModeEnabled && QStandardPaths::isTestModeEnabled()) {
wasTestModeEnabled = true; wasTestModeEnabled = true;
list->clear(); list->clear();
@ -86,7 +102,7 @@ KSharedConfigPtr KSharedConfig::openConfig(const QString &_fileName,
if (_fileName.isEmpty() && flags == FullConfig && resType == QStandardPaths::GenericConfigLocation) { if (_fileName.isEmpty() && flags == FullConfig && resType == QStandardPaths::GenericConfigLocation) {
list->mainConfig = ptr; list->mainConfig = ptr;
static bool userWarned = false; static QBasicAtomicInt userWarned = Q_BASIC_ATOMIC_INITIALIZER(false);
if (!userWarned) { if (!userWarned) {
userWarned = true; userWarned = true;
QByteArray readOnly = qgetenv("KDE_HOME_READONLY"); QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
@ -111,7 +127,7 @@ KSharedConfig::KSharedConfig(const QString &fileName,
KSharedConfig::~KSharedConfig() KSharedConfig::~KSharedConfig()
{ {
if (!globalSharedConfigList.isDestroyed()) { if (s_storage.hasLocalData()) {
globalSharedConfigList()->removeAll(this); globalSharedConfigList()->removeAll(this);
} }
} }

@ -30,12 +30,16 @@
* *
* KConfig variant using shared memory * KConfig variant using shared memory
* *
* KSharedConfig provides a reference counted, shared memory variant * KSharedConfig provides a shared (reference counted) variant
* of KConfig. This allows you to use manipulate the same configuration * of KConfig. This allows you to use manipulate the same configuration
* files from different places in your code without worrying about * files from different places in your code without worrying about
* accidentally overwriting changes. * accidentally overwriting changes.
* *
* Note that, as with most of kdelibs, this is @b NOT threadsafe. * The openConfig() method is threadsafe: every thread gets a separate repository
* of shared KConfig objects. This means, however, that you'll be responsible for
* synchronizing the instances of KConfig for the same filename between threads,
* using reparseConfiguration after a manual change notification, just like you have
* to do between processes.
*/ */
class KCONFIGCORE_EXPORT KSharedConfig : public KConfig, public QSharedData //krazy:exclude=dpointer (only for refcounting) class KCONFIGCORE_EXPORT KSharedConfig : public KConfig, public QSharedData //krazy:exclude=dpointer (only for refcounting)
{ {

Loading…
Cancel
Save