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.
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/system/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"
25 base::AtomicSequenceNumber constructed_seq_;
26 base::AtomicSequenceNumber destructed_seq_;
28 class ConstructAndDestructLogger {
30 ConstructAndDestructLogger() {
31 constructed_seq_.GetNext();
33 ~ConstructAndDestructLogger() {
34 destructed_seq_.GetNext();
38 DISALLOW_COPY_AND_ASSIGN(ConstructAndDestructLogger);
41 class 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));
49 int some_int() const { return some_int_; }
51 static int constructed;
55 DISALLOW_COPY_AND_ASSIGN(SlowConstructor);
59 int SlowConstructor::constructed = 0;
61 class SlowDelegate : public base::DelegateSimpleThread::Delegate {
63 explicit SlowDelegate(
64 base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy)
68 EXPECT_EQ(12, lazy_->Get().some_int());
69 EXPECT_EQ(12, lazy_->Pointer()->some_int());
73 base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy_;
75 DISALLOW_COPY_AND_ASSIGN(SlowDelegate);
80 base::LazyInstance<ConstructAndDestructLogger>::DestructorAtExit lazy_logger =
81 LAZY_INSTANCE_INITIALIZER;
83 TEST(LazyInstanceTest, Basic) {
85 base::ShadowingAtExitManager shadow;
87 EXPECT_FALSE(lazy_logger.IsCreated());
88 EXPECT_EQ(0, constructed_seq_.GetNext());
89 EXPECT_EQ(0, destructed_seq_.GetNext());
92 EXPECT_TRUE(lazy_logger.IsCreated());
93 EXPECT_EQ(2, constructed_seq_.GetNext());
94 EXPECT_EQ(1, destructed_seq_.GetNext());
96 lazy_logger.Pointer();
97 EXPECT_TRUE(lazy_logger.IsCreated());
98 EXPECT_EQ(3, constructed_seq_.GetNext());
99 EXPECT_EQ(2, destructed_seq_.GetNext());
101 EXPECT_FALSE(lazy_logger.IsCreated());
102 EXPECT_EQ(4, constructed_seq_.GetNext());
103 EXPECT_EQ(4, destructed_seq_.GetNext());
106 base::LazyInstance<SlowConstructor>::DestructorAtExit lazy_slow =
107 LAZY_INSTANCE_INITIALIZER;
109 TEST(LazyInstanceTest, ConstructorThreadSafety) {
111 base::ShadowingAtExitManager shadow;
113 SlowDelegate delegate(&lazy_slow);
114 EXPECT_EQ(0, SlowConstructor::constructed);
116 base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
117 pool.AddWork(&delegate, 20);
118 EXPECT_EQ(0, SlowConstructor::constructed);
122 EXPECT_EQ(1, SlowConstructor::constructed);
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.
132 DeleteLogger() : deleted_(nullptr) {}
133 ~DeleteLogger() { *deleted_ = true; }
135 void SetDeletedPtr(bool* deleted) {
143 } // anonymous namespace
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;
150 base::ShadowingAtExitManager shadow;
151 static base::LazyInstance<DeleteLogger>::DestructorAtExit test =
152 LAZY_INSTANCE_INITIALIZER;
153 test.Get().SetDeletedPtr(&deleted1);
155 EXPECT_TRUE(deleted1);
157 // Check that using a *leaky* LazyInstance makes the dtor not run
158 // when the AtExitManager finishes.
159 bool deleted2 = false;
161 base::ShadowingAtExitManager shadow;
162 static base::LazyInstance<DeleteLogger>::Leaky
163 test = LAZY_INSTANCE_INITIALIZER;
164 test.Get().SetDeletedPtr(&deleted2);
166 EXPECT_FALSE(deleted2);
171 template <size_t alignment>
174 AlignedData() = default;
175 ~AlignedData() = default;
176 alignas(alignment) char data_[alignment];
181 #define EXPECT_ALIGNED(ptr, align) \
182 EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
184 TEST(LazyInstanceTest, Alignment) {
185 using base::LazyInstance;
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;
197 EXPECT_ALIGNED(align4.Pointer(), 4);
198 EXPECT_ALIGNED(align32.Pointer(), 32);
199 EXPECT_ALIGNED(align4096.Pointer(), 4096);
204 // A class whose constructor busy-loops until it is told to complete
206 class 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;
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);
223 // Returns true if BlockingConstructor() was entered.
224 static bool WasConstructorCalled() {
225 return base::subtle::NoBarrier_Load(&constructor_called_);
228 // Instructs BlockingConstructor() that it may now unblock its construction.
229 static void CompleteConstructionNow() {
230 base::subtle::NoBarrier_Store(&complete_construction_, 1);
233 bool done_construction() { return done_construction_; }
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_;
240 bool done_construction_ = false;
242 DISALLOW_COPY_AND_ASSIGN(BlockingConstructor);
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 {
249 BlockingConstructorThread(
250 base::ThreadPriority thread_priority,
251 base::LazyInstance<BlockingConstructor>::DestructorAtExit* lazy,
252 base::OnceClosure before_get)
253 : SimpleThread("BlockingConstructorThread", Options(thread_priority)),
255 before_get_(std::move(before_get)) {}
257 void Run() override {
259 std::move(before_get_).Run();
260 EXPECT_TRUE(lazy_->Get().done_construction());
264 base::LazyInstance<BlockingConstructor>::DestructorAtExit* lazy_;
265 base::OnceClosure before_get_;
267 DISALLOW_COPY_AND_ASSIGN(BlockingConstructorThread);
271 base::subtle::Atomic32 BlockingConstructor::constructor_called_ = 0;
273 base::subtle::Atomic32 BlockingConstructor::complete_construction_ = 0;
275 base::LazyInstance<BlockingConstructor>::DestructorAtExit lazy_blocking =
276 LAZY_INSTANCE_INITIALIZER;
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.
284 TEST(LazyInstanceTest, PriorityInversionAtInitializationResolves) {
285 base::TimeTicks test_begin = base::TimeTicks::Now();
287 // Construct BlockingConstructor from a background thread.
288 BlockingConstructorThread background_getter(
289 base::ThreadPriority::BACKGROUND, &lazy_blocking, base::OnceClosure());
290 background_getter.Start();
292 while (!BlockingConstructor::WasConstructorCalled())
293 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
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();
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();
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));