diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2019-08-12 17:35:45 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2019-08-12 17:35:45 -0400 |
commit | 4fce6dc4353dbf9ccd3c9c3aced89df72a4f3abd (patch) | |
tree | 818dfbed3ede3f6700801d592e7e3c4db28788e2 /indra/llcommon/llsingleton.h | |
parent | 5a72d34b7676031da35f93c91eda3eab01085aff (diff) |
DRTVWR-493: Permit LLParamSingleton::initSingleton() circularity.
This was forbidden, but AndreyK points out cases in which LLParamSingleton::
initSingleton() should in fact be allowed to circle back to its own instance()
method. Use a recursive_mutex instead of plain mutex to permit that; remove
LL_ERRS preventing it.
Add LLParamSingleton::instance() method that calls
LLParamSingleton::getInstance(). Inheriting LLSingleton::instance() called
LLSingleton::getInstance() -- not at all what we want.
Add LLParamSingleton unit tests.
Diffstat (limited to 'indra/llcommon/llsingleton.h')
-rw-r--r-- | indra/llcommon/llsingleton.h | 30 |
1 files changed, 16 insertions, 14 deletions
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 38d5af5309..03b7d5a349 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -491,9 +491,6 @@ typename LLSingleton<T>::SingletonData LLSingleton<T>::sData; * * However, distinct initParamSingleton() calls can be used to engage * different constructors, as long as only one such call is executed at * runtime. - * * Circularity is not permitted. No LLSingleton referenced by an - * LLParamSingleton's constructor or initSingleton() method may call this - * LLParamSingleton's instance() or getInstance() methods. * * Unlike LLSingleton, an LLParamSingleton cannot be "revived" by an * instance() or getInstance() call after deleteSingleton(). * @@ -508,7 +505,6 @@ private: public: using super::deleteSingleton; - using super::instance; using super::instanceExists; using super::wasDeleted; @@ -519,7 +515,7 @@ public: // In case racing threads both call initParamSingleton() at the same // time, serialize them. One should initialize; the other should see // mInitState already set. - std::unique_lock<std::mutex> lk(mMutex); + std::unique_lock<decltype(mMutex)> lk(mMutex); // For organizational purposes this function shouldn't be called twice if (super::sData.mInitState != super::UNINITIALIZED) { @@ -538,7 +534,7 @@ public: { // In case racing threads call getInstance() at the same moment as // initParamSingleton(), serialize the calls. - std::unique_lock<std::mutex> lk(mMutex); + std::unique_lock<decltype(mMutex)> lk(mMutex); switch (super::sData.mInitState) { @@ -550,15 +546,10 @@ public: case super::CONSTRUCTING: super::logerrs("Tried to access param singleton ", super::demangle(typeid(DERIVED_TYPE).name()).c_str(), - " from singleton constructor!"); + " from singleton constructor!"); break; case super::INITIALIZING: - super::logerrs("Tried to access param singleton ", - super::demangle(typeid(DERIVED_TYPE).name()).c_str(), - " from initSingleton() method!"); - break; - case super::INITIALIZED: return super::sData.mInstance; @@ -573,12 +564,23 @@ public: return nullptr; } + // instance() is replicated here so it calls + // LLParamSingleton::getInstance() rather than LLSingleton::getInstance() + // -- avoid making getInstance() virtual + static DERIVED_TYPE& instance() + { + return *getInstance(); + } + private: - static std::mutex mMutex; + // Use a recursive_mutex in case of constructor circularity. With a + // non-recursive mutex, that would result in deadlock rather than the + // logerrs() call coded above. + static std::recursive_mutex mMutex; }; template<typename T> -typename std::mutex LLParamSingleton<T>::mMutex; +typename std::recursive_mutex LLParamSingleton<T>::mMutex; /** * Initialization locked singleton, only derived class can decide when to initialize. |