/**
 * @file llsingleton.h
 *
 * $LicenseInfo:firstyear=2002&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */
#ifndef LLSINGLETON_H
#define LLSINGLETON_H

#include <boost/noncopyable.hpp>
#include <boost/unordered_set.hpp>
#include <initializer_list>
#include <list>
#include <typeinfo>
#include <vector>
#include "mutex.h"
#include "lockstatic.h"
#include "llthread.h"               // on_main_thread()
#include "llmainthreadtask.h"
#include "llprofiler.h"
#include "llerror.h"

#ifdef LL_WINDOWS
#pragma warning(push)
#pragma warning(disable : 4506)   // no definition for inline function
#endif

class LLSingletonBase: private boost::noncopyable
{
public:
    class MasterList;

private:
    // All existing LLSingleton instances are tracked in this master list.
    typedef std::list<LLSingletonBase*> list_t;
    // Size of stack whose top indicates the LLSingleton currently being
    // initialized.
    static list_t::size_type get_initializing_size();
    // Produce a vector<LLSingletonBase*> of master list, in dependency order.
    typedef std::vector<LLSingletonBase*> vec_t;
    static vec_t dep_sort();

    // we directly depend on these other LLSingletons
    typedef boost::unordered_set<LLSingletonBase*> set_t;
    set_t mDepends;

protected:
    typedef enum e_init_state
    {
        UNINITIALIZED = 0,          // must be default-initialized state
        QUEUED,                     // construction queued, not yet executing
        CONSTRUCTING,               // within DERIVED_TYPE constructor
        INITIALIZING,               // within DERIVED_TYPE::initSingleton()
        INITIALIZED,                // normal case
        DELETED                     // deleteSingleton() or deleteAll() called
    } EInitState;

    // Define tag<T> to pass to our template constructor. You can't explicitly
    // invoke a template constructor with ordinary template syntax:
    // http://stackoverflow.com/a/3960925/5533635
    template <typename T>
    struct tag
    {
        typedef T type;
    };

    // Base-class constructor should only be invoked by the DERIVED_TYPE
    // constructor, which passes tag<DERIVED_TYPE> for various purposes.
    template <typename DERIVED_TYPE>
    LLSingletonBase(tag<DERIVED_TYPE>);
    virtual ~LLSingletonBase();

    // Every new LLSingleton should be added to/removed from the master list
    void add_master();
    void remove_master();
    // with a little help from our friends.
    template <class T> friend struct LLSingleton_manage_master;

    // Maintain a stack of the LLSingleton subclass instance currently being
    // initialized. We use this to notice direct dependencies: we want to know
    // if A requires B. We deduce a dependency if while initializing A,
    // control reaches B::getInstance().
    // We want &A to be at the top of that stack during both A::A() and
    // A::initSingleton(), since a call to B::getInstance() might occur during
    // either.
    // Unfortunately the desired timespan does not correspond neatly with a
    // single C++ scope, else we'd use RAII to track it. But we do know that
    // LLSingletonBase's constructor definitely runs just before
    // LLSingleton's, which runs just before the specific subclass's.
    void push_initializing(const char*);
    // LLSingleton is, and must remain, the only caller to initSingleton().
    // That being the case, we control exactly when it happens -- and we can
    // pop the stack immediately thereafter.
    void pop_initializing();
    // Remove 'this' from the init stack in case of exception in the
    // LLSingleton subclass constructor.
    static void reset_initializing(list_t::size_type size);
protected:
    // 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();

    // delegate logging calls to llsingleton.cpp
public:
    typedef std::initializer_list<const std::string> string_params;
protected:
    static void logerrs  (const string_params&);
    static void logwarns (const string_params&);
    static void loginfos (const string_params&);
    static void logdebugs(const string_params&);
    static std::string demangle(const char* mangled);
    // these classname() declarations restate template functions declared in
    // llerror.h because we avoid #including that here
    template <typename T>
    static std::string classname()       { return demangle(typeid(T).name()); }
    template <typename T>
    static std::string classname(T* ptr) { return demangle(typeid(*ptr).name()); }

    // Default methods in case subclass doesn't declare them.
    virtual void initSingleton() {}
    virtual void cleanupSingleton() {}

