1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stddef.h>
6
7 #include <memory>
8 #include <utility>
9 #include <vector>
10
11 #include "base/at_exit.h"
12 #include "base/atomic_sequence_num.h"
13 #include "base/atomicops.h"
14 #include "base/barrier_closure.h"
15 #include "base/functional/bind.h"
16 #include "base/functional/callback.h"
17 #include "base/lazy_instance.h"
18 #include "base/memory/aligned_memory.h"
19 #include "base/memory/raw_ptr.h"
20 #include "base/system/sys_info.h"
21 #include "base/threading/platform_thread.h"
22 #include "base/threading/simple_thread.h"
23 #include "base/time/time.h"
24 #include "build/build_config.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 namespace {
28
29 base::AtomicSequenceNumber constructed_seq_;
30 base::AtomicSequenceNumber destructed_seq_;
31
32 class ConstructAndDestructLogger {
33 public:
ConstructAndDestructLogger()34 ConstructAndDestructLogger() {
35 constructed_seq_.GetNext();
36 }
37 ConstructAndDestructLogger(const ConstructAndDestructLogger&) = delete;
38 ConstructAndDestructLogger& operator=(const ConstructAndDestructLogger&) =
39 delete;
~ConstructAndDestructLogger()40 ~ConstructAndDestructLogger() {
41 destructed_seq_.GetNext();
42 }
43 };
44
45 class SlowConstructor {
46 public:
SlowConstructor()47 SlowConstructor() : some_int_(0) {
48 // Sleep for 1 second to try to cause a race.
49 base::PlatformThread::Sleep(base::Seconds(1));
50 ++constructed;
51 some_int_ = 12;
52 }
53 SlowConstructor(const SlowConstructor&) = delete;
54 SlowConstructor& operator=(const SlowConstructor&) = delete;
some_int() const55 int some_int() const { return some_int_; }
56
57 static int constructed;
58 private:
59 int some_int_;
60 };
61
62 // static
63 int SlowConstructor::constructed = 0;
64
65 class SlowDelegate : public base::DelegateSimpleThread::Delegate {
66 public:
SlowDelegate(base::LazyInstance<SlowConstructor>::DestructorAtExit * lazy)67 explicit SlowDelegate(
68 base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy)
69 : lazy_(lazy) {}
70 SlowDelegate(const SlowDelegate&) = delete;
71 SlowDelegate& operator=(const SlowDelegate&) = delete;
72
Run()73 void Run() override {
74 EXPECT_EQ(12, lazy_->Get().some_int());
75 EXPECT_EQ(12, lazy_->Pointer()->some_int());
76 }
77
78 private:
79 raw_ptr<base::LazyInstance<SlowConstructor>::DestructorAtExit> lazy_;
80 };
81
82 } // namespace
83
84 base::LazyInstance<ConstructAndDestructLogger>::DestructorAtExit lazy_logger =
85 LAZY_INSTANCE_INITIALIZER;
86
TEST(LazyInstanceTest,Basic)87 TEST(LazyInstanceTest, Basic) {
88 {
89 base::ShadowingAtExitManager shadow;
90
91 EXPECT_FALSE(lazy_logger.IsCreated());
92 EXPECT_EQ(0, constructed_seq_.GetNext());
93 EXPECT_EQ(0, destructed_seq_.GetNext());
94
95 lazy_logger.Get();
96 EXPECT_TRUE(lazy_logger.IsCreated());
97 EXPECT_EQ(2, constructed_seq_.GetNext());
98 EXPECT_EQ(1, destructed_seq_.GetNext());
99
100 lazy_logger.Pointer();
101 EXPECT_TRUE(lazy_logger.IsCreated());
102 EXPECT_EQ(3, constructed_seq_.GetNext());
103 EXPECT_EQ(2, destructed_seq_.GetNext());
104 }
105 EXPECT_FALSE(lazy_logger.IsCreated());
106 EXPECT_EQ(4, constructed_seq_.GetNext());
107 EXPECT_EQ(4, destructed_seq_.GetNext());
108 }
109
110 base::LazyInstance<SlowConstructor>::DestructorAtExit lazy_slow =
111 LAZY_INSTANCE_INITIALIZER;
112
TEST(LazyInstanceTest,ConstructorThreadSafety)113 TEST(LazyInstanceTest, ConstructorThreadSafety) {
114 {
115 base::ShadowingAtExitManager shadow;
116
117 SlowDelegate delegate(&lazy_slow);
118 EXPECT_EQ(0, SlowConstructor::constructed);
119
120 base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
121 pool.AddWork(&delegate, 20);
122 EXPECT_EQ(0, SlowConstructor::constructed);
123
124 pool.Start();
125 pool.JoinAll();
126 EXPECT_EQ(1, SlowConstructor::constructed);
127 }
128 }
129
130 namespace {
131
132 // DeleteLogger is an object which sets a flag when it's destroyed.
133 // It accepts a bool* and sets the bool to true when the dtor runs.
134 class DeleteLogger {
135 public:
DeleteLogger()136 DeleteLogger() : deleted_(nullptr) {}
~DeleteLogger()137 ~DeleteLogger() { *deleted_ = true; }
138
SetDeletedPtr(bool * deleted)139 void SetDeletedPtr(bool* deleted) {
140 deleted_ = deleted;
141 }
142
143 private:
144 raw_ptr<bool> deleted_;
145 };
146
147 } // anonymous namespace
148
TEST(LazyInstanceTest,LeakyLazyInstance)149 TEST(LazyInstanceTest, LeakyLazyInstance) {
150 // Check that using a plain LazyInstance causes the dtor to run
151 // when the AtExitManager finishes.
152 bool deleted1 = false;
153 {
154 base::ShadowingAtExitManager shadow;
155 static base::LazyInstance<DeleteLogger>::DestructorAtExit test =
156 LAZY_INSTANCE_INITIALIZER;
157 test.Get().SetDeletedPtr(&deleted1);
158 }
159 EXPECT_TRUE(deleted1);
160
161 // Check that using a *leaky* LazyInstance makes the dtor not run
162 // when the AtExitManager finishes.
163 bool deleted2 = false;
164 {
165 base::ShadowingAtExitManager shadow;
166 static base::LazyInstance<DeleteLogger>::Leaky
167 test = LAZY_INSTANCE_INITIALIZER;
168 test.Get().SetDeletedPtr(&deleted2);
169 }
170 EXPECT_FALSE(deleted2);
171 }
172
173 namespace {
174
175 template <size_t alignment>
176 class AlignedData {
177 public:
178 AlignedData() = default;
179 ~AlignedData() = default;
180 alignas(alignment) char data_[alignment];
181 };
182
183 } // namespace
184
TEST(LazyInstanceTest,Alignment)185 TEST(LazyInstanceTest, Alignment) {
186 using base::LazyInstance;
187
188 // Create some static instances with increasing sizes and alignment
189 // requirements. By ordering this way, the linker will need to do some work to
190 // ensure proper alignment of the static data.
191 static LazyInstance<AlignedData<4>>::DestructorAtExit align4 =
192 LAZY_INSTANCE_INITIALIZER;
193 static LazyInstance<AlignedData<32>>::DestructorAtExit align32 =
194 LAZY_INSTANCE_INITIALIZER;
195 static LazyInstance<AlignedData<4096>>::DestructorAtExit align4096 =
196 LAZY_INSTANCE_INITIALIZER;
197
198 EXPECT_TRUE(base::IsAligned(align4.Pointer(), 4));
199 EXPECT_TRUE(base::IsAligned(align32.Pointer(), 32));
200 EXPECT_TRUE(base::IsAligned(align4096.Pointer(), 4096));
201 }
202
203 namespace {
204
205 // A class whose constructor busy-loops until it is told to complete
206 // construction.
207 class BlockingConstructor {
208 public:
BlockingConstructor()209 BlockingConstructor() {
210 EXPECT_FALSE(WasConstructorCalled());
211 base::subtle::NoBarrier_Store(&constructor_called_, 1);
212 EXPECT_TRUE(WasConstructorCalled());
213 while (!base::subtle::NoBarrier_Load(&complete_construction_))
214 base::PlatformThread::YieldCurrentThread();
215 done_construction_ = true;
216 }
217 BlockingConstructor(const BlockingConstructor&) = delete;
218 BlockingConstructor& operator=(const BlockingConstructor&) = delete;
~BlockingConstructor()219 ~BlockingConstructor() {
220 // Restore static state for the next test.
221 base::subtle::NoBarrier_Store(&constructor_called_, 0);
222 base::subtle::NoBarrier_Store(&complete_construction_, 0);
223 }
224
225 // Returns true if BlockingConstructor() was entered.
WasConstructorCalled()226 static bool WasConstructorCalled() {
227 return base::subtle::NoBarrier_Load(&constructor_called_);
228 }
229
230 // Instructs BlockingConstructor() that it may now unblock its construction.
CompleteConstructionNow()231 static void CompleteConstructionNow() {
232 base::subtle::NoBarrier_Store(&complete_construction_, 1);
233 }
234
done_construction() const235 bool done_construction() const { return done_construction_; }
236
237 private:
238 // Use Atomic32 instead of AtomicFlag for them to be trivially initialized.
239 static base::subtle::Atomic32 constructor_called_;
240 static base::subtle::Atomic32 complete_construction_;
241
242 bool done_construction_ = false;
243 };
244
245 // A SimpleThread running at |thread_type| which invokes |before_get| (optional)
246 // and then invokes Get() on the LazyInstance it's assigned.
247 class BlockingConstructorThread : public base::SimpleThread {
248 public:
BlockingConstructorThread(base::ThreadType thread_type,base::LazyInstance<BlockingConstructor>::DestructorAtExit * lazy,base::OnceClosure before_get)249 BlockingConstructorThread(
250 base::ThreadType thread_type,
251 base::LazyInstance<BlockingConstructor>::DestructorAtExit* lazy,
252 base::OnceClosure before_get)
253 : SimpleThread("BlockingConstructorThread", Options(thread_type)),
254 lazy_(lazy),
255 before_get_(std::move(before_get)) {}
256 BlockingConstructorThread(const BlockingConstructorThread&) = delete;
257 BlockingConstructorThread& operator=(const BlockingConstructorThread&) =
258 delete;
259
Run()260 void Run() override {
261 if (before_get_)
262 std::move(before_get_).Run();
263 EXPECT_TRUE(lazy_->Get().done_construction());
264 }
265
266 private:
267 raw_ptr<base::LazyInstance<BlockingConstructor>::DestructorAtExit> lazy_;
268 base::OnceClosure before_get_;
269 };
270
271 // static
272 base::subtle::Atomic32 BlockingConstructor::constructor_called_ = 0;
273 // static
274 base::subtle::Atomic32 BlockingConstructor::complete_construction_ = 0;
275
276 base::LazyInstance<BlockingConstructor>::DestructorAtExit lazy_blocking =
277 LAZY_INSTANCE_INITIALIZER;
278
279 } // namespace
280
281 // Tests that if the thread assigned to construct the LazyInstance runs at
282 // background priority : the foreground threads will yield to it enough for it
283 // to eventually complete construction.
284 // This is a regression test for https://crbug.com/797129.
TEST(LazyInstanceTest,PriorityInversionAtInitializationResolves)285 TEST(LazyInstanceTest, PriorityInversionAtInitializationResolves) {
286 base::TimeTicks test_begin = base::TimeTicks::Now();
287
288 // Construct BlockingConstructor from a background thread.
289 BlockingConstructorThread background_getter(
290 base::ThreadType::kBackground, &lazy_blocking, base::OnceClosure());
291 background_getter.Start();
292
293 while (!BlockingConstructor::WasConstructorCalled())
294 base::PlatformThread::Sleep(base::Milliseconds(1));
295
296 // Spin 4 foreground thread per core contending to get the already under
297 // construction LazyInstance. When they are all running and poking at it :
298 // allow the background thread to complete its work.
299 const int kNumForegroundThreads = 4 * base::SysInfo::NumberOfProcessors();
300 std::vector<std::unique_ptr<base::SimpleThread>> foreground_threads;
301 base::RepeatingClosure foreground_thread_ready_callback =
302 base::BarrierClosure(
303 kNumForegroundThreads,
304 base::BindOnce(&BlockingConstructor::CompleteConstructionNow));
305 for (int i = 0; i < kNumForegroundThreads; ++i) {
306 foreground_threads.push_back(std::make_unique<BlockingConstructorThread>(
307 base::ThreadType::kDefault, &lazy_blocking,
308 foreground_thread_ready_callback));
309 foreground_threads.back()->Start();
310 }
311
312 // This test will hang if the foreground threads become stuck in
313 // LazyInstance::Get() per the background thread never being scheduled to
314 // complete construction.
315 for (auto& foreground_thread : foreground_threads)
316 foreground_thread->Join();
317 background_getter.Join();
318
319 // Fail if this test takes more than 5 seconds (it takes 5-10 seconds on a
320 // Z840 without r527445 but is expected to be fast (~30ms) with the fix).
321 EXPECT_LT(base::TimeTicks::Now() - test_begin, base::Seconds(5));
322 }
323