// Copyright (C) 2014 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef EMUGL_COMMON_LAZY_INSTANCE_H #define EMUGL_COMMON_LAZY_INSTANCE_H #include #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN 1 # include #endif namespace emugl { namespace internal { // A LazyInstance is a helper template that can be used to perform // thread-safe lazy initialization of static C++ objects without forcing // the generation of C++ static constructors in the final executable. // // In a nutshell, you can replace a statement like: // // static Foo gFoo; // // With: // // static LazyInstance gFoo = LAZY_INSTANCE_INIT; // // In the first case, a hidden static C++ constructor is embedded in the // final executable, and executed at *load* *time* to call the Foo::Foo // constructor on the gFoo object. // // On the second case, gFoo will only be initialized lazily, i.e. the first // time any code actually tries to access the variable. // // Note that access is slightly different, i.e.: // // gFoo.get() returns a reference to the lazy-initialized object. // gFoo.ptr() returns a pointer to it. // gFoo->Something() is equivalent to doing gFoo.ptr()->Something(). // // 'gFoo' is stored in the .bss section and this doesn't use heap allocation. // This class can only be used to perform lazy initialization through the // class' default constructor. For more specialized cases, you will have // to create a derived class, e.g.: // // class FoorWithDefaultParams : public Foo { // public: // FooWithDefaultParams() : Foo() {} // }; // // LazyInstance gFoo = LAZY_INSTANCE_INIT; // // The implementation of LazyInstance relies on atomic operations and // POD-struct class definitions, i.e. one that doesn't have any constructor, // destructor, virtual members, or private ones, and that can be // zero-initialized at link time. // // You can also use LazyInstance<> instances as static local variables, // e.g.: // // Foo* getFooSingleton() { // static LazyInstance sFoo = LAZY_INSTANCE_INIT; // return sFoo.ptr(); // } // // This is useful on Windows which doesn't support thread-safe lazy // initialization of static C++ local variables, or when the code is // compiled with -fno-threadsafe-statics. // // This class is heavily inspired by Chromium's implementation of the // same-named class (see $CHROMIUM/src/base/lazy_instance.h). // Atomic state variable type. Used to ensure to synchronize concurrent // initialization and access without incurring the full cost of a mutex // lock/unlock. struct LazyInstanceState { enum { STATE_INIT = 0, STATE_CONSTRUCTING = 1, STATE_DONE = 2, }; bool inInitState(); bool needConstruction(); void doneConstructing(); #ifdef _WIN32 typedef LONG volatile AtomicType; #else typedef int volatile AtomicType; #endif volatile AtomicType mState; }; #define LAZY_INSTANCE_STATE_INIT \ { ::emugl::internal::LazyInstanceState::STATE_INIT } } // namespace internal // LazyInstance template definition, see comment above for usage // instructions. It is crucial to make this a POD-struct compatible // type [1]. // // [1] http://en.wikipedia.org/wiki/Plain_Old_Data_Structures // template struct LazyInstance { bool hasInstance() const { return !mState.inInitState(); } T& get() const { return *ptr(); } T* ptr() const; const T* operator->() const { return ptr(); } T* operator->() { return ptr(); } T& operator*() { return get(); } // Really private, do not use. union { mutable internal::LazyInstanceState mState; double mPadding; }; mutable char mStorage[sizeof(T)]; }; // Initialization value, must resolve to all-0 to ensure the object // instance is actually placed in the .bss #define LAZY_INSTANCE_INIT { { LAZY_INSTANCE_STATE_INIT }, { 0 } } template T* LazyInstance::ptr() const { if (mState.needConstruction()) { new (mStorage) T(); mState.doneConstructing(); } return reinterpret_cast(mStorage); } } // namespace emugl #endif // EMUGL_COMMON_LAZY_INSTANCE_H