summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/llsingleton.h205
1 files changed, 205 insertions, 0 deletions
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 859e271e26..b127f4f529 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -446,6 +446,177 @@ public:
return sData.mInitState == DELETED;
}
+protected:
+ static EInitState getInitState()
+ {
+ return sData.mInitState;
+ }
+
+private:
+ struct SingletonData
+ {
+ // explicitly has a default constructor so that member variables are zero initialized in BSS
+ // and only changed by singleton logic, not constructor running during startup
+ EInitState mInitState;
+ DERIVED_TYPE* mInstance;
+ };
+ static SingletonData sData;
+};
+
+
+template <typename DERIVED_TYPE>
+class LLParamSingleton : public LLSingletonBase
+{
+private:
+
+ template <typename... Args>
+ static DERIVED_TYPE* constructSingleton(Args&&... args)
+ {
+ return new DERIVED_TYPE(std::forward<Args>(args)...);
+ }
+
+ // We know of no way to instruct the compiler that every subclass
+ // constructor MUST be private.
+ // However, we can make the LLPARAMSINGLETON() macro both declare
+ // a private constructor and provide the required friend declaration.
+ // How can we ensure that every subclass uses LLPARAMSINGLETON()?
+ // By making that macro provide a definition for this pure virtual
+ // method. If you get "can't instantiate class due to missing pure
+ // virtual method" for this method, then add LLPARAMSINGLETON(yourclass)
+ // in the subclass body.
+ virtual void you_must_use_LLSINGLETON_macro() = 0;
+
+protected:
+ // Pass DERIVED_TYPE explicitly to LLSingletonBase's constructor because,
+ // until our subclass constructor completes, *this isn't yet a
+ // full-fledged DERIVED_TYPE.
+ LLParamSingleton() : LLSingletonBase(LLSingletonBase::tag<DERIVED_TYPE>())
+ {
+ // populate base-class function pointer with the static
+ // deleteSingleton() function for this particular specialization
+ mDeleteSingleton = &deleteSingleton;
+
+ // add this new instance to the master list
+ LLSingleton_manage_master<DERIVED_TYPE>().add(this);
+ }
+
+public:
+
+ virtual ~LLParamSingleton()
+ {
+ // remove this instance from the master list
+ LLSingleton_manage_master<DERIVED_TYPE>().remove(this);
+ sData.mInstance = NULL;
+ sData.mInitState = DELETED;
+ }
+
+ // Passes arguments to DERIVED_TYPE's constructor and sets apropriate states
+ template <typename... Args>
+ static void initParamSingleton(Args&&... args)
+ {
+ sData.mInitState = CONSTRUCTING;
+ sData.mInstance = constructSingleton(std::forward<Args>(args)...);
+ sData.mInitState = INITIALIZED;
+ // initialize singleton after constructing it so that it can
+ // reference other singletons which in turn depend on it, thus
+ // breaking cyclic dependencies
+ sData.mInstance->initSingleton();
+ // pop this off stack of initializing singletons
+ LLSingleton_manage_master<DERIVED_TYPE>().pop_initializing(sData.mInstance);
+ }
+
+ /**
+ * @brief Immediately delete the singleton.
+ *
+ * A subsequent call to LLProxy::getInstance() will construct a new
+ * instance of the class.
+ *
+ * Without an explicit call to LLSingletonBase::deleteAll(), LLSingletons
+ * are implicitly destroyed after main() has exited and the C++ runtime is
+ * cleaning up statically-constructed objects. Some classes derived from
+ * LLSingleton have objects that are part of a runtime system that is
+ * terminated before main() exits. Calling the destructor of those objects
+ * after the termination of their respective systems can cause crashes and
+ * other problems during termination of the project. Using this method to
+ * destroy the singleton early can prevent these crashes.
+ *
+ * An example where this is needed is for a LLSingleton that has an APR
+ * object as a member that makes APR calls on destruction. The APR system is
+ * shut down explicitly before main() exits. This causes a crash on exit.
+ * Using this method before the call to apr_terminate() and NOT calling
+ * getInstance() again will prevent the crash.
+ */
+ static void deleteSingleton()
+ {
+ delete sData.mInstance;
+ sData.mInstance = NULL;
+ sData.mInitState = DELETED;
+ }
+
+ static DERIVED_TYPE* getInstance()
+ {
+ switch (sData.mInitState)
+ {
+ case UNINITIALIZED:
+ logerrs("Uninitialized param singleton ",
+ demangle(typeid(DERIVED_TYPE).name()).c_str());
+ return NULL;
+
+ case CONSTRUCTING:
+ logerrs("Tried to access singleton ",
+ demangle(typeid(DERIVED_TYPE).name()).c_str(),
+ " from singleton constructor!");
+ return NULL;
+
+ case INITIALIZING:
+ logerrs("State not supported by ",
+ demangle(typeid(DERIVED_TYPE).name()).c_str(),
+ " since it is a parametric singleton!");
+ break;
+
+ case INITIALIZED:
+ break;
+
+ case DELETED:
+ logerrs("Trying to access deleted param singleton ",
+ demangle(typeid(DERIVED_TYPE).name()).c_str());
+
+ break;
+ }
+
+ // By this point, if DERIVED_TYPE was pushed onto the initializing
+ // stack, it has been popped off. So the top of that stack, if any, is
+ // 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(
+ LLSingleton_manage_master<DERIVED_TYPE>().get_initializing(sData.mInstance),
+ sData.mInitState);
+ return sData.mInstance;
+ }
+
+ // Reference version of getInstance()
+ // Preferred over getInstance() as it disallows checking for NULL
+ static DERIVED_TYPE& instance()
+ {
+ return *getInstance();
+ }
+
+ // Has this singleton been created yet?
+ // Use this to avoid accessing singletons before they can safely be constructed.
+ static bool instanceExists()
+ {
+ return sData.mInitState == INITIALIZED;
+ }
+
+ // Has this singleton been deleted? This can be useful during shutdown
+ // processing to avoid "resurrecting" a singleton we thought we'd already
+ // cleaned up.
+ static bool wasDeleted()
+ {
+ return sData.mInitState == DELETED;
+ }
+
private:
struct SingletonData
{
@@ -460,6 +631,9 @@ private:
template<typename T>
typename LLSingleton<T>::SingletonData LLSingleton<T>::sData;
+template<typename T>
+typename LLParamSingleton<T>::SingletonData LLParamSingleton<T>::sData;
+
/**
* Use LLSINGLETON(Foo); at the start of an LLSingleton<Foo> subclass body
* when you want to declare an out-of-line constructor:
@@ -510,4 +684,35 @@ private: \
/* LLSINGLETON() is carefully implemented to permit exactly this */ \
LLSINGLETON(DERIVED_CLASS) {}
+/**
+* Use LLPARAMSINGLETON(Foo); at the start of an LLParamSingleton<Foo> subclass body
+* when you want to declare an out-of-line constructor:
+*
+* @code
+* class Foo: public LLParamSingleton<Foo>
+* {
+* // use this macro at start of every LLSingleton subclass
+* LLPARAMSINGLETON(Foo);
+* public:
+* // ...
+* };
+* // ...
+* [inline]
+* Foo::Foo() { ... }
+* @endcode
+*
+* Unfortunately, this mechanism does not permit you to define even a simple
+* (but nontrivial) constructor within the class body. Use LLPARAMSINGLETON()
+* and define the constructor outside the class body. If you must define it
+* in a header file, use 'inline' (unless it's a template class) to avoid
+* duplicate-symbol errors at link time.
+*/
+#define LLPARAMSINGLETON(DERIVED_CLASS, ...) \
+private: \
+ /* implement LLSingleton pure virtual method whose sole purpose */ \
+ /* is to remind people to use this macro */ \
+ virtual void you_must_use_LLSINGLETON_macro() {} \
+ friend class LLParamSingleton<DERIVED_CLASS>; \
+ DERIVED_CLASS(__VA_ARGS__)
+
#endif