/** * @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 #include #include #include #include #include #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 list_t; // Size of stack whose top indicates the LLSingleton currently being // initialized. static list_t::size_type get_initializing_size(); // Produce a vector of master list, in dependency order. typedef std::vector vec_t; static vec_t dep_sort(); // we directly depend on these other LLSingletons typedef boost::unordered_set 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 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 struct tag { typedef T type; }; // Base-class constructor should only be invoked by the DERIVED_TYPE // constructor, which passes tag for various purposes. template LLSingletonBase(tag); 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 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 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 static std::string classname() { return demangle(typeid(T).name()); } template 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 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 { 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 LLSingletonBase::LLSingletonBase(tag): 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().push_initializing(this); } // forward declare for friend directive within LLSingleton template 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 * { * // 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::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::cleanupSingleton(), your method will * implicitly be called by LLSingleton::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 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 class LLSingleton : public LLSingletonBase { private: // LLSingleton 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 LockStatic; // Allow LLParamSingleton subclass -- but NOT DERIVED_TYPE itself -- to // access our private members. friend class LLParamSingleton; // 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 static void constructSingleton(LockStatic& lk, Args&&... args) { auto prev_size = LLSingleton_manage_master().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)...); } 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().reset_initializing(prev_size); logwarns({"Error constructing ", classname(), ": ", 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(), "::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().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().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()) { // 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().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().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::getInstance() will construct a new * instance of the class. * * Without an explicit call to LLSingletonBase::deleteAll(), or * LLSingleton::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(), " 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(), " -- 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(), "::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(), "::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(), "::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 is like LLSingleton, 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 class LLParamSingleton : public LLSingleton { private: typedef LLSingleton super; using typename super::LockStatic; // Passes arguments to DERIVED_TYPE's constructor and sets appropriate // states, returning a pointer to the new instance. template 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(), " twice!"}); return nullptr; } else if (on_main_thread()) { // on the main thread, simply construct instance while holding lock super::logdebugs({super::template classname(), "::initParamSingleton()"}); super::constructSingleton(lk, std::forward(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(), "::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(), "::initParamSingleton() on main thread"}); return initParamSingleton_(std::forward(args)...); }); super::loginfos({super::template classname(), "::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 static DERIVED_TYPE& initParamSingleton(Args&&... args) { return *initParamSingleton_(std::forward(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()}); break; case super::CONSTRUCTING: super::logerrs({"Tried to access param singleton ", super::template classname(), " 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()}); 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 class LLLockedSingleton : public LLParamSingleton
{ typedef LLParamSingleton
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 subclass body * when you want to declare an out-of-line constructor: * * @code * class Foo: public LLSingleton * { * // 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(__VA_ARGS__) /** * Use LLSINGLETON_EMPTY_CTOR(Foo); at the start of an LLSingleton * subclass body when the constructor is trivial: * * @code * class Foo: public LLSingleton * { * // 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 LLSimpleton { public: template static void createInstance(ARGS&&... args) { llassert(sInstance == nullptr); sInstance = new T(std::forward(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 T* LLSimpleton::sInstance{ nullptr }; #ifdef LL_WINDOWS #pragma warning(pop) #endif #endif