Skip to content
Snippets Groups Projects
Commit 687efd84 authored by Nat Goodspeed's avatar Nat Goodspeed
Browse files

MAINT-5232: Loosen LLSingleton circularity constraints slightly.

LLSingleton explicitly supports circular dependencies: initialization
performed during an LLSingleton subclass's initSingleton() method may
recursively call that same subclass's getInstance() method. On the other hand,
circularity from a subclass constructor cannot be permitted, else
getInstance() would have to return a partially-constructed object.
Our dependency tracking circularity check initially forbade both. Loosen it to
permit references from within initSingleton().
parent aefdba12
No related branches found
No related tags found
No related merge requests found
......@@ -123,7 +123,7 @@ void LLSingletonBase::pop_initializing()
list.pop_back();
}
void LLSingletonBase::capture_dependency()
void LLSingletonBase::capture_dependency(EInitState initState)
{
// Did this getInstance() call come from another LLSingleton, or from
// vanilla application code? Note that although this is a nontrivial
......@@ -150,11 +150,18 @@ void LLSingletonBase::capture_dependency()
// is the actual LLSingletonBase instance.
out << typeid(**found).name() << " -> ";
}
// DEBUGGING: Initially, make this crump. We want to know how bad
// the problem is before we add it to the long, sad list of
// ominous warnings that everyone always ignores.
logerrs("LLSingleton circularity: ", out.str().c_str(),
typeid(*this).name());
// We promise to capture dependencies from both the constructor
// and the initSingleton() method, so an LLSingleton's instance
// pointer is on the initializing list during both. Now that we've
// detected circularity, though, we must distinguish the two. If
// the recursive call is from the constructor, we CAN'T honor it:
// otherwise we'd be returning a pointer to a partially-
// constructed object! But from initSingleton() is okay: that
// method exists specifically to support circularity.
// Decide which log helper to call based on initState. They have
// identical signatures.
((initState == CONSTRUCTING)? logerrs : logwarns)
("LLSingleton circularity: ", out.str().c_str(), typeid(*this).name(), "");
}
else
{
......
......@@ -58,6 +58,15 @@ class LLSingletonBase: private boost::noncopyable
set_t mDepends;
protected:
typedef enum e_init_state
{
UNINITIALIZED = 0, // must be default-initialized state
CONSTRUCTING,
INITIALIZING,
INITIALIZED,
DELETED
} EInitState;
// Base-class constructor should only be invoked by the DERIVED_TYPE
// constructor.
LLSingletonBase();
......@@ -87,7 +96,7 @@ class LLSingletonBase: private boost::noncopyable
void pop_initializing();
// If a given call to B::getInstance() happens during either A::A() or
// A::initSingleton(), record that A directly depends on B.
void capture_dependency();
void capture_dependency(EInitState);
// delegate LL_ERRS() logging to llsingleton.cpp
static void logerrs(const char* p1, const char* p2="",
......@@ -232,15 +241,6 @@ template <typename DERIVED_TYPE>
class LLSingleton : public LLSingletonBase
{
private:
typedef enum e_init_state
{
UNINITIALIZED = 0, // must be default-initialized state
CONSTRUCTING,
INITIALIZING,
INITIALIZED,
DELETED
} EInitState;
static DERIVED_TYPE* constructSingleton()
{
return new DERIVED_TYPE();
......@@ -377,7 +377,7 @@ class LLSingleton : public LLSingletonBase
// an LLSingleton that directly depends on DERIVED_TYPE. If this call
// came from another LLSingleton, rather than from vanilla application
// code, record the dependency.
sData.mInstance->capture_dependency();
sData.mInstance->capture_dependency(sData.mInitState);
return sData.mInstance;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment