no_destructor_unittest.cc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Copyright 2018 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 "base/no_destructor.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/atomicops.h"
  10. #include "base/barrier_closure.h"
  11. #include "base/bind.h"
  12. #include "base/check.h"
  13. #include "base/system/sys_info.h"
  14. #include "base/threading/platform_thread.h"
  15. #include "base/threading/simple_thread.h"
  16. #include "build/build_config.h"
  17. #include "testing/gtest/include/gtest/gtest.h"
  18. namespace base {
  19. namespace {
  20. struct CheckOnDestroy {
  21. ~CheckOnDestroy() { CHECK(false); }
  22. };
  23. TEST(NoDestructorTest, SkipsDestructors) {
  24. NoDestructor<CheckOnDestroy> destructor_should_not_run;
  25. }
  26. struct UncopyableUnmovable {
  27. UncopyableUnmovable() = default;
  28. explicit UncopyableUnmovable(int value) : value(value) {}
  29. UncopyableUnmovable(const UncopyableUnmovable&) = delete;
  30. UncopyableUnmovable& operator=(const UncopyableUnmovable&) = delete;
  31. int value = 1;
  32. std::string something_with_a_nontrivial_destructor;
  33. };
  34. struct CopyOnly {
  35. CopyOnly() = default;
  36. CopyOnly(const CopyOnly&) = default;
  37. CopyOnly& operator=(const CopyOnly&) = default;
  38. CopyOnly(CopyOnly&&) = delete;
  39. CopyOnly& operator=(CopyOnly&&) = delete;
  40. };
  41. struct MoveOnly {
  42. MoveOnly() = default;
  43. MoveOnly(const MoveOnly&) = delete;
  44. MoveOnly& operator=(const MoveOnly&) = delete;
  45. MoveOnly(MoveOnly&&) = default;
  46. MoveOnly& operator=(MoveOnly&&) = default;
  47. };
  48. struct ForwardingTestStruct {
  49. ForwardingTestStruct(const CopyOnly&, MoveOnly&&) {}
  50. std::string something_with_a_nontrivial_destructor;
  51. };
  52. TEST(NoDestructorTest, UncopyableUnmovable) {
  53. static NoDestructor<UncopyableUnmovable> default_constructed;
  54. EXPECT_EQ(1, default_constructed->value);
  55. static NoDestructor<UncopyableUnmovable> constructed_with_arg(-1);
  56. EXPECT_EQ(-1, constructed_with_arg->value);
  57. }
  58. TEST(NoDestructorTest, ForwardsArguments) {
  59. CopyOnly copy_only;
  60. MoveOnly move_only;
  61. static NoDestructor<ForwardingTestStruct> test_forwarding(
  62. copy_only, std::move(move_only));
  63. }
  64. TEST(NoDestructorTest, Accessors) {
  65. static NoDestructor<std::string> awesome("awesome");
  66. EXPECT_EQ("awesome", *awesome);
  67. EXPECT_EQ(0, awesome->compare("awesome"));
  68. EXPECT_EQ(0, awesome.get()->compare("awesome"));
  69. }
  70. TEST(NoDestructorTest, AllowForTriviallyDestructibleType) {
  71. static NoDestructor<bool, AllowForTriviallyDestructibleType>
  72. trivially_destructible_type;
  73. }
  74. // Passing initializer list to a NoDestructor like in this test
  75. // is ambiguous in GCC.
  76. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84849
  77. #if !defined(COMPILER_GCC) && !defined(__clang__)
  78. TEST(NoDestructorTest, InitializerList) {
  79. static NoDestructor<std::vector<std::string>> vector({"a", "b", "c"});
  80. }
  81. #endif
  82. } // namespace
  83. namespace {
  84. // A class whose constructor busy-loops until it is told to complete
  85. // construction.
  86. class BlockingConstructor {
  87. public:
  88. BlockingConstructor() {
  89. EXPECT_FALSE(WasConstructorCalled());
  90. subtle::NoBarrier_Store(&constructor_called_, 1);
  91. EXPECT_TRUE(WasConstructorCalled());
  92. while (!subtle::NoBarrier_Load(&complete_construction_))
  93. PlatformThread::YieldCurrentThread();
  94. done_construction_ = true;
  95. }
  96. BlockingConstructor(const BlockingConstructor&) = delete;
  97. BlockingConstructor& operator=(const BlockingConstructor&) = delete;
  98. ~BlockingConstructor() = delete;
  99. // Returns true if BlockingConstructor() was entered.
  100. static bool WasConstructorCalled() {
  101. return subtle::NoBarrier_Load(&constructor_called_);
  102. }
  103. // Instructs BlockingConstructor() that it may now unblock its construction.
  104. static void CompleteConstructionNow() {
  105. subtle::NoBarrier_Store(&complete_construction_, 1);
  106. }
  107. bool done_construction() const { return done_construction_; }
  108. private:
  109. // Use Atomic32 instead of AtomicFlag for them to be trivially initialized.
  110. static subtle::Atomic32 constructor_called_;
  111. static subtle::Atomic32 complete_construction_;
  112. bool done_construction_ = false;
  113. };
  114. // static
  115. subtle::Atomic32 BlockingConstructor::constructor_called_ = 0;
  116. // static
  117. subtle::Atomic32 BlockingConstructor::complete_construction_ = 0;
  118. // A SimpleThread running at |thread_type| which invokes |before_get| (optional)
  119. // and then invokes thread-safe scoped-static-initializationconstruction on its
  120. // NoDestructor instance.
  121. class BlockingConstructorThread : public SimpleThread {
  122. public:
  123. BlockingConstructorThread(ThreadType thread_type, OnceClosure before_get)
  124. : SimpleThread("BlockingConstructorThread", Options(thread_type)),
  125. before_get_(std::move(before_get)) {}
  126. BlockingConstructorThread(const BlockingConstructorThread&) = delete;
  127. BlockingConstructorThread& operator=(const BlockingConstructorThread&) =
  128. delete;
  129. void Run() override {
  130. if (before_get_)
  131. std::move(before_get_).Run();
  132. static NoDestructor<BlockingConstructor> instance;
  133. EXPECT_TRUE(instance->done_construction());
  134. }
  135. private:
  136. OnceClosure before_get_;
  137. };
  138. } // namespace
  139. // Tests that if the thread assigned to construct the local-static
  140. // initialization of the NoDestructor runs at background priority : the
  141. // foreground threads will yield to it enough for it to eventually complete
  142. // construction. While local-static thread-safe initialization isn't specific to
  143. // NoDestructor, it is tested here as NoDestructor is set to replace
  144. // LazyInstance and this is an important regression test for it
  145. // (https://crbug.com/797129).
  146. TEST(NoDestructorTest, PriorityInversionAtStaticInitializationResolves) {
  147. TimeTicks test_begin = TimeTicks::Now();
  148. // Construct BlockingConstructor from a thread that is lower priority than the
  149. // other threads that will be constructed. This thread used to be BACKGROUND
  150. // priority but that caused it to be starved by other simultaneously running
  151. // test processes, leading to false-positive failures.
  152. BlockingConstructorThread background_getter(ThreadType::kDefault,
  153. OnceClosure());
  154. background_getter.Start();
  155. while (!BlockingConstructor::WasConstructorCalled())
  156. PlatformThread::Sleep(Milliseconds(1));
  157. // Spin 4 foreground thread per core contending to get the already under
  158. // construction NoDestructor. When they are all running and poking at it :
  159. // allow the background thread to complete its work.
  160. const int kNumForegroundThreads = 4 * SysInfo::NumberOfProcessors();
  161. std::vector<std::unique_ptr<SimpleThread>> foreground_threads;
  162. RepeatingClosure foreground_thread_ready_callback =
  163. BarrierClosure(kNumForegroundThreads,
  164. BindOnce(&BlockingConstructor::CompleteConstructionNow));
  165. for (int i = 0; i < kNumForegroundThreads; ++i) {
  166. // Create threads that are higher priority than background_getter. See above
  167. // for why these particular priorities are chosen.
  168. foreground_threads.push_back(std::make_unique<BlockingConstructorThread>(
  169. ThreadType::kDisplayCritical, foreground_thread_ready_callback));
  170. foreground_threads.back()->Start();
  171. }
  172. // This test will hang if the foreground threads become stuck in
  173. // NoDestructor's construction per the background thread never being scheduled
  174. // to complete construction.
  175. for (auto& foreground_thread : foreground_threads)
  176. foreground_thread->Join();
  177. background_getter.Join();
  178. // Fail if this test takes more than 5 seconds (it takes 5-10 seconds on a
  179. // Z840 without https://crrev.com/527445 but is expected to be fast (~30ms)
  180. // with the fix).
  181. EXPECT_LT(TimeTicks::Now() - test_begin, Seconds(5));
  182. }
  183. } // namespace base