1 // Copyright (C) 2014 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef EMUGL_COMMON_LAZY_INSTANCE_H 16 #define EMUGL_COMMON_LAZY_INSTANCE_H 17 18 #include <new> 19 20 #ifdef _WIN32 21 # define WIN32_LEAN_AND_MEAN 1 22 # include <windows.h> 23 #endif 24 25 namespace emugl { 26 namespace internal { 27 28 // A LazyInstance is a helper template that can be used to perform 29 // thread-safe lazy initialization of static C++ objects without forcing 30 // the generation of C++ static constructors in the final executable. 31 // 32 // In a nutshell, you can replace a statement like: 33 // 34 // static Foo gFoo; 35 // 36 // With: 37 // 38 // static LazyInstance<Foo> gFoo = LAZY_INSTANCE_INIT; 39 // 40 // In the first case, a hidden static C++ constructor is embedded in the 41 // final executable, and executed at *load* *time* to call the Foo::Foo 42 // constructor on the gFoo object. 43 // 44 // On the second case, gFoo will only be initialized lazily, i.e. the first 45 // time any code actually tries to access the variable. 46 // 47 // Note that access is slightly different, i.e.: 48 // 49 // gFoo.get() returns a reference to the lazy-initialized object. 50 // gFoo.ptr() returns a pointer to it. 51 // gFoo->Something() is equivalent to doing gFoo.ptr()->Something(). 52 // 53 // 'gFoo' is stored in the .bss section and this doesn't use heap allocation. 54 // This class can only be used to perform lazy initialization through the 55 // class' default constructor. For more specialized cases, you will have 56 // to create a derived class, e.g.: 57 // 58 // class FoorWithDefaultParams : public Foo { 59 // public: 60 // FooWithDefaultParams() : Foo(<default-parameters>) {} 61 // }; 62 // 63 // LazyInstance<FooWithDefaultParams> gFoo = LAZY_INSTANCE_INIT; 64 // 65 // The implementation of LazyInstance relies on atomic operations and 66 // POD-struct class definitions, i.e. one that doesn't have any constructor, 67 // destructor, virtual members, or private ones, and that can be 68 // zero-initialized at link time. 69 // 70 // You can also use LazyInstance<> instances as static local variables, 71 // e.g.: 72 // 73 // Foo* getFooSingleton() { 74 // static LazyInstance<Foo> sFoo = LAZY_INSTANCE_INIT; 75 // return sFoo.ptr(); 76 // } 77 // 78 // This is useful on Windows which doesn't support thread-safe lazy 79 // initialization of static C++ local variables, or when the code is 80 // compiled with -fno-threadsafe-statics. 81 // 82 // This class is heavily inspired by Chromium's implementation of the 83 // same-named class (see $CHROMIUM/src/base/lazy_instance.h). 84 85 // Atomic state variable type. Used to ensure to synchronize concurrent 86 // initialization and access without incurring the full cost of a mutex 87 // lock/unlock. 88 struct LazyInstanceState { 89 enum { 90 STATE_INIT = 0, 91 STATE_CONSTRUCTING = 1, 92 STATE_DONE = 2, 93 }; 94 95 bool inInitState(); 96 bool needConstruction(); 97 void doneConstructing(); 98 99 #ifdef _WIN32 100 typedef LONG volatile AtomicType; 101 #else 102 typedef int volatile AtomicType; 103 #endif 104 105 volatile AtomicType mState; 106 }; 107 108 #define LAZY_INSTANCE_STATE_INIT \ 109 { ::emugl::internal::LazyInstanceState::STATE_INIT } 110 111 } // namespace internal 112 113 // LazyInstance template definition, see comment above for usage 114 // instructions. It is crucial to make this a POD-struct compatible 115 // type [1]. 116 // 117 // [1] http://en.wikipedia.org/wiki/Plain_Old_Data_Structures 118 // 119 template <class T> 120 struct LazyInstance { 121 bool hasInstance() const { return !mState.inInitState(); } 122 123 T& get() const { return *ptr(); } 124 125 T* ptr() const; 126 127 const T* operator->() const { return ptr(); } 128 129 T* operator->() { return ptr(); } 130 131 T& operator*() { return get(); } 132 133 // Really private, do not use. 134 union { 135 mutable internal::LazyInstanceState mState; 136 double mPadding; 137 }; 138 mutable char mStorage[sizeof(T)]; 139 }; 140 141 // Initialization value, must resolve to all-0 to ensure the object 142 // instance is actually placed in the .bss 143 #define LAZY_INSTANCE_INIT { { LAZY_INSTANCE_STATE_INIT }, { 0 } } 144 145 template <class T> 146 T* LazyInstance<T>::ptr() const { 147 if (mState.needConstruction()) { 148 new (mStorage) T(); 149 mState.doneConstructing(); 150 } 151 return reinterpret_cast<T*>(mStorage); 152 } 153 154 } // namespace emugl 155 156 #endif // EMUGL_COMMON_LAZY_INSTANCE_H 157