    // internal wrapper around calls to cleanupSingleton()
    void cleanup_();

    // deleteSingleton() isn't -- and shouldn't be -- a virtual method. It's a
    // class static. However, given only Foo*, deleteAll() does need to be
    // able to reach Foo::deleteSingleton(). Make LLSingleton (which declares
    // deleteSingleton()) store a pointer here. Since we know it's a static
    // class method, a classic-C function pointer will do.
    void (*mDeleteSingleton)();

public:
    /**
     * deleteAll() calls the cleanupSingleton() and deleteSingleton() methods
     * for every LLSingleton constructed since the start of the last
     * deleteAll() call. (Any LLSingleton constructed DURING a deleteAll()
     * call won't be cleaned up until the next deleteAll() call.)
     * deleteSingleton() deletes and destroys its LLSingleton. Any cleanup
     * logic that might take significant realtime -- or throw an exception --
     * must not be placed in your LLSingleton's destructor, but rather in its
     * cleanupSingleton() method, which is called implicitly by
     * deleteSingleton().
     *
     * The most important property of deleteAll() is that deleteSingleton()
     * methods are called in dependency order, leaf classes last. Thus, given
     * two LLSingleton subclasses A and B, if A's dependency on B is properly
     * expressed as a B::getInstance() or B::instance() call during either
     * A::A() or A::initSingleton(), B will be cleaned up after A.
     *
     * If a cleanupSingleton() or deleteSingleton() method throws an
     * exception, the exception is logged, but deleteAll() attempts to
     * continue calling the rest of the deleteSingleton() methods.
     */
    static void deleteAll();
};

// Most of the time, we want LLSingleton_manage_master() to forward its
// methods to real LLSingletonBase methods.
template <class T>
struct LLSingleton_manage_master
{
    void add(LLSingletonBase* sb) { sb->add_master(); }
    void remove(LLSingletonBase* sb) { sb->remove_master(); }
    void push_initializing(LLSingletonBase* sb) { sb->push_initializing(typeid(T).name()); }
    void pop_initializing (LLSingletonBase* sb) { sb->pop_initializing(); }
    // used for init stack cleanup in case an LLSingleton subclass constructor
    // throws an exception
    void reset_initializing(LLSingletonBase::list_t::size_type size)
    {
        LLSingletonBase::reset_initializing(size);
    }
    // For any LLSingleton subclass except the MasterList, obtain the size of
    // the init stack from the MasterList singleton instance.
    LLSingletonBase::list_t::size_type get_initializing_size()
    {
        return LLSingletonBase::get_initializing_size();
    }
    void capture_dependency(LLSingletonBase* sb)
    {
        sb->capture_dependency();
    }
};

// But for the specific case of LLSingletonBase::MasterList, don't.
template <>
struct LLSingleton_manage_master<LLSingletonBase::MasterList>
{
    void add(LLSingletonBase*) {}
    void remove(LLSingletonBase*) {}
    void push_initializing(LLSingletonBase*) {}
    void pop_initializing (LLSingletonBase*) {}
    // since we never pushed, no need to clean up
    void reset_initializing(LLSingletonBase::list_t::size_type size) {}
    LLSingletonBase::list_t::size_type get_initializing_size() { return 0; }
    void capture_dependency(LLSingletonBase*) {}
};

// Now we can implement LLSingletonBase's template constructor.
template <typename DERIVED_TYPE>
LLSingletonBase::LLSingletonBase(tag<DERIVED_TYPE>):
    mDeleteSingleton(nullptr)
{
    // This is the earliest possible point at which we can push this new
    // instance onto the init stack. LLSingleton::constructSingleton() can't
    // do it before calling the constructor, because it doesn't have an
    // instance pointer until the constructor returns. Fortunately this
    // constructor is guaranteed to be called before any subclass constructor.
    // Make this new instance the currently-initializing LLSingleton.
    LLSingleton_manage_master<DERIVED_TYPE>().push_initializing(this);
}

// forward declare for friend directive within LLSingleton
template <typename DERIVED_TYPE>
class LLParamSingleton;

