diff options
author | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-15 13:31:49 +0000 |
---|---|---|
committer | joth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-15 13:31:49 +0000 |
commit | 6de0fd1d935e8c6c9257f1082dbd227acb1a06b1 (patch) | |
tree | 0ed5bc4ef9c2da0b498c30e562218f4528eaac9e /base/lazy_instance.h | |
parent | 0f86c358fdb5e47aa9cd4a99b12da5e66507d080 (diff) | |
download | chromium_src-6de0fd1d935e8c6c9257f1082dbd227acb1a06b1.zip chromium_src-6de0fd1d935e8c6c9257f1082dbd227acb1a06b1.tar.gz chromium_src-6de0fd1d935e8c6c9257f1082dbd227acb1a06b1.tar.bz2 |
Allow linker initialization of lazy instance
Using the initializer list construct = {0} allows the object to be linker initialized.
Modify the LazyInstance class design to make it a pod aggregate type that can be linker initialized this way. Also combines the instance and state members, in line with the Singleton<> class design.
Introduces a new LAZY_INSTANCE_INITIALIZER macro specifically for using to init all lazy instances + modify all existing callsites to use it. (Old code would no longer compile)
BUG=94925
TEST=existing tests pass. http://build.chromium.org/f/chromium/perf/linux-release/sizes/report.html?history=150&header=chrome-si&graph=chrome-si&rev=-1 should step downward.
TBR=jam@chromium.org,rvargas@chromium.org,darin@chromium.org,ben@chromium.org,apatrick@chromium.org,akalin@chromium.org
Review URL: http://codereview.chromium.org/8491043
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110076 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/lazy_instance.h')
-rw-r--r-- | base/lazy_instance.h | 148 |
1 files changed, 74 insertions, 74 deletions
diff --git a/base/lazy_instance.h b/base/lazy_instance.h index ac94a00..ededc73 100644 --- a/base/lazy_instance.h +++ b/base/lazy_instance.h @@ -14,7 +14,7 @@ // LazyInstance is completely thread safe, assuming that you create it safely. // The class was designed to be POD initialized, so it shouldn't require a // static constructor. It really only makes sense to declare a LazyInstance as -// a global variable using the base::LinkerInitialized constructor. +// a global variable using the LAZY_INSTANCE_INITIALIZER initializer. // // LazyInstance is similar to Singleton, except it does not have the singleton // property. You can have multiple LazyInstance's of the same type, and each @@ -24,7 +24,7 @@ // requires that Type be a complete type so we can determine the size. // // Example usage: -// static LazyInstance<MyClass> my_instance(base::LINKER_INITIALIZED); +// static LazyInstance<MyClass> my_instance = LAZY_INSTANCE_INITIALIZER; // void SomeMethod() { // my_instance.Get().SomeMethod(); // MyClass::SomeMethod() // @@ -45,6 +45,12 @@ #include "base/third_party/dynamic_annotations/dynamic_annotations.h" #include "base/threading/thread_restrictions.h" +// LazyInstance uses its own struct initializer-list style static +// initialization, as base's LINKER_INITIALIZED requires a constructor and on +// some compilers (notably gcc 4.4) this still ends up needing runtime +// initialization. +#define LAZY_INSTANCE_INITIALIZER {0} + namespace base { template <typename Type> @@ -79,53 +85,36 @@ struct LeakyLazyInstanceTraits { } }; -// We pull out some of the functionality into a non-templated base, so that we +// We pull out some of the functionality into non-templated functions, so we // can implement the more complicated pieces out of line in the .cc file. -class BASE_EXPORT LazyInstanceHelper { - protected: - enum { - STATE_EMPTY = 0, - STATE_CREATING = 1, - STATE_CREATED = 2 - }; - - explicit LazyInstanceHelper(LinkerInitialized /*unused*/) {/* state_ is 0 */} - - // Declaring a destructor (even if it's empty) will cause MSVC to register a - // static initializer to register the empty destructor with atexit(). - - // A destructor is intentionally not defined. If we were to say - // ~LazyInstanceHelper() { } - // Even though it's empty, a destructor will still be generated. - // In order for the constructor to be called for static variables, - // it will be registered as a callback at runtime with AtExit(). - // We don't want this, so we don't declare a destructor at all, - // effectively keeping the type POD (at least in terms of - // initialization and destruction). - - // Check if instance needs to be created. If so return true otherwise - // if another thread has beat us, wait for instance to be created and - // return false. - bool NeedsInstance(); - - // After creating an instance, call this to register the dtor to be called - // at program exit and to update the state to STATE_CREATED. - void CompleteInstance(void* instance, void (*dtor)(void*)); - - base::subtle::Atomic32 state_; +namespace internal { - private: - DISALLOW_COPY_AND_ASSIGN(LazyInstanceHelper); -}; +// Our AtomicWord doubles as a spinlock, where a value of +// kBeingCreatedMarker means the spinlock is being held for creation. +static const subtle::AtomicWord kLazyInstanceStateCreating = 1; + +// Check if instance needs to be created. If so return true otherwise +// if another thread has beat us, wait for instance to be created and +// return false. +BASE_EXPORT bool NeedsLazyInstance(subtle::AtomicWord* state); + +// After creating an instance, call this to register the dtor to be called +// at program exit and to update the atomic state to hold the |new_instance| +BASE_EXPORT void CompleteLazyInstance(subtle::AtomicWord* state, + subtle::AtomicWord new_instance, + void* lazy_instance, + void (*dtor)(void*)); + +} // namespace internal template <typename Type, typename Traits = DefaultLazyInstanceTraits<Type> > -class LazyInstance : public LazyInstanceHelper { +class LazyInstance { public: - explicit LazyInstance(LinkerInitialized x) : LazyInstanceHelper(x) { } - - // Declaring a destructor (even if it's empty) will cause MSVC to register a - // static initializer to register the empty destructor with atexit(). - // Refer to the destructor-related comment in LazyInstanceHelper. + // Do not define a destructor, as doing so makes LazyInstance a + // non-POD-struct. We don't want that because then a static initializer will + // be created to register the (empty) destructor with atexit() under MSVC, for + // example. We handle destruction of the contained Type class explicitly via + // the OnExit member function, where needed. // ~LazyInstance() {} Type& Get() { @@ -136,61 +125,72 @@ class LazyInstance : public LazyInstanceHelper { #ifndef NDEBUG // Avoid making TLS lookup on release builds. if (!Traits::kAllowedToAccessOnNonjoinableThread) - base::ThreadRestrictions::AssertSingletonAllowed(); + ThreadRestrictions::AssertSingletonAllowed(); #endif + // If any bit in the created mask is true, the instance has already been + // fully constructed. + static const subtle::AtomicWord kLazyInstanceCreatedMask = + ~internal::kLazyInstanceStateCreating; // We will hopefully have fast access when the instance is already created. - // Since a thread sees state_ != STATE_CREATED at most once, - // the load is taken out of NeedsInstance() as a fast-path. + // Since a thread sees private_instance_ == 0 or kLazyInstanceStateCreating + // at most once, the load is taken out of NeedsInstance() as a fast-path. // The load has acquire memory ordering as a thread which sees - // state_ == STATE_CREATED needs to acquire visibility over - // the associated data (buf_). Pairing Release_Store is in - // CompleteInstance(). - if ((base::subtle::Acquire_Load(&state_) != STATE_CREATED) && - NeedsInstance()) { - // Create the instance in the space provided by |buf_|. - instance_ = Traits::New(buf_); - CompleteInstance(this, Traits::kRegisterOnExit ? OnExit : NULL); + // private_instance_ > creating needs to acquire visibility over + // the associated data (private_buf_). Pairing Release_Store is in + // CompleteLazyInstance(). + subtle::AtomicWord value = subtle::Acquire_Load(&private_instance_); + if (!(value & kLazyInstanceCreatedMask) && + internal::NeedsLazyInstance(&private_instance_)) { + // Create the instance in the space provided by |private_buf_|. + value = reinterpret_cast<subtle::AtomicWord>(Traits::New(private_buf_)); + internal::CompleteLazyInstance(&private_instance_, value, this, + Traits::kRegisterOnExit ? OnExit : NULL); } // This annotation helps race detectors recognize correct lock-less // synchronization between different threads calling Pointer(). // We suggest dynamic race detection tool that "Traits::New" above - // and CompleteInstance(...) happens before "return instance_" below. - // See the corresponding HAPPENS_BEFORE in CompleteInstance(...). - ANNOTATE_HAPPENS_AFTER(&state_); - return instance_; + // and CompleteLazyInstance(...) happens before "return instance()" below. + // See the corresponding HAPPENS_BEFORE in CompleteLazyInstance(...). + ANNOTATE_HAPPENS_AFTER(&private_instance_); + return instance(); } bool operator==(Type* p) { - switch (base::subtle::NoBarrier_Load(&state_)) { - case STATE_EMPTY: + switch (subtle::NoBarrier_Load(&private_instance_)) { + case 0: return p == NULL; - case STATE_CREATING: - return static_cast<int8*>(static_cast<void*>(p)) == buf_; - case STATE_CREATED: - return p == instance_; + case internal::kLazyInstanceStateCreating: + return static_cast<int8*>(static_cast<void*>(p)) == private_buf_; default: - return false; + return p == instance(); } } + // Effectively private: member data is only public to allow the linker to + // statically initialize it. DO NOT USE FROM OUTSIDE THIS CLASS. + + // Note this must use AtomicWord, not Atomic32, to ensure correct alignment + // of |private_buf_| on 64 bit architectures. (This member must be first to + // allow the syntax used in LAZY_INSTANCE_INITIALIZER to work correctly.) + subtle::AtomicWord private_instance_; + int8 private_buf_[sizeof(Type)]; // Preallocated space for the Type instance. + private: + Type* instance() { + return reinterpret_cast<Type*>(subtle::NoBarrier_Load(&private_instance_)); + } + // Adapter function for use with AtExit. This should be called single // threaded, so don't synchronize across threads. // Calling OnExit while the instance is in use by other threads is a mistake. static void OnExit(void* lazy_instance) { LazyInstance<Type, Traits>* me = reinterpret_cast<LazyInstance<Type, Traits>*>(lazy_instance); - Traits::Delete(me->instance_); - me->instance_ = NULL; - base::subtle::Release_Store(&me->state_, STATE_EMPTY); + Traits::Delete(me->instance()); + subtle::Release_Store(&me->private_instance_, 0); } - - Type *instance_; - int8 buf_[sizeof(Type)]; // Preallocate the space for the Type instance. - - DISALLOW_COPY_AND_ASSIGN(LazyInstance); }; } // namespace base |