PageRenderTime 70ms CodeModel.GetById 61ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/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
 28#include "llerror.h"	// *TODO: eliminate this
 29
 30#include <typeinfo>
 31#include <boost/noncopyable.hpp>
 32
 33/// @brief A global registry of all singletons to prevent duplicate allocations
 34/// across shared library boundaries
 35class LL_COMMON_API LLSingletonRegistry {
 36	private:
 37		typedef std::map<std::string, void *> TypeMap;
 38		static TypeMap * sSingletonMap;
 39
 40		static void checkInit()
 41		{
 42			if(sSingletonMap == NULL)
 43			{
 44				sSingletonMap = new TypeMap();
 45			}
 46		}
 47
 48	public:
 49		template<typename T> static void * & get()
 50		{
 51			std::string name(typeid(T).name());
 52
 53			checkInit();
 54
 55			// the first entry of the pair returned by insert will be either the existing
 56			// iterator matching our key, or the newly inserted NULL initialized entry
 57			// see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
 58			TypeMap::iterator result =
 59				sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first;
 60
 61			return result->second;
 62		}
 63};
 64
 65// LLSingleton implements the getInstance() method part of the Singleton
 66// pattern. It can't make the derived class constructors protected, though, so
 67// you have to do that yourself.
 68//
 69// There are two ways to use LLSingleton. The first way is to inherit from it
 70// while using the typename that you'd like to be static as the template
 71// parameter, like so:
 72//
 73//   class Foo: public LLSingleton<Foo>{};
 74//
 75//   Foo& instance = Foo::instance();
 76//
 77// The second way is to use the singleton class directly, without inheritance:
 78//
 79//   typedef LLSingleton<Foo> FooSingleton;
 80//
 81//   Foo& instance = FooSingleton::instance();
 82//
 83// In this case, the class being managed as a singleton needs to provide an
 84// initSingleton() method since the LLSingleton virtual method won't be
 85// available
 86//
 87// As currently written, it is not thread-safe.
 88
 89template <typename DERIVED_TYPE>
 90class LLSingleton : private boost::noncopyable
 91{
 92	
 93private:
 94	typedef enum e_init_state
 95	{
 96		UNINITIALIZED,
 97		CONSTRUCTING,
 98		INITIALIZING,
 99		INITIALIZED,
100		DELETED
101	} EInitState;
102	
103	// stores pointer to singleton instance
104	// and tracks initialization state of singleton
105	struct SingletonInstanceData
106	{
107		EInitState		mInitState;
108		DERIVED_TYPE*	mSingletonInstance;
109		
110		SingletonInstanceData()
111		:	mSingletonInstance(NULL),
112			mInitState(UNINITIALIZED)
113		{}
114
115		~SingletonInstanceData()
116		{
117			if (mInitState != DELETED)
118			{
119				deleteSingleton();
120			}
121		}
122	};
123	
124public:
125	virtual ~LLSingleton()
126	{
127		SingletonInstanceData& data = getData();
128		data.mSingletonInstance = NULL;
129		data.mInitState = DELETED;
130	}
131
132	/**
133	 * @brief Immediately delete the singleton.
134	 *
135	 * A subsequent call to LLProxy::getInstance() will construct a new
136	 * instance of the class.
137	 *
138	 * LLSingletons are normally destroyed after main() has exited and the C++
139	 * runtime is cleaning up statically-constructed objects. Some classes
140	 * derived from LLSingleton have objects that are part of a runtime system
141	 * that is terminated before main() exits. Calling the destructor of those
142	 * objects after the termination of their respective systems can cause
143	 * crashes and other problems during termination of the project. Using this
144	 * method to destroy the singleton early can prevent these crashes.
145	 *
146	 * An example where this is needed is for a LLSingleton that has an APR
147	 * object as a member that makes APR calls on destruction. The APR system is
148	 * shut down explicitly before main() exits. This causes a crash on exit.
149	 * Using this method before the call to apr_terminate() and NOT calling
150	 * getInstance() again will prevent the crash.
151	 */
152	static void deleteSingleton()
153	{
154		delete getData().mSingletonInstance;
155		getData().mSingletonInstance = NULL;
156		getData().mInitState = DELETED;
157	}
158
159	static SingletonInstanceData& getData()
160	{
161		// this is static to cache the lookup results
162		static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
163
164		// *TODO - look into making this threadsafe
165		if(NULL == registry)
166		{
167			static SingletonInstanceData data;
168			registry = &data;
169		}
170
171		return *static_cast<SingletonInstanceData *>(registry);
172	}
173
174	static DERIVED_TYPE* getInstance()
175	{
176		SingletonInstanceData& data = getData();
177
178		if (data.mInitState == CONSTRUCTING)
179		{
180			llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl;
181		}
182
183		if (data.mInitState == DELETED)
184		{
185			llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl;
186		}
187		
188		if (!data.mSingletonInstance) 
189		{
190			data.mInitState = CONSTRUCTING;
191			data.mSingletonInstance = new DERIVED_TYPE(); 
192			data.mInitState = INITIALIZING;
193			data.mSingletonInstance->initSingleton(); 
194			data.mInitState = INITIALIZED;	
195		}
196		
197		return data.mSingletonInstance;
198	}
199
200	// Reference version of getInstance()
201	// Preferred over getInstance() as it disallows checking for NULL
202	static DERIVED_TYPE& instance()
203	{
204		return *getInstance();
205	}
206	
207	// Has this singleton been created uet?
208	// Use this to avoid accessing singletons before the can safely be constructed
209	static bool instanceExists()
210	{
211		return getData().mInitState == INITIALIZED;
212	}
213	
214	// Has this singleton already been deleted?
215	// Use this to avoid accessing singletons from a static object's destructor
216	static bool destroyed()
217	{
218		return getData().mInitState == DELETED;
219	}
220
221private:
222	virtual void initSingleton() {}
223};
224
225#endif