/**
 * LLSingleton implements the getInstance() method part of the Singleton
 * pattern. It can't make the derived class constructors protected, though, so
 * you have to do that yourself.
 *
 * Derive your class from LLSingleton, passing your subclass name as
 * LLSingleton's template parameter, like so:
 *
 *   class Foo: public LLSingleton<Foo>
 *   {
 *       // use this macro at start of every LLSingleton subclass
 *       LLSINGLETON(Foo);
 *   public:
 *       // ...
 *   };
 *
 *   Foo& instance = Foo::instance();
 *
 * LLSingleton recognizes a couple special methods in your derived class.
 *
 * If you override LLSingleton<T>::initSingleton(), your method will be called
 * immediately after the instance is constructed. This is useful for breaking
 * circular dependencies: if you find that your LLSingleton subclass
 * constructor references other LLSingleton subclass instances in a chain
 * leading back to yours, move the instance reference from your constructor to
 * your initSingleton() method.
 *
 * If you override LLSingleton<T>::cleanupSingleton(), your method will
 * implicitly be called by LLSingleton<T>::deleteSingleton() just before the
 * instance is destroyed. We introduce a special cleanupSingleton() method
 * because cleanupSingleton() operations can involve nontrivial realtime, or
 * throw an exception. A destructor should do neither!
 *
 * If your cleanupSingleton() method throws an exception, we log that
 * exception but carry on.
 *
 * If at some point you call LLSingletonBase::deleteAll(), all remaining
 * LLSingleton<T> instances will be destroyed in reverse dependency order. (Or
 * call MySubclass::deleteSingleton() to specifically destroy the canonical
 * MySubclass instance.)
 *
 * That is, consider LLSingleton subclasses C, B and A. A depends on B, which
 * in turn depends on C. These dependencies are expressed as calls to
 * B::instance() or B::getInstance(), and C::instance() or C::getInstance().
 * It shouldn't matter whether these calls appear in A::A() or
 * A::initSingleton(), likewise B::B() or B::initSingleton().
 *
 * We promise that if you later call LLSingletonBase::deleteAll():
 * 1. A::deleteSingleton() will be called before
 * 2. B::deleteSingleton(), which will be called before
 * 3. C::deleteSingleton().
 * Put differently, if your LLSingleton subclass constructor or
 * initSingleton() method explicitly depends on some other LLSingleton
 * subclass, you may continue to rely on that other subclass in your
 * cleanupSingleton() method.
 */
template <typename DERIVED_TYPE>
class LLSingleton : public LLSingletonBase
{
private:
    // LLSingleton<DERIVED_TYPE> must have a distinct instance of
    // SingletonData for every distinct DERIVED_TYPE. It's tempting to
    // consider hoisting SingletonData up into LLSingletonBase. Don't do it.
    struct SingletonData
    {
        // Use a recursive_mutex in case of constructor circularity. With a
        // non-recursive mutex, that would result in deadlock.
        typedef std::recursive_mutex mutex_t;
        LL_PROFILE_MUTEX_NAMED(mutex_t, mMutex, "Singleton Data"); // LockStatic looks for mMutex

        EInitState      mInitState{UNINITIALIZED};
        DERIVED_TYPE*   mInstance{nullptr};
    };
    typedef llthread::LockStatic<SingletonData> LockStatic;

    // Allow LLParamSingleton subclass -- but NOT DERIVED_TYPE itself -- to
    // access our private members.
    friend class LLParamSingleton<DERIVED_TYPE>;

    // LLSingleton only supports a nullary constructor. However, the specific
    // purpose for its subclass LLParamSingleton is to support Singletons
    // requiring constructor arguments. constructSingleton() supports both use
    // cases.
    // Accepting LockStatic& requires that the caller has already locked our
    // static data before calling.
    template <typename... Args>
    static void constructSingleton(LockStatic& lk, Args&&... args)
    {
        auto prev_size = LLSingleton_manage_master<DERIVED_TYPE>().get_initializing_size();
        // Any getInstance() calls after this point are from within constructor
        lk->mInitState = CONSTRUCTING;
        try
        {
            lk->mInstance = new DERIVED_TYPE(std::forward<Args>(args)...);
        }
        catch (const std::exception& err)
        {
            // LLSingletonBase might -- or might not -- have pushed the new
            // instance onto the init stack before the exception. Reset the
            // init stack to its previous size BEFORE logging so log-machinery
            // LLSingletons don't record a dependency on DERIVED_TYPE!
            LLSingleton_manage_master<DERIVED_TYPE>().reset_initializing(prev_size);
            logwarns({"Error constructing ", classname<DERIVED_TYPE>(),
                     ": ", err.what()});
            // There isn't a separate EInitState value meaning "we attempted
            // to construct this LLSingleton subclass but could not," so use
            // DELETED. That seems slightly more appropriate than UNINITIALIZED.
            lk->mInitState = DELETED;
            // propagate the exception
            throw;
        }

        // Any getInstance() calls after this point are from within initSingleton()
        lk->mInitState = INITIALIZING;
        try
        {
            // initialize singleton after constructing it so that it can
            // reference other singletons which in turn depend on it, thus
            // breaking cyclic dependencies
            lk->mInstance->initSingleton();
            lk->mInitState = INITIALIZED;

            // pop this off stack of initializing singletons
            pop_initializing(lk->mInstance);
        }
        catch (const std::exception& err)
        {
            // pop this off stack of initializing singletons here, too --
            // BEFORE logging, so log-machinery LLSingletons don't record a
            // dependency on DERIVED_TYPE!
            pop_initializing(lk->mInstance);
            logwarns({"Error in ", classname<DERIVED_TYPE>(),
                     "::initSingleton(): ", err.what()});
            // Get rid of the instance entirely. This call depends on our
            // recursive_mutex. We could have a deleteSingleton(LockStatic&)
            // overload and pass lk, but we don't strictly need it.
            deleteSingleton();
            // propagate the exception
            throw;
        }
    }

    static void pop_initializing(LLSingletonBase* sb)
    {
        // route through LLSingleton_manage_master so we Do The Right Thing
        // (namely, nothing) for MasterList
        LLSingleton_manage_master<DERIVED_TYPE>().pop_initializing(sb);
    }

    static void capture_dependency(LLSingletonBase* sb)
    {
        // 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
        // getInstance() was called by another LLSingleton, rather than from
        // vanilla application code, record the dependency.
        LLSingleton_manage_master<DERIVED_TYPE>().capture_dependency(sb);
    }

    // We know of no way to instruct the compiler that every subclass
    // constructor MUST be private. However, we can make the LLSINGLETON()
    // macro both declare a private constructor and provide the required
    // friend declaration. How can we ensure that every subclass uses
    // LLSINGLETON()? 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 LLSINGLETON(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.
    LLSingleton(): 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);
    }

protected:
    virtual ~LLSingleton()
    {
        // This phase of cleanup is performed in the destructor rather than in
        // deleteSingleton() to defend against manual deletion. When we moved
        // cleanup to deleteSingleton(), we hit crashes due to dangling
        // pointers in the MasterList.
        LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);
        lk->mInstance  = nullptr;
        lk->mInitState = DELETED;

        // Remove this instance from the master list.
        LLSingleton_manage_master<DERIVED_TYPE>().remove(this);
    }

