lazy_instance_unittest.cc 10 KB

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