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