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