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