diff options
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/llsingleton.h | 205 | 
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 | 
