/indra/llcommon/llsingleton.h

https://bitbucket.org/lindenlab/viewer-beta/ · C++ Header · 225 lines · 114 code · 29 blank · 82 comment · 13 complexity · ae2a81ee073472e124db265ad55638eb MD5 · raw file

  1. /**
  2. * @file llsingleton.h
  3. *
  4. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  5. * Second Life Viewer Source Code
  6. * Copyright (C) 2010, Linden Research, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation;
  11. * version 2.1 of the License only.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  23. * $/LicenseInfo$
  24. */
  25. #ifndef LLSINGLETON_H
  26. #define LLSINGLETON_H
  27. #include "llerror.h" // *TODO: eliminate this
  28. #include <typeinfo>
  29. #include <boost/noncopyable.hpp>
  30. /// @brief A global registry of all singletons to prevent duplicate allocations
  31. /// across shared library boundaries
  32. class LL_COMMON_API LLSingletonRegistry {
  33. private:
  34. typedef std::map<std::string, void *> TypeMap;
  35. static TypeMap * sSingletonMap;
  36. static void checkInit()
  37. {
  38. if(sSingletonMap == NULL)
  39. {
  40. sSingletonMap = new TypeMap();
  41. }
  42. }
  43. public:
  44. template<typename T> static void * & get()
  45. {
  46. std::string name(typeid(T).name());
  47. checkInit();
  48. // the first entry of the pair returned by insert will be either the existing
  49. // iterator matching our key, or the newly inserted NULL initialized entry
  50. // see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
  51. TypeMap::iterator result =
  52. sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first;
  53. return result->second;
  54. }
  55. };
  56. // LLSingleton implements the getInstance() method part of the Singleton
  57. // pattern. It can't make the derived class constructors protected, though, so
  58. // you have to do that yourself.
  59. //
  60. // There are two ways to use LLSingleton. The first way is to inherit from it
  61. // while using the typename that you'd like to be static as the template
  62. // parameter, like so:
  63. //
  64. // class Foo: public LLSingleton<Foo>{};
  65. //
  66. // Foo& instance = Foo::instance();
  67. //
  68. // The second way is to use the singleton class directly, without inheritance:
  69. //
  70. // typedef LLSingleton<Foo> FooSingleton;
  71. //
  72. // Foo& instance = FooSingleton::instance();
  73. //
  74. // In this case, the class being managed as a singleton needs to provide an
  75. // initSingleton() method since the LLSingleton virtual method won't be
  76. // available
  77. //
  78. // As currently written, it is not thread-safe.
  79. template <typename DERIVED_TYPE>
  80. class LLSingleton : private boost::noncopyable
  81. {
  82. private:
  83. typedef enum e_init_state
  84. {
  85. UNINITIALIZED,
  86. CONSTRUCTING,
  87. INITIALIZING,
  88. INITIALIZED,
  89. DELETED
  90. } EInitState;
  91. // stores pointer to singleton instance
  92. // and tracks initialization state of singleton
  93. struct SingletonInstanceData
  94. {
  95. EInitState mInitState;
  96. DERIVED_TYPE* mSingletonInstance;
  97. SingletonInstanceData()
  98. : mSingletonInstance(NULL),
  99. mInitState(UNINITIALIZED)
  100. {}
  101. ~SingletonInstanceData()
  102. {
  103. if (mInitState != DELETED)
  104. {
  105. deleteSingleton();
  106. }
  107. }
  108. };
  109. public:
  110. virtual ~LLSingleton()
  111. {
  112. SingletonInstanceData& data = getData();
  113. data.mSingletonInstance = NULL;
  114. data.mInitState = DELETED;
  115. }
  116. /**
  117. * @brief Immediately delete the singleton.
  118. *
  119. * A subsequent call to LLProxy::getInstance() will construct a new
  120. * instance of the class.
  121. *
  122. * LLSingletons are normally destroyed after main() has exited and the C++
  123. * runtime is cleaning up statically-constructed objects. Some classes
  124. * derived from LLSingleton have objects that are part of a runtime system
  125. * that is terminated before main() exits. Calling the destructor of those
  126. * objects after the termination of their respective systems can cause
  127. * crashes and other problems during termination of the project. Using this
  128. * method to destroy the singleton early can prevent these crashes.
  129. *
  130. * An example where this is needed is for a LLSingleton that has an APR
  131. * object as a member that makes APR calls on destruction. The APR system is
  132. * shut down explicitly before main() exits. This causes a crash on exit.
  133. * Using this method before the call to apr_terminate() and NOT calling
  134. * getInstance() again will prevent the crash.
  135. */
  136. static void deleteSingleton()
  137. {
  138. delete getData().mSingletonInstance;
  139. getData().mSingletonInstance = NULL;
  140. getData().mInitState = DELETED;
  141. }
  142. static SingletonInstanceData& getData()
  143. {
  144. // this is static to cache the lookup results
  145. static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
  146. // *TODO - look into making this threadsafe
  147. if(NULL == registry)
  148. {
  149. static SingletonInstanceData data;
  150. registry = &data;
  151. }
  152. return *static_cast<SingletonInstanceData *>(registry);
  153. }
  154. static DERIVED_TYPE* getInstance()
  155. {
  156. SingletonInstanceData& data = getData();
  157. if (data.mInitState == CONSTRUCTING)
  158. {
  159. llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl;
  160. }
  161. if (data.mInitState == DELETED)
  162. {
  163. llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl;
  164. }
  165. if (!data.mSingletonInstance)
  166. {
  167. data.mInitState = CONSTRUCTING;
  168. data.mSingletonInstance = new DERIVED_TYPE();
  169. data.mInitState = INITIALIZING;
  170. data.mSingletonInstance->initSingleton();
  171. data.mInitState = INITIALIZED;
  172. }
  173. return data.mSingletonInstance;
  174. }
  175. // Reference version of getInstance()
  176. // Preferred over getInstance() as it disallows checking for NULL
  177. static DERIVED_TYPE& instance()
  178. {
  179. return *getInstance();
  180. }
  181. // Has this singleton been created uet?
  182. // Use this to avoid accessing singletons before the can safely be constructed
  183. static bool instanceExists()
  184. {
  185. return getData().mInitState == INITIALIZED;
  186. }
  187. // Has this singleton already been deleted?
  188. // Use this to avoid accessing singletons from a static object's destructor
  189. static bool destroyed()
  190. {
  191. return getData().mInitState == DELETED;
  192. }
  193. private:
  194. virtual void initSingleton() {}
  195. };
  196. #endif