1 // Copyright (C) 2014-2015 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 #pragma once
16
17 #include <atomic>
18 #include <new>
19 #include <type_traits>
20
21 namespace android {
22 namespace base {
23 namespace internal {
24
25 // Older GCC stdlib uses deprecated naming scheme has_xxx instead of is_xxx
26 #if (defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 4) || \
27 defined(__OLD_STD_VERSION__)
28 template <class T>
29 using is_trivially_default_constructible =
30 std::has_trivial_default_constructor<T>;
31 #else
32 template <class T>
33 using is_trivially_default_constructible =
34 std::is_trivially_default_constructible<T>;
35 #endif
36
37 // A LazyInstance is a helper template that can be used to perform
38 // thread-safe lazy initialization of static C++ objects without forcing
39 // the generation of C++ static constructors in the final executable.
40 //
41 // In a nutshell, you can replace a statement like:
42 //
43 // static Foo gFoo;
44 //
45 // With:
46 //
47 // static LazyInstance<Foo> gFoo = LAZY_INSTANCE_INIT;
48 //
49 // In the first case, a hidden static C++ constructor is embedded in the
50 // final executable, and executed at *load* *time* to call the Foo::Foo
51 // constructor on the gFoo object.
52 //
53 // On the second case, gFoo will only be initialized lazily, i.e. the first
54 // time any code actually tries to access the variable.
55 //
56 // Note that access is slightly different, i.e.:
57 //
58 // gFoo.get() returns a reference to the lazy-initialized object.
59 // gFoo.ptr() returns a pointer to it.
60 // gFoo->Something() is equivalent to doing gFoo.ptr()->Something().
61 //
62 // 'gFoo' is stored in the .bss section and this doesn't use heap allocation.
63 // This class can only be used to perform lazy initialization through the
64 // class' default constructor. For more specialized cases, you will have
65 // to create a derived class, e.g.:
66 //
67 // class FoorWithDefaultParams : public Foo {
68 // public:
69 // FooWithDefaultParams() : Foo(<default-parameters>) {}
70 // };
71 //
72 // LazyInstance<FooWithDefaultParams> gFoo = LAZY_INSTANCE_INIT;
73 //
74 // The implementation of LazyInstance relies on atomic operations and
75 // POD-struct class definitions, i.e. one that doesn't have any constructor,
76 // destructor, virtual members, or private ones, and that can be
77 // zero-initialized at link time.
78 //
79 // You can also use LazyInstance<> instances as static local variables,
80 // e.g.:
81 //
82 // Foo* getFooSingleton() {
83 // static LazyInstance<Foo> sFoo = LAZY_INSTANCE_INIT;
84 // return sFoo.ptr();
85 // }
86 //
87 // This is useful on Windows which doesn't support thread-safe lazy
88 // initialization of static C++ local variables, or on other platforms
89 // when the code is compiled with -fno-threadsafe-statics.
90 //
91 // This class is heavily inspired by Chromium's implementation of the
92 // same-named class (see $CHROMIUM/src/base/lazy_instance.h).
93
94 // Atomic state variable type. Used to ensure to synchronize concurrent
95 // initialization and access without incurring the full cost of a mutex
96 // lock/unlock.
97
98 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DEPRECATED !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
99 // Please don't use this macro. Use a function-local static of type
100 // android::base::NoDestructor<T> instead:
101 //
102 // Factory& Factory::GetInstance() {
103 // static base::NoDestructor<Factory> instance;
104 // return *instance;
105 // }
106 //
107 // From C++20 onwards this will no longer compile. See:
108 // See https://github.com/microsoft/STL/issues/661
109 // For details on issues and guarantees around atomic initialization.
110 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
111 struct LazyInstanceState {
112 enum class State : char {
113 Init = 0,
114 Constructing = 1,
115 Done = 2,
116 Destroying = 3,
117 };
118
119 bool inNoObjectState() const;
120 bool needConstruction();
121 void doneConstructing();
122
123 bool needDestruction();
124 void doneDestroying();
125
126 std::atomic<State> mState;
127 };
128
129 static_assert(std::is_standard_layout<LazyInstanceState>::value,
130 "LazyInstanceState is not a standard layout type");
131 #ifndef _MSC_VER
132 static_assert(is_trivially_default_constructible<LazyInstanceState>::value,
133 "LazyInstanceState can't be trivially default constructed");
134 #endif
135 } // namespace internal
136
137 class Lock;
138 class StaticLock;
139
140 // LazyInstance template definition, see comment above for usage
141 // instructions. It is crucial to make this a POD-struct compatible
142 // type [1].
143 //
144 // [1] http://en.wikipedia.org/wiki/Plain_Old_Data_Structures
145 //
146 template <class T>
147 struct LazyInstance {
148 static_assert(!std::is_same<T, Lock>::value &&
149 !std::is_same<T, StaticLock>::value,
150 "Don't use LazyInstance<Lock | StaticLock>, use StaticLock "
151 "by value instead");
152
hasInstanceLazyInstance153 bool hasInstance() const { return !mState.inNoObjectState(); }
154
getLazyInstance155 const T& get() const { return *ptr(); }
getLazyInstance156 T& get() { return *ptr(); }
157
158 const T* operator->() const { return ptr(); }
159 T* operator->() { return ptr(); }
160
161 const T& operator*() const { return get(); }
162 T& operator*() { return get(); }
163
ptrLazyInstance164 T* ptr() { return ptrInternal(); }
ptrLazyInstance165 const T* ptr() const { return ptrInternal(); }
166
clearLazyInstance167 void clear() {
168 if (mState.needDestruction()) {
169 reinterpret_cast<T*>(&mStorage)->~T();
170 mState.doneDestroying();
171 }
172 }
173
174 private:
175 T* ptrInternal() const;
176
177 using StorageT =
178 typename std::aligned_storage<sizeof(T),
179 std::alignment_of<T>::value>::type;
180
181 alignas(double) mutable internal::LazyInstanceState mState;
182 mutable StorageT mStorage;
183 };
184
185 // Initialization value, must resolve to all-0 to ensure the object
186 // instance is actually placed in the .bss
187 #define LAZY_INSTANCE_INIT \
188 {}
189
190 template <class T>
ptrInternal()191 T* LazyInstance<T>::ptrInternal() const {
192 // Make sure that LazyInstance<> instantiation remains static.
193 // NB: this can't go in a class scope as class is still incomplete there.
194 static_assert(std::is_standard_layout<LazyInstance>::value,
195 "LazyInstance<T> is not a standard layout type");
196 #ifndef _MSC_VER
197 // These checks are not working in vs2019..
198 static_assert(
199 internal::is_trivially_default_constructible<LazyInstance>::value,
200 "LazyInstance<T> can't be trivially default constructed");
201 #endif
202 if (mState.needConstruction()) {
203 new (&mStorage) T();
204 mState.doneConstructing();
205 }
206 return reinterpret_cast<T*>(&mStorage);
207 }
208
209 } // namespace base
210 } // namespace android
211