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.
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/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"
29 base::AtomicSequenceNumber constructed_seq_;
30 base::AtomicSequenceNumber destructed_seq_;
32 class ConstructAndDestructLogger {
34 ConstructAndDestructLogger() {
35 constructed_seq_.GetNext();
37 ConstructAndDestructLogger(const ConstructAndDestructLogger&) = delete;
38 ConstructAndDestructLogger& operator=(const ConstructAndDestructLogger&) =
40 ~ConstructAndDestructLogger() {
41 destructed_seq_.GetNext();
45 class SlowConstructor {
47 SlowConstructor() : some_int_(0) {
48 // Sleep for 1 second to try to cause a race.
49 base::PlatformThread::Sleep(base::Seconds(1));
53 SlowConstructor(const SlowConstructor&) = delete;
54 SlowConstructor& operator=(const SlowConstructor&) = delete;
55 int some_int() const { return some_int_; }
57 static int constructed;
63 int SlowConstructor::constructed = 0;
65 class SlowDelegate : public base::DelegateSimpleThread::Delegate {
67 explicit SlowDelegate(
68 base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy)
70 SlowDelegate(const SlowDelegate&) = delete;
71 SlowDelegate& operator=(const SlowDelegate&) = delete;
74 EXPECT_EQ(12, lazy_->Get().some_int());
75 EXPECT_EQ(12, lazy_->Pointer()->some_int());
79 raw_ptr<base::LazyInstance<SlowConstructor>::DestructorAtExit> lazy_;
84 base::LazyInstance<ConstructAndDestructLogger>::DestructorAtExit lazy_logger =
85 LAZY_INSTANCE_INITIALIZER;
87 TEST(LazyInstanceTest, Basic) {
89 base::ShadowingAtExitManager shadow;
91 EXPECT_FALSE(lazy_logger.IsCreated());
92 EXPECT_EQ(0, constructed_seq_.GetNext());
93 EXPECT_EQ(0, destructed_seq_.GetNext());
96 EXPECT_TRUE(lazy_logger.IsCreated());
97 EXPECT_EQ(2, constructed_seq_.GetNext());
98 EXPECT_EQ(1, destructed_seq_.GetNext());
100 lazy_logger.Pointer();
101 EXPECT_TRUE(lazy_logger.IsCreated());
102 EXPECT_EQ(3, constructed_seq_.GetNext());
103 EXPECT_EQ(2, destructed_seq_.GetNext());
105 EXPECT_FALSE(lazy_logger.IsCreated());
106 EXPECT_EQ(4, constructed_seq_.GetNext());
107 EXPECT_EQ(4, destructed_seq_.GetNext());
110 base::LazyInstance<SlowConstructor>::DestructorAtExit lazy_slow =
111 LAZY_INSTANCE_INITIALIZER;
113 TEST(LazyInstanceTest, ConstructorThreadSafety) {
115 base::ShadowingAtExitManager shadow;
117 SlowDelegate delegate(&lazy_slow);
118 EXPECT_EQ(0, SlowConstructor::constructed);
120 base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
121 pool.AddWork(&delegate, 20);
122 EXPECT_EQ(0, SlowConstructor::constructed);
126 EXPECT_EQ(1, SlowConstructor::constructed);
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.
136 DeleteLogger() : deleted_(nullptr) {}
137 ~DeleteLogger() { *deleted_ = true; }
139 void SetDeletedPtr(bool* deleted) {
144 raw_ptr<bool> deleted_;
147 } // anonymous namespace
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;
154 base::ShadowingAtExitManager shadow;
155 static base::LazyInstance<DeleteLogger>::DestructorAtExit test =
156 LAZY_INSTANCE_INITIALIZER;
157 test.Get().SetDeletedPtr(&deleted1);
159 EXPECT_TRUE(deleted1);
161 // Check that using a *leaky* LazyInstance makes the dtor not run
162 // when the AtExitManager finishes.
163 bool deleted2 = false;
165 base::ShadowingAtExitManager shadow;
166 static base::LazyInstance<DeleteLogger>::Leaky
167 test = LAZY_INSTANCE_INITIALIZER;
168 test.Get().SetDeletedPtr(&deleted2);
170 EXPECT_FALSE(deleted2);
175 template <size_t alignment>
178 AlignedData() = default;
179 ~AlignedData() = default;
180 alignas(alignment) char data_[alignment];
185 TEST(LazyInstanceTest, Alignment) {
186 using base::LazyInstance;
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;
198 EXPECT_TRUE(base::IsAligned(align4.Pointer(), 4));
199 EXPECT_TRUE(base::IsAligned(align32.Pointer(), 32));
200 EXPECT_TRUE(base::IsAligned(align4096.Pointer(), 4096));
205 // A class whose constructor busy-loops until it is told to complete
207 class 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;
217 BlockingConstructor(const BlockingConstructor&) = delete;
218 BlockingConstructor& operator=(const BlockingConstructor&) = delete;
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);
225 // Returns true if BlockingConstructor() was entered.
226 static bool WasConstructorCalled() {
227 return base::subtle::NoBarrier_Load(&constructor_called_);
230 // Instructs BlockingConstructor() that it may now unblock its construction.
231 static void CompleteConstructionNow() {
232 base::subtle::NoBarrier_Store(&complete_construction_, 1);
235 bool done_construction() const { return done_construction_; }
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_;
242 bool done_construction_ = false;
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 {
249 BlockingConstructorThread(
250 base::ThreadType thread_type,
251 base::LazyInstance<BlockingConstructor>::DestructorAtExit* lazy,
252 base::OnceClosure before_get)
253 : SimpleThread("BlockingConstructorThread", Options(thread_type)),
255 before_get_(std::move(before_get)) {}
256 BlockingConstructorThread(const BlockingConstructorThread&) = delete;
257 BlockingConstructorThread& operator=(const BlockingConstructorThread&) =
260 void Run() override {
262 std::move(before_get_).Run();
263 EXPECT_TRUE(lazy_->Get().done_construction());
267 raw_ptr<base::LazyInstance<BlockingConstructor>::DestructorAtExit> lazy_;
268 base::OnceClosure before_get_;
272 base::subtle::Atomic32 BlockingConstructor::constructor_called_ = 0;
274 base::subtle::Atomic32 BlockingConstructor::complete_construction_ = 0;
276 base::LazyInstance<BlockingConstructor>::DestructorAtExit lazy_blocking =
277 LAZY_INSTANCE_INITIALIZER;
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.
285 TEST(LazyInstanceTest, PriorityInversionAtInitializationResolves) {
286 base::TimeTicks test_begin = base::TimeTicks::Now();
288 // Construct BlockingConstructor from a background thread.
289 BlockingConstructorThread background_getter(
290 base::ThreadType::kBackground, &lazy_blocking, base::OnceClosure());
291 background_getter.Start();
293 while (!BlockingConstructor::WasConstructorCalled())
294 base::PlatformThread::Sleep(base::Milliseconds(1));
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();
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();
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));