public:
    /**
     * @brief Cleanup and destroy the singleton instance.
     *
     * deleteSingleton() calls this instance's cleanupSingleton() method and
     * then destroys the instance.
     *
     * A subsequent call to LLSingleton<T>::getInstance() will construct a new
     * instance of the class.
     *
     * Without an explicit call to LLSingletonBase::deleteAll(), or
     * LLSingleton<T>::deleteSingleton(), LLSingleton instances are simply
     * leaked. (Allowing implicit destruction at shutdown caused too many
     * problems.)
     */
    static void deleteSingleton()
    {
        // Hold the lock while we call cleanupSingleton() and the destructor.
        // Our destructor also instantiates LockStatic, requiring a recursive
        // mutex.
        LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);
        // of course, only cleanup and delete if there's something there
        if (lk->mInstance)
        {
            lk->mInstance->cleanup_();
            delete lk->mInstance;
            // destructor clears mInstance (and mInitState)
        }
    }

    static DERIVED_TYPE* getInstance()
    {
        //LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; // TODO -- reenable this when we have a fix for using Tracy with coroutines
        // We know the viewer has LLSingleton dependency circularities. If you
        // feel strongly motivated to eliminate them, cheers and good luck.
        // (At that point we could consider a much simpler locking mechanism.)

        // If A and B depend on each other, and thread T1 requests A at the
        // same moment thread T2 requests B, you could get a sequence like this:
        // - T1 locks A
        // - T2 locks B
        // - T1, having constructed A, calls A::initSingleton(), which calls
        //   B::getInstance() and blocks on B's lock
        // - T2, having constructed B, calls B::initSingleton(), which calls
        //   A::getInstance() and blocks on A's lock
        // In other words, classic deadlock.

        // Avoid that by constructing and initializing every LLSingleton on
        // the main thread. In that scenario:
        // - T1 locks A
        // - T2 locks B
        // - T1 discovers A is UNINITIALIZED, so it queues a task for the main
        //   thread, unlocks A and blocks on the std::future.
        // - T2 discovers B is UNINITIALIZED, so it queues a task for the main
        //   thread, unlocks B and blocks on the std::future.
        // - The main thread executes T1's request for A. It locks A and
        //   starts to construct it.
        // - A::initSingleton() calls B::getInstance(). Fine: nobody's holding
        //   B's lock.
        // - The main thread locks B, constructs B, calls B::initSingleton(),
        //   which calls A::getInstance(), which returns A.
        // - B::getInstance() returns B to A::initSingleton(), unlocking B.
        // - A::getInstance() returns A to the task wrapper, unlocking A.
        // - The task wrapper passes A to T1 via the future. T1 resumes.
        // - The main thread executes T2's request for B. Oh look, B already
        //   exists. The task wrapper passes B to T2 via the future. T2
        //   resumes.
        // This still works even if one of T1 or T2 *is* the main thread.
        // This still works even if thread T3 requests B at the same moment as
        // T2. Finding B still UNINITIALIZED, T3 also queues a task for the
        // main thread, unlocks B and blocks on a (distinct) std::future. By
        // the time the main thread executes T3's request for B, B already
        // exists, and is simply delivered via the future.

        { // nested scope for 'lk'
            // In case racing threads call getInstance() at the same moment,
            // serialize the calls.
            LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);

            switch (lk->mInitState)
            {
            case CONSTRUCTING:
                // here if DERIVED_TYPE's constructor (directly or indirectly)
                // calls DERIVED_TYPE::getInstance()
                logerrs({"Tried to access singleton ",
                        classname<DERIVED_TYPE>(),
                        " from singleton constructor!"});
                return nullptr;

            case INITIALIZING:
                // here if DERIVED_TYPE::initSingleton() (directly or indirectly)
                // calls DERIVED_TYPE::getInstance(): go ahead and allow it
            case INITIALIZED:
                // normal subsequent calls
                // record the dependency, if any: check if we got here from another
                // LLSingleton's constructor or initSingleton() method
                capture_dependency(lk->mInstance);
                return lk->mInstance;

            case DELETED:
                // called after deleteSingleton()
                logwarns({"Trying to access deleted singleton ",
                         classname<DERIVED_TYPE>(),
                         " -- creating new instance"});
                // fall through
                [[fallthrough]];
            case UNINITIALIZED:
            case QUEUED:
                // QUEUED means some secondary thread has already requested an
                // instance, but for present purposes that's semantically
                // identical to UNINITIALIZED: either way, we must ourselves
                // request an instance.
                break;
            }

            // Here we need to construct a new instance.
            if (on_main_thread())
            {
                // On the main thread, directly construct the instance while
                // holding the lock.
                constructSingleton(lk);
                capture_dependency(lk->mInstance);
                return lk->mInstance;
            }

            // Here we need to construct a new instance, but we're on a secondary
            // thread.
            lk->mInitState = QUEUED;
        } // unlock 'lk'

        // Per the comment block above, dispatch to the main thread.
        loginfos({classname<DERIVED_TYPE>(),
                 "::getInstance() dispatching to main thread"});
        auto instance = LLMainThreadTask::dispatch(
            [](){
                // VERY IMPORTANT to call getInstance() on the main thread,
                // rather than going straight to constructSingleton()!
                // During the time window before mInitState is INITIALIZED,
                // multiple requests might be queued. It's essential that, as
                // the main thread processes them, only the FIRST such request
                // actually constructs the instance -- every subsequent one
                // simply returns the existing instance.
                loginfos({classname<DERIVED_TYPE>(),
                         "::getInstance() on main thread"});
                return getInstance();
            });
        // record the dependency chain tracked on THIS thread, not the main
        // thread (consider a getInstance() overload with a tag param that
        // suppresses dep tracking when dispatched to the main thread)
        capture_dependency(instance);
        loginfos({classname<DERIVED_TYPE>(),
                 "::getInstance() returning on requesting thread"});
        return instance;
    }

    // Reference version of getInstance()
    // Preferred over getInstance() as it disallows checking for nullptr
    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()
    {
        // defend any access to sData from racing threads
        LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);
        return lk->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()
    {
        // defend any access to sData from racing threads
        LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);
        return lk->mInitState == DELETED;
    }
};


