summaryrefslogtreecommitdiff
path: root/indra/llcommon/llsingleton.h
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2019-08-12 17:35:45 -0400
committerNat Goodspeed <nat@lindenlab.com>2019-08-12 17:35:45 -0400
commit4fce6dc4353dbf9ccd3c9c3aced89df72a4f3abd (patch)
tree818dfbed3ede3f6700801d592e7e3c4db28788e2 /indra/llcommon/llsingleton.h
parent5a72d34b7676031da35f93c91eda3eab01085aff (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.h30
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.