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.
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/bind.h"
16 #include "base/lazy_instance.h"
17 #include "base/memory/aligned_memory.h"
18 #include "base/system/sys_info.h"
19 #include "base/threading/platform_thread.h"
20 #include "base/threading/simple_thread.h"
21 #include "base/time/time.h"
22 #include "build/build_config.h"
23 #include "testing/gtest/include/gtest/gtest.h"
27 base::AtomicSequenceNumber constructed_seq_;
28 base::AtomicSequenceNumber destructed_seq_;
30 class ConstructAndDestructLogger {
32 ConstructAndDestructLogger() {
33 constructed_seq_.GetNext();
35 ~ConstructAndDestructLogger() {
36 destructed_seq_.GetNext();
40 DISALLOW_COPY_AND_ASSIGN(ConstructAndDestructLogger);
43 class SlowConstructor {
45 SlowConstructor() : some_int_(0) {
46 // Sleep for 1 second to try to cause a race.
47 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
51 int some_int() const { return some_int_; }
53 static int constructed;
57 DISALLOW_COPY_AND_ASSIGN(SlowConstructor);
61 int SlowConstructor::constructed = 0;
63 class SlowDelegate : public base::DelegateSimpleThread::Delegate {
65 explicit SlowDelegate(
66 base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy)
70 EXPECT_EQ(12, lazy_->Get().some_int());
71 EXPECT_EQ(12, lazy_->Pointer()->some_int());
75 base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy_;
77 DISALLOW_COPY_AND_ASSIGN(SlowDelegate);
82 base::LazyInstance<ConstructAndDestructLogger>::DestructorAtExit lazy_logger =
83 LAZY_INSTANCE_INITIALIZER;
85 TEST(LazyInstanceTest, Basic) {
87 base::ShadowingAtExitManager shadow;
89 EXPECT_FALSE(lazy_logger.IsCreated());
90 EXPECT_EQ(0, constructed_seq_.GetNext());
91 EXPECT_EQ(0, destructed_seq_.GetNext());
94 EXPECT_TRUE(lazy_logger.IsCreated());
95 EXPECT_EQ(2, constructed_seq_.GetNext());
96 EXPECT_EQ(1, destructed_seq_.GetNext());
98 lazy_logger.Pointer();
99 EXPECT_TRUE(lazy_logger.IsCreated());
100 EXPECT_EQ(3, constructed_seq_.GetNext());
101 EXPECT_EQ(2, destructed_seq_.GetNext());
103 EXPECT_FALSE(lazy_logger.IsCreated());
104 EXPECT_EQ(4, constructed_seq_.GetNext());
105 EXPECT_EQ(4, destructed_seq_.GetNext());
108 base::LazyInstance<SlowConstructor>::DestructorAtExit lazy_slow =
109 LAZY_INSTANCE_INITIALIZER;
111 TEST(LazyInstanceTest, ConstructorThreadSafety) {
113 base::ShadowingAtExitManager shadow;
115 SlowDelegate delegate(&lazy_slow);
116 EXPECT_EQ(0, SlowConstructor::constructed);
118 base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
119 pool.AddWork(&delegate, 20);
120 EXPECT_EQ(0, SlowConstructor::constructed);
124 EXPECT_EQ(1, SlowConstructor::constructed);
130 // DeleteLogger is an object which sets a flag when it's destroyed.
131 // It accepts a bool* and sets the bool to true when the dtor runs.
134 DeleteLogger() : deleted_(nullptr) {}
135 ~DeleteLogger() { *deleted_ = true; }
137 void SetDeletedPtr(bool* deleted) {
145 } // anonymous namespace
147 TEST(LazyInstanceTest, LeakyLazyInstance) {
148 // Check that using a plain LazyInstance causes the dtor to run
149 // when the AtExitManager finishes.
150 bool deleted1 = false;
152 base::ShadowingAtExitManager shadow;
153 static base::LazyInstance<DeleteLogger>::DestructorAtExit test =
154 LAZY_INSTANCE_INITIALIZER;
155 test.Get().SetDeletedPtr(&deleted1);
157 EXPECT_TRUE(deleted1);
159 // Check that using a *leaky* LazyInstance makes the dtor not run
160 // when the AtExitManager finishes.
161 bool deleted2 = false;
163 base::ShadowingAtExitManager shadow;
164 static base::LazyInstance<DeleteLogger>::Leaky
165 test = LAZY_INSTANCE_INITIALIZER;
166 test.Get().SetDeletedPtr(&deleted2);
168 EXPECT_FALSE(deleted2);
173 template <size_t alignment>
176 AlignedData() = default;
177 ~AlignedData() = default;
178 alignas(alignment) char data_[alignment];
183 TEST(LazyInstanceTest, Alignment) {
184 using base::LazyInstance;
186 // Create some static instances with increasing sizes and alignment
187 // requirements. By ordering this way, the linker will need to do some work to
188 // ensure proper alignment of the static data.
189 static LazyInstance<AlignedData<4>>::DestructorAtExit align4 =
190 LAZY_INSTANCE_INITIALIZER;
191 static LazyInstance<AlignedData<32>>::DestructorAtExit align32 =
192 LAZY_INSTANCE_INITIALIZER;
193 static LazyInstance<AlignedData<4096>>::DestructorAtExit align4096 =
194 LAZY_INSTANCE_INITIALIZER;
196 EXPECT_TRUE(base::IsAligned(align4.Pointer(), 4));
197 EXPECT_TRUE(base::IsAligned(align32.Pointer(), 32));
198 EXPECT_TRUE(base::IsAligned(align4096.Pointer(), 4096));
203 // A class whose constructor busy-loops until it is told to complete
205 class BlockingConstructor {
207 BlockingConstructor() {
208 EXPECT_FALSE(WasConstructorCalled());
209 base::subtle::NoBarrier_Store(&constructor_called_, 1);
210 EXPECT_TRUE(WasConstructorCalled());
211 while (!base::subtle::NoBarrier_Load(&complete_construction_))
212 base::PlatformThread::YieldCurrentThread();
213 done_construction_ = true;
216 ~BlockingConstructor() {
217 // Restore static state for the next test.
218 base::subtle::NoBarrier_Store(&constructor_called_, 0);
219 base::subtle::NoBarrier_Store(&complete_construction_, 0);
222 // Returns true if BlockingConstructor() was entered.
223 static bool WasConstructorCalled() {
224 return base::subtle::NoBarrier_Load(&constructor_called_);
227 // Instructs BlockingConstructor() that it may now unblock its construction.
228 static void CompleteConstructionNow() {
229 base::subtle::NoBarrier_Store(&complete_construction_, 1);
232 bool done_construction() { return done_construction_; }
235 // Use Atomic32 instead of AtomicFlag for them to be trivially initialized.
236 static base::subtle::Atomic32 constructor_called_;
237 static base::subtle::Atomic32 complete_construction_;
239 bool done_construction_ = false;
241 DISALLOW_COPY_AND_ASSIGN(BlockingConstructor);
244 // A SimpleThread running at |thread_priority| which invokes |before_get|
245 // (optional) and then invokes Get() on the LazyInstance it's assigned.
246 class BlockingConstructorThread : public base::SimpleThread {
248 BlockingConstructorThread(
249 base::ThreadPriority thread_priority,
250 base::LazyInstance<BlockingConstructor>::DestructorAtExit* lazy,
251 base::OnceClosure before_get)
252 : SimpleThread("BlockingConstructorThread", Options(thread_priority)),
254 before_get_(std::move(before_get)) {}
256 void Run() override {
258 std::move(before_get_).Run();
259 EXPECT_TRUE(lazy_->Get().done_construction());
263 base::LazyInstance<BlockingConstructor>::DestructorAtExit* lazy_;
264 base::OnceClosure before_get_;
266 DISALLOW_COPY_AND_ASSIGN(BlockingConstructorThread);
270 base::subtle::Atomic32 BlockingConstructor::constructor_called_ = 0;
272 base::subtle::Atomic32 BlockingConstructor::complete_construction_ = 0;
274 base::LazyInstance<BlockingConstructor>::DestructorAtExit lazy_blocking =
275 LAZY_INSTANCE_INITIALIZER;
279 // Tests that if the thread assigned to construct the LazyInstance runs at
280 // background priority : the foreground threads will yield to it enough for it
281 // to eventually complete construction.
282 // This is a regression test for https://crbug.com/797129.
283 TEST(LazyInstanceTest, PriorityInversionAtInitializationResolves) {
284 base::TimeTicks test_begin = base::TimeTicks::Now();
286 // Construct BlockingConstructor from a background thread.
287 BlockingConstructorThread background_getter(
288 base::ThreadPriority::BACKGROUND, &lazy_blocking, base::OnceClosure());
289 background_getter.Start();
291 while (!BlockingConstructor::WasConstructorCalled())
292 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
294 // Spin 4 foreground thread per core contending to get the already under
295 // construction LazyInstance. When they are all running and poking at it :
296 // allow the background thread to complete its work.
297 const int kNumForegroundThreads = 4 * base::SysInfo::NumberOfProcessors();
298 std::vector<std::unique_ptr<base::SimpleThread>> foreground_threads;
299 base::RepeatingClosure foreground_thread_ready_callback =
300 base::BarrierClosure(
301 kNumForegroundThreads,
302 base::BindOnce(&BlockingConstructor::CompleteConstructionNow));
303 for (int i = 0; i < kNumForegroundThreads; ++i) {
304 foreground_threads.push_back(std::make_unique<BlockingConstructorThread>(
305 base::ThreadPriority::NORMAL, &lazy_blocking,
306 foreground_thread_ready_callback));
307 foreground_threads.back()->Start();
310 // This test will hang if the foreground threads become stuck in
311 // LazyInstance::Get() per the background thread never being scheduled to
312 // complete construction.
313 for (auto& foreground_thread : foreground_threads)
314 foreground_thread->Join();
315 background_getter.Join();
317 // Fail if this test takes more than 5 seconds (it takes 5-10 seconds on a
318 // Z840 without r527445 but is expected to be fast (~30ms) with the fix).
319 EXPECT_LT(base::TimeTicks::Now() - test_begin,
320 base::TimeDelta::FromSeconds(5));