/**
 * LLParamSingleton<T> is like LLSingleton<T>, except in the following ways:
 *
 * * It is NOT instantiated on demand (instance() or getInstance()). You must
 *   first call initParamSingleton(constructor args...).
 * * Before initParamSingleton(), calling instance() or getInstance() dies with
 *   LL_ERRS.
 * * initParamSingleton() may be called only once. A second call dies with
 *   LL_ERRS.
 * * However, distinct initParamSingleton() calls can be used to engage
 *   different constructors, as long as only one such call is executed at
 *   runtime.
 * * Unlike LLSingleton, an LLParamSingleton cannot be "revived" by an
 *   instance() or getInstance() call after deleteSingleton().
 *
 * Importantly, though, each LLParamSingleton subclass does participate in the
 * dependency-ordered LLSingletonBase::deleteAll() processing.
 */
template <typename DERIVED_TYPE>
class LLParamSingleton : public LLSingleton<DERIVED_TYPE>
{
private:
    typedef LLSingleton<DERIVED_TYPE> super;
    using typename super::LockStatic;

    // Passes arguments to DERIVED_TYPE's constructor and sets appropriate
    // states, returning a pointer to the new instance.
    template <typename... Args>
    static DERIVED_TYPE* initParamSingleton_(Args&&... args)
    {
        // In case racing threads both call initParamSingleton() at the same
        // time, serialize them. One should initialize; the other should see
        // mInitState already set.
        LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);
        // For organizational purposes this function shouldn't be called twice
        if (lk->mInitState != super::UNINITIALIZED)
        {
            super::logerrs({"Tried to initialize singleton ",
                           super::template classname<DERIVED_TYPE>(),
                           " twice!"});
            return nullptr;
        }
        else if (on_main_thread())
        {
            // on the main thread, simply construct instance while holding lock
            super::logdebugs({super::template classname<DERIVED_TYPE>(),
                             "::initParamSingleton()"});
            super::constructSingleton(lk, std::forward<Args>(args)...);
            return lk->mInstance;
        }
        else
        {
            // on secondary thread, dispatch to main thread --
            // set state so we catch any other calls before the main thread
            // picks up the task
            lk->mInitState = super::QUEUED;
            // very important to unlock here so main thread can actually process
            lk.unlock();
            super::loginfos({super::template classname<DERIVED_TYPE>(),
                            "::initParamSingleton() dispatching to main thread"});
            // Normally it would be the height of folly to reference-bind
            // 'args' into a lambda to be executed on some other thread! By
            // the time that thread executed the lambda, the references would
            // all be dangling, and Bad Things would result. But
            // LLMainThreadTask::dispatch() promises to block until the passed
            // task has completed. So in this case we know the references will
            // remain valid until the lambda has run, so we dare to bind
            // references.
            auto instance = LLMainThreadTask::dispatch(
                [&](){
                    super::loginfos({super::template classname<DERIVED_TYPE>(),
                                    "::initParamSingleton() on main thread"});
                    return initParamSingleton_(std::forward<Args>(args)...);
                });
            super::loginfos({super::template classname<DERIVED_TYPE>(),
                            "::initParamSingleton() returning on requesting thread"});
            return instance;
        }
    }

