/** * @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 "llerror.h" // *TODO: eliminate this #include #include #include /// @brief A global registry of all singletons to prevent duplicate allocations /// across shared library boundaries class LL_COMMON_API LLSingletonRegistry { typedef std::map TypeMap; static TypeMap* sSingletonMap; public: template static void * & get() { std::string name(typeid(T).name()); if (!sSingletonMap) sSingletonMap = new TypeMap(); // the first entry of the pair returned by insert will be either the existing // iterator matching our key, or the newly inserted NULL initialized entry // see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html TypeMap::iterator result = sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first; return result->second; } }; // 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. // // There are two ways to use LLSingleton. The first way is to inherit from it // while using the typename that you'd like to be static as the template // parameter, like so: // // class Foo: public LLSingleton{}; // // Foo& instance = Foo::instance(); // // The second way is to use the singleton class directly, without inheritance: // // typedef LLSingleton FooSingleton; // // Foo& instance = FooSingleton::instance(); // // In this case, the class being managed as a singleton needs to provide an // initSingleton() method since the LLSingleton virtual method won't be // available // // As currently written, it is not thread-safe. template class LLSingleton : private boost::noncopyable { private: typedef enum e_init_state { UNINITIALIZED, CONSTRUCTING, INITIALIZING, INITIALIZED, DELETED } EInitState; static DERIVED_TYPE* constructSingleton() { return new DERIVED_TYPE(); } struct SingletonData; // stores pointer to singleton instance struct SingletonLifetimeManager { /*SingletonLifetimeManager() { construct(); }*/ static void construct() { SingletonData& sData(getData()); sData.mInitState = CONSTRUCTING; sData.mInstance = constructSingleton(); sData.mInitState = INITIALIZING; } /*~SingletonLifetimeManager() { SingletonData& sData(getData()); if (sData.mInitState != DELETED) { deleteSingleton(); } }*/ }; public: virtual ~LLSingleton() { SingletonData& sData(getData()); sData.mInstance = NULL; sData.mInitState = DELETED; } /** * @brief Immediately delete the singleton. * * A subsequent call to LLProxy::getInstance() will construct a new * instance of the class. * * LLSingletons are normally 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() { SingletonData& sData(getData()); delete sData.mInstance; sData.mInstance = NULL; sData.mInitState = DELETED; } static SingletonData& getData() { // this is static to cache the lookup results static void * & registry = LLSingletonRegistry::get(); // *TODO - look into making this threadsafe if (!registry) { static SingletonData data; registry = &data; } return *static_cast(registry); } static DERIVED_TYPE* getInstance() { //static SingletonLifetimeManager sLifeTimeMgr; SingletonData& sData(getData()); switch (sData.mInitState) { case CONSTRUCTING: LL_ERRS() << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << LL_ENDL; return NULL; case INITIALIZING: LL_WARNS() << "Using singleton " << typeid(DERIVED_TYPE).name() << " during its own initialization, before its initialization completed!" << LL_ENDL; return sData.mInstance; case INITIALIZED: return sData.mInstance; case DELETED: LL_WARNS() << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << LL_ENDL; case UNINITIALIZED: // This must be the first time we get here. SingletonLifetimeManager::construct(); // same as first time construction // Singu note: LL sets the state to INITIALIZED here *already* - which avoids the warning below, but is clearly total bullshit. sData.mInstance->initSingleton(); sData.mInitState = INITIALIZED; return sData.mInstance; } return NULL; } static DERIVED_TYPE* getIfExists() { SingletonData& sData(getData()); 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 uet? // Use this to avoid accessing singletons before the can safely be constructed static bool instanceExists() { SingletonData& sData(getData()); return sData.mInitState == INITIALIZED; } // Has this singleton already been deleted? // Use this to avoid accessing singletons from a static object's destructor static bool destroyed() { SingletonData& sData(getData()); return sData.mInitState == DELETED; } private: virtual void initSingleton() {} 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; }; }; #endif