summaryrefslogtreecommitdiffstats
path: root/base/singleton.h
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 21:49:38 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 21:49:38 +0000
commitd7cae12696b96500c05dd2d430f6238922c20c96 (patch)
treeecff27b367735535b2a66477f8cd89d3c462a6c0 /base/singleton.h
parentee2815e28d408216cf94e874825b6bcf76c69083 (diff)
downloadchromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.zip
chromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.tar.gz
chromium_src-d7cae12696b96500c05dd2d430f6238922c20c96.tar.bz2
Add base to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/singleton.h')
-rw-r--r--base/singleton.h293
1 files changed, 293 insertions, 0 deletions
diff --git a/base/singleton.h b/base/singleton.h
new file mode 100644
index 0000000..47c0c1d
--- /dev/null
+++ b/base/singleton.h
@@ -0,0 +1,293 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef BASE_SINGLETON_H__
+#define BASE_SINGLETON_H__
+
+#include <stdlib.h>
+
+#include <utility>
+
+#include "base/lock.h"
+#include "base/singleton_internal.h"
+
+#ifdef WIN32
+#include "base/fix_wp64.h"
+#else // WIN32
+#include <pthread.h>
+#endif // WIN32
+
+// Default traits for Singleton<Type>. Calls operator new and operator delete on
+// the object. Registers automatic deletion at library unload or process exit.
+// Overload if you need arguments or another memory allocation function.
+template<typename Type>
+struct DefaultSingletonTraits {
+ // Allocates the object.
+ static Type* New() {
+ // The parenthesis is very important here; it forces POD type
+ // initialization.
+ return new Type();
+ }
+
+ // Destroys the object.
+ static void Delete(Type* x) {
+ delete x;
+ }
+
+ // Set to true to automatically register deletion of the object on library
+ // unload or process exit.
+ static const bool kRegisterAtExit = true;
+
+ // Note: Only apply on Windows. Has *no effect* on other platform.
+ // When set to true, it signals that Trait::New() *must* not be called
+ // multiple times at construction. Anything that must be done to not enter
+ // this situation should be done at all cost. This simply involves creating a
+ // temporary lock.
+ static const bool kMustCallNewExactlyOnce = false;
+};
+
+
+// The Singleton<Type, Traits, DifferentiatingType> class manages a single
+// instance of Type which will be created on first use and will be destroyed at
+// library unload (or on normal process exit). The Trait::Delete function will
+// not be called on abnormal process exit.
+//
+// DifferentiatingType is used as a key to differentiate two different
+// singletons having the same memory allocation functions but serving a
+// different purpose. This is mainly used for Locks serving different purposes.
+//
+// Example usages: (none are preferred, they all result in the same code)
+// 1. FooClass* ptr = Singleton<FooClass>::get();
+// ptr->Bar();
+// 2. Singleton<FooClass>()->Bar();
+// 3. Singleton<FooClass>::get()->Bar();
+//
+// Singleton<> has no non-static members and doesn't need to actually be
+// instantiated. It does no harm to instantiate it and use it as a class member
+// or at global level since it is acting as a POD type.
+//
+// This class is itself thread-safe. The underlying Type must of course be
+// thread-safe if you want to use it concurrently. Two parameters may be tuned
+// depending on the user's requirements.
+//
+// Glossary:
+// MCNEO = kMustCallNewExactlyOnce
+// RAE = kRegisterAtExit
+//
+// On every platform, if Traits::RAE is true, the singleton will be destroyed at
+// library unload or process exit. if Traits::RAE is false, the singleton will
+// not be freed at library unload or process exit, thus the singleton will be
+// leaked if it is ever accessed. Traits::RAE shouldn't be false unless
+// absolutely necessary. Remember that the heap where the object is allocated
+// may be destroyed by the CRT anyway.
+//
+// On Windows, now the fun begins. Traits::New() may be called more than once
+// concurrently, but no user will gain access to the object until the winning
+// Traits::New() call is completed.
+//
+// On Windows, if Traits::MCNEO and Traits::RAE are both false,
+// Traits::Delete() can still be called. The reason is that a race condition can
+// occur during the object creation which will cause Traits::Delete() to be
+// called even if Traits::RAE is false, so Traits::Delete() should still be
+// implemented or objects may be leaked when there is a race condition in
+// creating the singleton. Even though this case is very rare, it may happen in
+// practice. To work around this situation, before creating a multithreaded
+// environment, be sure to call Singleton<>::get() to force the creation of the
+// instance.
+//
+// On Windows, If Traits::MCNEO is true, a temporary lock per singleton will be
+// created to ensure that Trait::New() is only called once.
+//
+// If you want to ensure that your class can only exist as a singleton, make
+// its constructors private, and make DefaultSingletonTraits<> a friend:
+//
+// #include "base/singleton.h"
+// class FooClass {
+// public:
+// void Bar() { ... }
+// private:
+// FooClass() { ... }
+// friend DefaultSingletonTraits<FooClass>;
+//
+// DISALLOW_EVIL_CONSTRUCTORS(FooClass);
+// };
+//
+// Caveats:
+// (a) Every call to get(), operator->() and operator*() incurs some overhead
+// (16ns on my P4/2.8GHz) to check whether the object has already been
+// initialized. You may wish to cache the result of get(); it will not
+// change.
+//
+// (b) Your factory function must never throw an exception. This class is not
+// exception-safe.
+//
+// (c) On Windows at least, if Traits::kMustCallNewExactlyOnce is false,
+// Traits::New() may be called two times in two different threads at the
+// same time so it must not have side effects. Set
+// Traits::kMustCallNewExactlyOnce to true to alleviate this issue, at
+// the cost of a slight increase of memory use and creation time.
+//
+template <typename Type,
+ typename Traits = DefaultSingletonTraits<Type>,
+ typename DifferentiatingType = Type>
+class Singleton
+ : public SingletonStorage<
+ Type,
+ std::pair<Traits, DifferentiatingType>,
+ UseVolatileSingleton<Traits::kMustCallNewExactlyOnce>::value> {
+ public:
+ // This class is safe to be constructed and copy-constructed since it has no
+ // member.
+
+ // Return a pointer to the one true instance of the class.
+ static Type* get() {
+ Type* value = instance_;
+ // Acute readers may think: why not just discard "value" and use
+ // "instance_" directly? Astute readers will remark that instance_ can be a
+ // volatile pointer on Windows and hence the compiler would be forced to
+ // generate two memory reads instead of just one. Since this is the hotspot,
+ // this is inefficient.
+ if (value)
+ return value;
+
+#ifdef WIN32
+ // Statically determine which function to call.
+ LockedConstruct<Traits::kMustCallNewExactlyOnce>();
+#else // WIN32
+ // Posix platforms already have the functionality embedded.
+ pthread_once(&control_, SafeConstruct);
+#endif // WIN32
+ return instance_;
+ }
+
+ // Shortcuts.
+ Type& operator*() {
+ return *get();
+ }
+
+ Type* operator->() {
+ return get();
+ }
+
+ private:
+#ifdef WIN32
+ // Use bool template differentiation to make sure to not build the other part
+ // of the code. We don't want to instantiate Singleton<Lock, ...> uselessly.
+ template<bool kUseLock>
+ static void LockedConstruct() {
+ // Define a differentiating type for the Lock.
+ typedef std::pair<Type, std::pair<Traits, DifferentiatingType> >
+ LockDifferentiatingType;
+
+ // Object-type lock. Note that the lock singleton is different per singleton
+ // type.
+ AutoLock lock(*Singleton<Lock,
+ DefaultSingletonTraits<Lock>,
+ LockDifferentiatingType>());
+ // Now that we have the lock, look if the instance is created, if not yet,
+ // create it.
+ if (!instance_)
+ SafeConstruct();
+ }
+
+ template<>
+ static void LockedConstruct<false>() {
+ // Implemented using atomic compare-and-swap. The new object is
+ // constructed and used as the new value in the operation; if the
+ // compare fails, the new object will be deleted. Future implementations
+ // for Windows might use InitOnceExecuteOnce (Vista-only), similar in
+ // spirit to pthread_once.
+
+ // On Windows, multiple concurrent Traits::New() calls are tolerated.
+ Type* value = Traits::New();
+ if (InterlockedCompareExchangePointer(
+ reinterpret_cast<void* volatile*>(&instance_), value, NULL)) {
+ // Race condition, discard the temporary value.
+ Traits::Delete(value);
+ } else {
+ // Got it, register destruction at unload. atexit() is called on library
+ // unload. It is assumed that atexit() is itself thread safe. It is also
+ // assumed that registered functions by atexit are called in a thread
+ // safe manner. At least on Windows, they are called with the loader
+ // lock held. On Windows, the CRT use a structure similar to
+ // std::map<dll_handle,std::vector<registered_functions>> so the right
+ // functions are called on library unload, independent of having a DLL
+ // CRT or a static CRT or even both.
+ if (Traits::kRegisterAtExit)
+ atexit(&OnExit);
+ }
+ }
+#endif // WIN32
+
+ // SafeConstruct is guaranteed to be executed only once.
+ static void SafeConstruct() {
+ instance_ = Traits::New();
+
+ // Porting note: this code depends on some properties of atexit which are
+ // not guaranteed by the standard:
+ // - atexit must be thread-safe: its internal manipulation of the list of
+ // registered functions must be tolerant of multiple threads attempting
+ // to register exit routines simultaneously.
+ // - exit routines must run when the executable module that contains them
+ // is unloaded. For routines in by dynamically-loaded modules, this
+ // may be sooner than process termination.
+ // - atexit should support an arbitrary number of registered exit
+ // routines, or at least should support more routines than will
+ // actually be registered (the standard only requires 32).
+ // The atexit implementations in contemporary versions of Mac OS X, glibc,
+ // and the Windows C runtime provide these capabilities. To port to other
+ // systems with less-advanced (even though still standard-conforming)
+ // atexit implmentations, consider alternatives such as __cxa_atexit or
+ // custom termination sections.
+ if (Traits::kRegisterAtExit)
+ atexit(OnExit);
+ }
+
+ // Adapter function for use with atexit().
+ static void OnExit() {
+ if (!instance_)
+ return;
+ Traits::Delete(instance_);
+ instance_ = NULL;
+ }
+
+#ifndef WIN32
+ static pthread_once_t control_;
+#endif // !WIN32
+};
+
+#ifndef WIN32
+
+template <typename Type, typename Traits, typename DifferentiatingType>
+pthread_once_t Singleton<Type, Traits, DifferentiatingType>::control_ =
+ PTHREAD_ONCE_INIT;
+
+#endif // !WIN32
+
+#endif // BASE_SINGLETON_H__