blob: f20c426beec7080b35bf5ea7ae8f7a458a21d4e9 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2012 The Chromium Authors
[email protected]30039e62008-09-08 14:11:132// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Benoît Lizéaac37182024-12-09 12:42:245#include "base/lazy_instance.h"
6
avi9b6f42932015-12-26 22:15:147#include <stddef.h>
8
Benoît Lizéaac37182024-12-09 12:42:249#include <atomic>
Gabriel Charette70b373022018-01-17 21:00:1810#include <memory>
Lei Zhang25c9ff62020-06-19 02:30:4311#include <utility>
Gabriel Charette70b373022018-01-17 21:00:1812#include <vector>
13
[email protected]30039e62008-09-08 14:11:1314#include "base/at_exit.h"
Joe Downing0d4683d2018-01-24 01:32:3815#include "base/atomic_sequence_num.h"
Gabriel Charette70b373022018-01-17 21:00:1816#include "base/barrier_closure.h"
Avi Drissman63e1f992023-01-13 18:54:4317#include "base/functional/bind.h"
18#include "base/functional/callback.h"
Lei Zhang25c9ff62020-06-19 02:30:4319#include "base/memory/aligned_memory.h"
Keishi Hattori0e45c022021-11-27 09:25:5220#include "base/memory/raw_ptr.h"
Sebastien Marchand75a7cdf2018-11-13 23:47:0321#include "base/system/sys_info.h"
Gabriel Charette70b373022018-01-17 21:00:1822#include "base/threading/platform_thread.h"
[email protected]ac9ba8fe2010-12-30 18:08:3623#include "base/threading/simple_thread.h"
Gabriel Charette70b373022018-01-17 21:00:1824#include "base/time/time.h"
brettw16289b3e2017-06-13 21:58:4025#include "build/build_config.h"
[email protected]30039e62008-09-08 14:11:1326#include "testing/gtest/include/gtest/gtest.h"
27
Daniel Cheng1b97e932018-01-23 23:51:3128namespace {
[email protected]30039e62008-09-08 14:11:1329
Joe Downing0d4683d2018-01-24 01:32:3830base::AtomicSequenceNumber constructed_seq_;
31base::AtomicSequenceNumber destructed_seq_;
32
[email protected]30039e62008-09-08 14:11:1333class ConstructAndDestructLogger {
34 public:
Peter Kasting134ef9af2024-12-28 02:30:0935 ConstructAndDestructLogger() { constructed_seq_.GetNext(); }
David Bienvenub4b441e2020-09-23 05:49:5736 ConstructAndDestructLogger(const ConstructAndDestructLogger&) = delete;
37 ConstructAndDestructLogger& operator=(const ConstructAndDestructLogger&) =
38 delete;
Peter Kasting134ef9af2024-12-28 02:30:0939 ~ConstructAndDestructLogger() { destructed_seq_.GetNext(); }
[email protected]30039e62008-09-08 14:11:1340};
41
42class SlowConstructor {
43 public:
Peter Kasting811504a72025-01-09 03:18:5044 SlowConstructor() {
[email protected]ce072a72010-12-31 20:02:1645 // Sleep for 1 second to try to cause a race.
Peter Kastinge5a38ed2021-10-02 03:06:3546 base::PlatformThread::Sleep(base::Seconds(1));
Joe Downing0d4683d2018-01-24 01:32:3847 ++constructed;
[email protected]30039e62008-09-08 14:11:1348 some_int_ = 12;
49 }
David Bienvenub4b441e2020-09-23 05:49:5750 SlowConstructor(const SlowConstructor&) = delete;
51 SlowConstructor& operator=(const SlowConstructor&) = delete;
[email protected]30039e62008-09-08 14:11:1352 int some_int() const { return some_int_; }
53
Joe Downing0d4683d2018-01-24 01:32:3854 static int constructed;
Peter Kasting134ef9af2024-12-28 02:30:0955
[email protected]30039e62008-09-08 14:11:1356 private:
Peter Kasting811504a72025-01-09 03:18:5057 int some_int_ = 0;
[email protected]30039e62008-09-08 14:11:1358};
59
Gabriel Charette70b373022018-01-17 21:00:1860// static
Joe Downing0d4683d2018-01-24 01:32:3861int SlowConstructor::constructed = 0;
[email protected]30039e62008-09-08 14:11:1362
Joe Downing0d4683d2018-01-24 01:32:3863class SlowDelegate : public base::DelegateSimpleThread::Delegate {
[email protected]30039e62008-09-08 14:11:1364 public:
Joe Downing0d4683d2018-01-24 01:32:3865 explicit SlowDelegate(
66 base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy)
[email protected]2fdc86a2010-01-26 23:08:0267 : lazy_(lazy) {}
David Bienvenub4b441e2020-09-23 05:49:5768 SlowDelegate(const SlowDelegate&) = delete;
69 SlowDelegate& operator=(const SlowDelegate&) = delete;
[email protected]2fdc86a2010-01-26 23:08:0270
dcheng56488182014-10-21 10:54:5171 void Run() override {
[email protected]30039e62008-09-08 14:11:1372 EXPECT_EQ(12, lazy_->Get().some_int());
73 EXPECT_EQ(12, lazy_->Pointer()->some_int());
74 }
75
76 private:
Keishi Hattori0e45c022021-11-27 09:25:5277 raw_ptr<base::LazyInstance<SlowConstructor>::DestructorAtExit> lazy_;
[email protected]30039e62008-09-08 14:11:1378};
79
80} // namespace
81
Joe Downing0d4683d2018-01-24 01:32:3882base::LazyInstance<ConstructAndDestructLogger>::DestructorAtExit lazy_logger =
83 LAZY_INSTANCE_INITIALIZER;
84
85TEST(LazyInstanceTest, Basic) {
86 {
87 base::ShadowingAtExitManager shadow;
88
89 EXPECT_FALSE(lazy_logger.IsCreated());
90 EXPECT_EQ(0, constructed_seq_.GetNext());
91 EXPECT_EQ(0, destructed_seq_.GetNext());
92
93 lazy_logger.Get();
94 EXPECT_TRUE(lazy_logger.IsCreated());
95 EXPECT_EQ(2, constructed_seq_.GetNext());
96 EXPECT_EQ(1, destructed_seq_.GetNext());
97
98 lazy_logger.Pointer();
99 EXPECT_TRUE(lazy_logger.IsCreated());
100 EXPECT_EQ(3, constructed_seq_.GetNext());
101 EXPECT_EQ(2, destructed_seq_.GetNext());
102 }
103 EXPECT_FALSE(lazy_logger.IsCreated());
104 EXPECT_EQ(4, constructed_seq_.GetNext());
105 EXPECT_EQ(4, destructed_seq_.GetNext());
106}
107
108base::LazyInstance<SlowConstructor>::DestructorAtExit lazy_slow =
109 LAZY_INSTANCE_INITIALIZER;
110
[email protected]30039e62008-09-08 14:11:13111TEST(LazyInstanceTest, ConstructorThreadSafety) {
Joe Downing0d4683d2018-01-24 01:32:38112 {
113 base::ShadowingAtExitManager shadow;
[email protected]30039e62008-09-08 14:11:13114
Joe Downing0d4683d2018-01-24 01:32:38115 SlowDelegate delegate(&lazy_slow);
116 EXPECT_EQ(0, SlowConstructor::constructed);
[email protected]30039e62008-09-08 14:11:13117
Joe Downing0d4683d2018-01-24 01:32:38118 base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
119 pool.AddWork(&delegate, 20);
120 EXPECT_EQ(0, SlowConstructor::constructed);
[email protected]30039e62008-09-08 14:11:13121
Joe Downing0d4683d2018-01-24 01:32:38122 pool.Start();
123 pool.JoinAll();
124 EXPECT_EQ(1, SlowConstructor::constructed);
125 }
[email protected]30039e62008-09-08 14:11:13126}
[email protected]dcc69332010-10-21 20:41:47127
128namespace {
129
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.
132class DeleteLogger {
133 public:
Ivan Kotenkova16212a52017-11-08 12:37:33134 DeleteLogger() : deleted_(nullptr) {}
[email protected]dcc69332010-10-21 20:41:47135 ~DeleteLogger() { *deleted_ = true; }
136
Peter Kasting134ef9af2024-12-28 02:30:09137 void SetDeletedPtr(bool* deleted) { deleted_ = deleted; }
[email protected]dcc69332010-10-21 20:41:47138
139 private:
Keishi Hattori0e45c022021-11-27 09:25:52140 raw_ptr<bool> deleted_;
[email protected]dcc69332010-10-21 20:41:47141};
142
143} // anonymous namespace
144
145TEST(LazyInstanceTest, LeakyLazyInstance) {
Joe Downing0d4683d2018-01-24 01:32:38146 // Check that using a plain LazyInstance causes the dtor to run
147 // when the AtExitManager finishes.
[email protected]dcc69332010-10-21 20:41:47148 bool deleted1 = false;
149 {
Joe Downing0d4683d2018-01-24 01:32:38150 base::ShadowingAtExitManager shadow;
151 static base::LazyInstance<DeleteLogger>::DestructorAtExit test =
scottmg5e65e3a2017-03-08 08:48:46152 LAZY_INSTANCE_INITIALIZER;
[email protected]dcc69332010-10-21 20:41:47153 test.Get().SetDeletedPtr(&deleted1);
154 }
Joe Downing0d4683d2018-01-24 01:32:38155 EXPECT_TRUE(deleted1);
[email protected]dcc69332010-10-21 20:41:47156
157 // Check that using a *leaky* LazyInstance makes the dtor not run
158 // when the AtExitManager finishes.
159 bool deleted2 = false;
160 {
Joe Downing0d4683d2018-01-24 01:32:38161 base::ShadowingAtExitManager shadow;
Peter Kasting134ef9af2024-12-28 02:30:09162 static base::LazyInstance<DeleteLogger>::Leaky test =
163 LAZY_INSTANCE_INITIALIZER;
[email protected]dcc69332010-10-21 20:41:47164 test.Get().SetDeletedPtr(&deleted2);
165 }
166 EXPECT_FALSE(deleted2);
167}
[email protected]cd924d62012-02-23 17:52:20168
169namespace {
170
171template <size_t alignment>
172class AlignedData {
173 public:
Chris Watkinsbb7211c2017-11-29 07:16:38174 AlignedData() = default;
175 ~AlignedData() = default;
brettw16289b3e2017-06-13 21:58:40176 alignas(alignment) char data_[alignment];
[email protected]cd924d62012-02-23 17:52:20177};
178
brettw16289b3e2017-06-13 21:58:40179} // namespace
[email protected]cd924d62012-02-23 17:52:20180
[email protected]cd924d62012-02-23 17:52:20181TEST(LazyInstanceTest, Alignment) {
Joe Downing0d4683d2018-01-24 01:32:38182 using base::LazyInstance;
183
[email protected]cd924d62012-02-23 17:52:20184 // Create some static instances with increasing sizes and alignment
185 // requirements. By ordering this way, the linker will need to do some work to
186 // ensure proper alignment of the static data.
scottmg5e65e3a2017-03-08 08:48:46187 static LazyInstance<AlignedData<4>>::DestructorAtExit align4 =
188 LAZY_INSTANCE_INITIALIZER;
189 static LazyInstance<AlignedData<32>>::DestructorAtExit align32 =
190 LAZY_INSTANCE_INITIALIZER;
191 static LazyInstance<AlignedData<4096>>::DestructorAtExit align4096 =
192 LAZY_INSTANCE_INITIALIZER;
[email protected]cd924d62012-02-23 17:52:20193
Lei Zhang25c9ff62020-06-19 02:30:43194 EXPECT_TRUE(base::IsAligned(align4.Pointer(), 4));
195 EXPECT_TRUE(base::IsAligned(align32.Pointer(), 32));
196 EXPECT_TRUE(base::IsAligned(align4096.Pointer(), 4096));
[email protected]cd924d62012-02-23 17:52:20197}
Gabriel Charette70b373022018-01-17 21:00:18198
199namespace {
200
201// A class whose constructor busy-loops until it is told to complete
202// construction.
203class BlockingConstructor {
204 public:
205 BlockingConstructor() {
206 EXPECT_FALSE(WasConstructorCalled());
Benoît Lizéaac37182024-12-09 12:42:24207 constructor_called_.store(true, std::memory_order_relaxed);
Gabriel Charette70b373022018-01-17 21:00:18208 EXPECT_TRUE(WasConstructorCalled());
Benoît Lizéaac37182024-12-09 12:42:24209 while (!complete_construction_.load(std::memory_order_relaxed)) {
Joe Downing0d4683d2018-01-24 01:32:38210 base::PlatformThread::YieldCurrentThread();
Benoît Lizéaac37182024-12-09 12:42:24211 }
Gabriel Charette70b373022018-01-17 21:00:18212 done_construction_ = true;
213 }
David Bienvenub4b441e2020-09-23 05:49:57214 BlockingConstructor(const BlockingConstructor&) = delete;
215 BlockingConstructor& operator=(const BlockingConstructor&) = delete;
Joe Downing0d4683d2018-01-24 01:32:38216 ~BlockingConstructor() {
217 // Restore static state for the next test.
Benoît Lizéaac37182024-12-09 12:42:24218 constructor_called_.store(false, std::memory_order_relaxed);
219 complete_construction_.store(false, std::memory_order_relaxed);
Joe Downing0d4683d2018-01-24 01:32:38220 }
221
Gabriel Charette70b373022018-01-17 21:00:18222 // Returns true if BlockingConstructor() was entered.
Joe Downing0d4683d2018-01-24 01:32:38223 static bool WasConstructorCalled() {
Benoît Lizéaac37182024-12-09 12:42:24224 return constructor_called_.load(std::memory_order_relaxed);
Joe Downing0d4683d2018-01-24 01:32:38225 }
Gabriel Charette70b373022018-01-17 21:00:18226
227 // Instructs BlockingConstructor() that it may now unblock its construction.
Joe Downing0d4683d2018-01-24 01:32:38228 static void CompleteConstructionNow() {
Benoît Lizéaac37182024-12-09 12:42:24229 complete_construction_.store(true, std::memory_order_relaxed);
Joe Downing0d4683d2018-01-24 01:32:38230 }
Gabriel Charette70b373022018-01-17 21:00:18231
David Bienvenub4b441e2020-09-23 05:49:57232 bool done_construction() const { return done_construction_; }
Gabriel Charette70b373022018-01-17 21:00:18233
234 private:
Joe Downing0d4683d2018-01-24 01:32:38235 // Use Atomic32 instead of AtomicFlag for them to be trivially initialized.
Benoît Lizéaac37182024-12-09 12:42:24236 static std::atomic<bool> constructor_called_;
237 static std::atomic<bool> complete_construction_;
Gabriel Charette70b373022018-01-17 21:00:18238
239 bool done_construction_ = false;
Gabriel Charette70b373022018-01-17 21:00:18240};
241
Zhibo Wangd9e4a002022-07-07 04:34:59242// A SimpleThread running at |thread_type| which invokes |before_get| (optional)
243// and then invokes Get() on the LazyInstance it's assigned.
Joe Downing0d4683d2018-01-24 01:32:38244class BlockingConstructorThread : public base::SimpleThread {
Gabriel Charette70b373022018-01-17 21:00:18245 public:
246 BlockingConstructorThread(
Zhibo Wangd9e4a002022-07-07 04:34:59247 base::ThreadType thread_type,
Joe Downing0d4683d2018-01-24 01:32:38248 base::LazyInstance<BlockingConstructor>::DestructorAtExit* lazy,
249 base::OnceClosure before_get)
Zhibo Wangd9e4a002022-07-07 04:34:59250 : SimpleThread("BlockingConstructorThread", Options(thread_type)),
Gabriel Charette70b373022018-01-17 21:00:18251 lazy_(lazy),
252 before_get_(std::move(before_get)) {}
David Bienvenub4b441e2020-09-23 05:49:57253 BlockingConstructorThread(const BlockingConstructorThread&) = delete;
254 BlockingConstructorThread& operator=(const BlockingConstructorThread&) =
255 delete;
Gabriel Charette70b373022018-01-17 21:00:18256
257 void Run() override {
Peter Kasting134ef9af2024-12-28 02:30:09258 if (before_get_) {
Gabriel Charette70b373022018-01-17 21:00:18259 std::move(before_get_).Run();
Peter Kasting134ef9af2024-12-28 02:30:09260 }
Gabriel Charette70b373022018-01-17 21:00:18261 EXPECT_TRUE(lazy_->Get().done_construction());
262 }
263
264 private:
Keishi Hattori0e45c022021-11-27 09:25:52265 raw_ptr<base::LazyInstance<BlockingConstructor>::DestructorAtExit> lazy_;
Joe Downing0d4683d2018-01-24 01:32:38266 base::OnceClosure before_get_;
Gabriel Charette70b373022018-01-17 21:00:18267};
268
269// static
Benoît Lizéaac37182024-12-09 12:42:24270std::atomic<bool> BlockingConstructor::constructor_called_ = false;
Gabriel Charette70b373022018-01-17 21:00:18271// static
Benoît Lizéaac37182024-12-09 12:42:24272std::atomic<bool> BlockingConstructor::complete_construction_ = false;
Gabriel Charette70b373022018-01-17 21:00:18273
Joe Downing0d4683d2018-01-24 01:32:38274base::LazyInstance<BlockingConstructor>::DestructorAtExit lazy_blocking =
Gabriel Charette70b373022018-01-17 21:00:18275 LAZY_INSTANCE_INITIALIZER;
276
277} // namespace
278
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.
283TEST(LazyInstanceTest, PriorityInversionAtInitializationResolves) {
Joe Downing0d4683d2018-01-24 01:32:38284 base::TimeTicks test_begin = base::TimeTicks::Now();
Gabriel Charette70b373022018-01-17 21:00:18285
286 // Construct BlockingConstructor from a background thread.
Joe Downing0d4683d2018-01-24 01:32:38287 BlockingConstructorThread background_getter(
Zhibo Wangd9e4a002022-07-07 04:34:59288 base::ThreadType::kBackground, &lazy_blocking, base::OnceClosure());
Gabriel Charette70b373022018-01-17 21:00:18289 background_getter.Start();
290
Peter Kasting134ef9af2024-12-28 02:30:09291 while (!BlockingConstructor::WasConstructorCalled()) {
Peter Kastinge5a38ed2021-10-02 03:06:35292 base::PlatformThread::Sleep(base::Milliseconds(1));
Peter Kasting134ef9af2024-12-28 02:30:09293 }
Gabriel Charette70b373022018-01-17 21:00:18294
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.
Joe Downing0d4683d2018-01-24 01:32:38298 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));
Gabriel Charette70b373022018-01-17 21:00:18304 for (int i = 0; i < kNumForegroundThreads; ++i) {
305 foreground_threads.push_back(std::make_unique<BlockingConstructorThread>(
Zhibo Wangd9e4a002022-07-07 04:34:59306 base::ThreadType::kDefault, &lazy_blocking,
Gabriel Charette70b373022018-01-17 21:00:18307 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.
Peter Kasting134ef9af2024-12-28 02:30:09314 for (auto& foreground_thread : foreground_threads) {
Gabriel Charette70b373022018-01-17 21:00:18315 foreground_thread->Join();
Peter Kasting134ef9af2024-12-28 02:30:09316 }
Gabriel Charette70b373022018-01-17 21:00:18317 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).
Peter Kastinge5a38ed2021-10-02 03:06:35321 EXPECT_LT(base::TimeTicks::Now() - test_begin, base::Seconds(5));
Gabriel Charette70b373022018-01-17 21:00:18322}