Fix emulator build error
[platform/framework/web/chromium-efl.git] / base / lazy_instance_unittest.cc
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.
4
5 #include <stddef.h>
6
7 #include <memory>
8 #include <utility>
9 #include <vector>
10
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/functional/bind.h"
16 #include "base/functional/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"
26
27 namespace {
28
29 base::AtomicSequenceNumber constructed_seq_;
30 base::AtomicSequenceNumber destructed_seq_;
31
32 class ConstructAndDestructLogger {
33  public:
34   ConstructAndDestructLogger() {
35     constructed_seq_.GetNext();
36   }
37   ConstructAndDestructLogger(const ConstructAndDestructLogger&) = delete;
38   ConstructAndDestructLogger& operator=(const ConstructAndDestructLogger&) =
39       delete;
40   ~ConstructAndDestructLogger() {
41     destructed_seq_.GetNext();
42   }
43 };
44
45 class SlowConstructor {
46  public:
47   SlowConstructor() : some_int_(0) {
48     // Sleep for 1 second to try to cause a race.
49     base::PlatformThread::Sleep(base::Seconds(1));
50     ++constructed;
51     some_int_ = 12;
52   }
53   SlowConstructor(const SlowConstructor&) = delete;
54   SlowConstructor& operator=(const SlowConstructor&) = delete;
55   int some_int() const { return some_int_; }
56
57   static int constructed;
58  private:
59   int some_int_;
60 };
61
62 // static
63 int SlowConstructor::constructed = 0;
64
65 class SlowDelegate : public base::DelegateSimpleThread::Delegate {
66  public:
67   explicit SlowDelegate(
68       base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy)
69       : lazy_(lazy) {}
70   SlowDelegate(const SlowDelegate&) = delete;
71   SlowDelegate& operator=(const SlowDelegate&) = delete;
72
73   void Run() override {
74     EXPECT_EQ(12, lazy_->Get().some_int());
75     EXPECT_EQ(12, lazy_->Pointer()->some_int());
76   }
77
78  private:
79   raw_ptr<base::LazyInstance<SlowConstructor>::DestructorAtExit> lazy_;
80 };
81
82 }  // namespace
83
84 base::LazyInstance<ConstructAndDestructLogger>::DestructorAtExit lazy_logger =
85     LAZY_INSTANCE_INITIALIZER;
86
87 TEST(LazyInstanceTest, Basic) {
88   {
89     base::ShadowingAtExitManager shadow;
90
91     EXPECT_FALSE(lazy_logger.IsCreated());
92     EXPECT_EQ(0, constructed_seq_.GetNext());
93     EXPECT_EQ(0, destructed_seq_.GetNext());
94
95     lazy_logger.Get();
96     EXPECT_TRUE(lazy_logger.IsCreated());
97     EXPECT_EQ(2, constructed_seq_.GetNext());
98     EXPECT_EQ(1, destructed_seq_.GetNext());
99
100     lazy_logger.Pointer();
101     EXPECT_TRUE(lazy_logger.IsCreated());
102     EXPECT_EQ(3, constructed_seq_.GetNext());
103     EXPECT_EQ(2, destructed_seq_.GetNext());
104   }
105   EXPECT_FALSE(lazy_logger.IsCreated());
106   EXPECT_EQ(4, constructed_seq_.GetNext());
107   EXPECT_EQ(4, destructed_seq_.GetNext());
108 }
109
110 base::LazyInstance<SlowConstructor>::DestructorAtExit lazy_slow =
111     LAZY_INSTANCE_INITIALIZER;
112
113 TEST(LazyInstanceTest, ConstructorThreadSafety) {
114   {
115     base::ShadowingAtExitManager shadow;
116
117     SlowDelegate delegate(&lazy_slow);
118     EXPECT_EQ(0, SlowConstructor::constructed);
119
120     base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
121     pool.AddWork(&delegate, 20);
122     EXPECT_EQ(0, SlowConstructor::constructed);
123
124     pool.Start();
125     pool.JoinAll();
126     EXPECT_EQ(1, SlowConstructor::constructed);
127   }
128 }
129
130 namespace {
131
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.
134 class DeleteLogger {
135  public:
136   DeleteLogger() : deleted_(nullptr) {}
137   ~DeleteLogger() { *deleted_ = true; }
138
139   void SetDeletedPtr(bool* deleted) {
140     deleted_ = deleted;
141   }
142
143  private:
144   raw_ptr<bool> deleted_;
145 };
146
147 }  // anonymous namespace
148
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;
153   {
154     base::ShadowingAtExitManager shadow;
155     static base::LazyInstance<DeleteLogger>::DestructorAtExit test =
156         LAZY_INSTANCE_INITIALIZER;
157     test.Get().SetDeletedPtr(&deleted1);
158   }
159   EXPECT_TRUE(deleted1);
160
161   // Check that using a *leaky* LazyInstance makes the dtor not run
162   // when the AtExitManager finishes.
163   bool deleted2 = false;
164   {
165     base::ShadowingAtExitManager shadow;
166     static base::LazyInstance<DeleteLogger>::Leaky
167         test = LAZY_INSTANCE_INITIALIZER;
168     test.Get().SetDeletedPtr(&deleted2);
169   }
170   EXPECT_FALSE(deleted2);
171 }
172
173 namespace {
174
175 template <size_t alignment>
176 class AlignedData {
177  public:
178   AlignedData() = default;
179   ~AlignedData() = default;
180   alignas(alignment) char data_[alignment];
181 };
182
183 }  // namespace
184
185 TEST(LazyInstanceTest, Alignment) {
186   using base::LazyInstance;
187
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;
197
198   EXPECT_TRUE(base::IsAligned(align4.Pointer(), 4));
199   EXPECT_TRUE(base::IsAligned(align32.Pointer(), 32));
200   EXPECT_TRUE(base::IsAligned(align4096.Pointer(), 4096));
201 }
202
203 namespace {
204
205 // A class whose constructor busy-loops until it is told to complete
206 // construction.
207 class BlockingConstructor {
208  public:
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;
216   }
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);
223   }
224
225   // Returns true if BlockingConstructor() was entered.
226   static bool WasConstructorCalled() {
227     return base::subtle::NoBarrier_Load(&constructor_called_);
228   }
229
230   // Instructs BlockingConstructor() that it may now unblock its construction.
231   static void CompleteConstructionNow() {
232     base::subtle::NoBarrier_Store(&complete_construction_, 1);
233   }
234
235   bool done_construction() const { return done_construction_; }
236
237  private:
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_;
241
242   bool done_construction_ = false;
243 };
244
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 {
248  public:
249   BlockingConstructorThread(
250       base::ThreadType thread_type,
251       base::LazyInstance<BlockingConstructor>::DestructorAtExit* lazy,
252       base::OnceClosure before_get)
253       : SimpleThread("BlockingConstructorThread", Options(thread_type)),
254         lazy_(lazy),
255         before_get_(std::move(before_get)) {}
256   BlockingConstructorThread(const BlockingConstructorThread&) = delete;
257   BlockingConstructorThread& operator=(const BlockingConstructorThread&) =
258       delete;
259
260   void Run() override {
261     if (before_get_)
262       std::move(before_get_).Run();
263     EXPECT_TRUE(lazy_->Get().done_construction());
264   }
265
266  private:
267   raw_ptr<base::LazyInstance<BlockingConstructor>::DestructorAtExit> lazy_;
268   base::OnceClosure before_get_;
269 };
270
271 // static
272 base::subtle::Atomic32 BlockingConstructor::constructor_called_ = 0;
273 // static
274 base::subtle::Atomic32 BlockingConstructor::complete_construction_ = 0;
275
276 base::LazyInstance<BlockingConstructor>::DestructorAtExit lazy_blocking =
277     LAZY_INSTANCE_INITIALIZER;
278
279 }  // namespace
280
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();
287
288   // Construct BlockingConstructor from a background thread.
289   BlockingConstructorThread background_getter(
290       base::ThreadType::kBackground, &lazy_blocking, base::OnceClosure());
291   background_getter.Start();
292
293   while (!BlockingConstructor::WasConstructorCalled())
294     base::PlatformThread::Sleep(base::Milliseconds(1));
295
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();
310   }
311
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();
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).
321   EXPECT_LT(base::TimeTicks::Now() - test_begin, base::Seconds(5));
322 }