public:
    using super::deleteSingleton;
    using super::instanceExists;
    using super::wasDeleted;

    /// initParamSingleton() constructs the instance, returning a reference.
    /// Pass whatever arguments are required to construct DERIVED_TYPE.
    template <typename... Args>
    static DERIVED_TYPE& initParamSingleton(Args&&... args)
    {
        return *initParamSingleton_(std::forward<Args>(args)...);
    }

    static DERIVED_TYPE* getInstance()
    {
        // In case racing threads call getInstance() at the same moment as
        // initParamSingleton(), serialize the calls.
        LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex);

        switch (lk->mInitState)
        {
        case super::UNINITIALIZED:
        case super::QUEUED:
            super::logerrs({"Uninitialized param singleton ",
                           super::template classname<DERIVED_TYPE>()});
            break;

        case super::CONSTRUCTING:
            super::logerrs({"Tried to access param singleton ",
                           super::template classname<DERIVED_TYPE>(),
                           " from singleton constructor!"});
            break;

        case super::INITIALIZING:
            // As with LLSingleton, explicitly permit circular calls from
            // within initSingleton()
        case super::INITIALIZED:
            // for any valid call, capture dependencies
            super::capture_dependency(lk->mInstance);
            return lk->mInstance;

        case super::DELETED:
            super::logerrs({"Trying to access deleted param singleton ",
                           super::template classname<DERIVED_TYPE>()});
            break;
        }

        // should never actually get here; this is to pacify the compiler,
        // which assumes control might return from logerrs()
        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();
    }
};

/**
 * Initialization locked singleton, only derived class can decide when to initialize.
 * Starts locked.
 * For cases when singleton has a dependency onto something or.
 *
 * LLLockedSingleton is like an LLParamSingleton with a nullary constructor.
 * It cannot be instantiated on demand (instance() or getInstance() call) --
 * it must be instantiated by calling construct(). However, it does
 * participate in dependency-ordered LLSingletonBase::deleteAll() processing.
 */
template <typename DT>
class LLLockedSingleton : public LLParamSingleton<DT>
{
    typedef LLParamSingleton<DT> super;

public:
    using super::deleteSingleton;
    using super::getInstance;
    using super::instance;
    using super::instanceExists;
    using super::wasDeleted;

    static DT* construct()
    {
        return super::initParamSingleton();
    }
};

/**
 * Use LLSINGLETON(Foo); at the start of an LLSingleton<Foo> subclass body
 * when you want to declare an out-of-line constructor:
 *
 * @code
 *   class Foo: public LLSingleton<Foo>
 *   {
 *       // use this macro at start of every LLSingleton subclass
 *       LLSINGLETON(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. If it's literally
 * trivial, use LLSINGLETON_EMPTY_CTOR(); if not, use LLSINGLETON() 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 LLSINGLETON(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() override {}                    \
    friend class LLSingleton<DERIVED_CLASS>;                            \
    DERIVED_CLASS(__VA_ARGS__)

/**
 * Use LLSINGLETON_EMPTY_CTOR(Foo); at the start of an LLSingleton<Foo>
 * subclass body when the constructor is trivial:
 *
 * @code
 *   class Foo: public LLSingleton<Foo>
 *   {
 *       // use this macro at start of every LLSingleton subclass
 *       LLSINGLETON_EMPTY_CTOR(Foo);
 *   public:
 *       // ...
 *   };
 * @endcode
 */
#define LLSINGLETON_EMPTY_CTOR(DERIVED_CLASS)                           \
    /* LLSINGLETON() is carefully implemented to permit exactly this */ \
    LLSINGLETON(DERIVED_CLASS) {}

// Relatively unsafe singleton implementation that is much faster
// and simpler than LLSingleton, but has no dependency tracking
// or inherent thread safety and requires manual invocation of
// createInstance before first use.
template<class T>
class LLSimpleton
{
public:
    template <typename... ARGS>
    static void createInstance(ARGS&&... args)
    {
        llassert(sInstance == nullptr);
        sInstance = new T(std::forward<ARGS>(args)...);
    }

    static inline T* getInstance() { return sInstance; }
    static inline T& instance() { return *getInstance(); }
    static inline bool instanceExists() { return sInstance != nullptr; }

    static void deleteSingleton()
    {
        delete sInstance;
        sInstance = nullptr;
    }

private:
    static T* sInstance;
};

template <class T>
T* LLSimpleton<T>::sInstance{ nullptr };

#ifdef LL_WINDOWS
#pragma warning(pop)
#endif

#endif