| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include <stddef.h> | 
 |  | 
 | #include <memory> | 
 | #include <vector> | 
 |  | 
 | #include "base/at_exit.h" | 
 | #include "base/atomic_sequence_num.h" | 
 | #include "base/atomicops.h" | 
 | #include "base/barrier_closure.h" | 
 | #include "base/bind.h" | 
 | #include "base/lazy_instance.h" | 
 | #include "base/sys_info.h" | 
 | #include "base/threading/platform_thread.h" | 
 | #include "base/threading/simple_thread.h" | 
 | #include "base/time/time.h" | 
 | #include "build_config.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | namespace { | 
 |  | 
 | base::AtomicSequenceNumber constructed_seq_; | 
 | base::AtomicSequenceNumber destructed_seq_; | 
 |  | 
 | class ConstructAndDestructLogger { | 
 |  public: | 
 |   ConstructAndDestructLogger() { | 
 |     constructed_seq_.GetNext(); | 
 |   } | 
 |   ~ConstructAndDestructLogger() { | 
 |     destructed_seq_.GetNext(); | 
 |   } | 
 |  | 
 |  private: | 
 |   DISALLOW_COPY_AND_ASSIGN(ConstructAndDestructLogger); | 
 | }; | 
 |  | 
 | class SlowConstructor { | 
 |  public: | 
 |   SlowConstructor() : some_int_(0) { | 
 |     // Sleep for 1 second to try to cause a race. | 
 |     base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); | 
 |     ++constructed; | 
 |     some_int_ = 12; | 
 |   } | 
 |   int some_int() const { return some_int_; } | 
 |  | 
 |   static int constructed; | 
 |  private: | 
 |   int some_int_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(SlowConstructor); | 
 | }; | 
 |  | 
 | // static | 
 | int SlowConstructor::constructed = 0; | 
 |  | 
 | class SlowDelegate : public base::DelegateSimpleThread::Delegate { | 
 |  public: | 
 |   explicit SlowDelegate( | 
 |       base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy) | 
 |       : lazy_(lazy) {} | 
 |  | 
 |   void Run() override { | 
 |     EXPECT_EQ(12, lazy_->Get().some_int()); | 
 |     EXPECT_EQ(12, lazy_->Pointer()->some_int()); | 
 |   } | 
 |  | 
 |  private: | 
 |   base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(SlowDelegate); | 
 | }; | 
 |  | 
 | }  // namespace | 
 |  | 
 | base::LazyInstance<ConstructAndDestructLogger>::DestructorAtExit lazy_logger = | 
 |     LAZY_INSTANCE_INITIALIZER; | 
 |  | 
 | TEST(LazyInstanceTest, Basic) { | 
 |   { | 
 |     base::ShadowingAtExitManager shadow; | 
 |  | 
 |     EXPECT_FALSE(lazy_logger.IsCreated()); | 
 |     EXPECT_EQ(0, constructed_seq_.GetNext()); | 
 |     EXPECT_EQ(0, destructed_seq_.GetNext()); | 
 |  | 
 |     lazy_logger.Get(); | 
 |     EXPECT_TRUE(lazy_logger.IsCreated()); | 
 |     EXPECT_EQ(2, constructed_seq_.GetNext()); | 
 |     EXPECT_EQ(1, destructed_seq_.GetNext()); | 
 |  | 
 |     lazy_logger.Pointer(); | 
 |     EXPECT_TRUE(lazy_logger.IsCreated()); | 
 |     EXPECT_EQ(3, constructed_seq_.GetNext()); | 
 |     EXPECT_EQ(2, destructed_seq_.GetNext()); | 
 |   } | 
 |   EXPECT_FALSE(lazy_logger.IsCreated()); | 
 |   EXPECT_EQ(4, constructed_seq_.GetNext()); | 
 |   EXPECT_EQ(4, destructed_seq_.GetNext()); | 
 | } | 
 |  | 
 | base::LazyInstance<SlowConstructor>::DestructorAtExit lazy_slow = | 
 |     LAZY_INSTANCE_INITIALIZER; | 
 |  | 
 | TEST(LazyInstanceTest, ConstructorThreadSafety) { | 
 |   { | 
 |     base::ShadowingAtExitManager shadow; | 
 |  | 
 |     SlowDelegate delegate(&lazy_slow); | 
 |     EXPECT_EQ(0, SlowConstructor::constructed); | 
 |  | 
 |     base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5); | 
 |     pool.AddWork(&delegate, 20); | 
 |     EXPECT_EQ(0, SlowConstructor::constructed); | 
 |  | 
 |     pool.Start(); | 
 |     pool.JoinAll(); | 
 |     EXPECT_EQ(1, SlowConstructor::constructed); | 
 |   } | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | // DeleteLogger is an object which sets a flag when it's destroyed. | 
 | // It accepts a bool* and sets the bool to true when the dtor runs. | 
 | class DeleteLogger { | 
 |  public: | 
 |   DeleteLogger() : deleted_(nullptr) {} | 
 |   ~DeleteLogger() { *deleted_ = true; } | 
 |  | 
 |   void SetDeletedPtr(bool* deleted) { | 
 |     deleted_ = deleted; | 
 |   } | 
 |  | 
 |  private: | 
 |   bool* deleted_; | 
 | }; | 
 |  | 
 | }  // anonymous namespace | 
 |  | 
 | TEST(LazyInstanceTest, LeakyLazyInstance) { | 
 |   // Check that using a plain LazyInstance causes the dtor to run | 
 |   // when the AtExitManager finishes. | 
 |   bool deleted1 = false; | 
 |   { | 
 |     base::ShadowingAtExitManager shadow; | 
 |     static base::LazyInstance<DeleteLogger>::DestructorAtExit test = | 
 |         LAZY_INSTANCE_INITIALIZER; | 
 |     test.Get().SetDeletedPtr(&deleted1); | 
 |   } | 
 |   EXPECT_TRUE(deleted1); | 
 |  | 
 |   // Check that using a *leaky* LazyInstance makes the dtor not run | 
 |   // when the AtExitManager finishes. | 
 |   bool deleted2 = false; | 
 |   { | 
 |     base::ShadowingAtExitManager shadow; | 
 |     static base::LazyInstance<DeleteLogger>::Leaky | 
 |         test = LAZY_INSTANCE_INITIALIZER; | 
 |     test.Get().SetDeletedPtr(&deleted2); | 
 |   } | 
 |   EXPECT_FALSE(deleted2); | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | template <size_t alignment> | 
 | class AlignedData { | 
 |  public: | 
 |   AlignedData() = default; | 
 |   ~AlignedData() = default; | 
 |   alignas(alignment) char data_[alignment]; | 
 | }; | 
 |  | 
 | }  // namespace | 
 |  | 
 | #define EXPECT_ALIGNED(ptr, align) \ | 
 |     EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1)) | 
 |  | 
 | TEST(LazyInstanceTest, Alignment) { | 
 |   using base::LazyInstance; | 
 |  | 
 |   // Create some static instances with increasing sizes and alignment | 
 |   // requirements. By ordering this way, the linker will need to do some work to | 
 |   // ensure proper alignment of the static data. | 
 |   static LazyInstance<AlignedData<4>>::DestructorAtExit align4 = | 
 |       LAZY_INSTANCE_INITIALIZER; | 
 |   static LazyInstance<AlignedData<32>>::DestructorAtExit align32 = | 
 |       LAZY_INSTANCE_INITIALIZER; | 
 |   static LazyInstance<AlignedData<4096>>::DestructorAtExit align4096 = | 
 |       LAZY_INSTANCE_INITIALIZER; | 
 |  | 
 |   EXPECT_ALIGNED(align4.Pointer(), 4); | 
 |   EXPECT_ALIGNED(align32.Pointer(), 32); | 
 |   EXPECT_ALIGNED(align4096.Pointer(), 4096); | 
 | } | 
 |  | 
 | namespace { | 
 |  | 
 | // A class whose constructor busy-loops until it is told to complete | 
 | // construction. | 
 | class BlockingConstructor { | 
 |  public: | 
 |   BlockingConstructor() { | 
 |     EXPECT_FALSE(WasConstructorCalled()); | 
 |     base::subtle::NoBarrier_Store(&constructor_called_, 1); | 
 |     EXPECT_TRUE(WasConstructorCalled()); | 
 |     while (!base::subtle::NoBarrier_Load(&complete_construction_)) | 
 |       base::PlatformThread::YieldCurrentThread(); | 
 |     done_construction_ = true; | 
 |   } | 
 |  | 
 |   ~BlockingConstructor() { | 
 |     // Restore static state for the next test. | 
 |     base::subtle::NoBarrier_Store(&constructor_called_, 0); | 
 |     base::subtle::NoBarrier_Store(&complete_construction_, 0); | 
 |   } | 
 |  | 
 |   // Returns true if BlockingConstructor() was entered. | 
 |   static bool WasConstructorCalled() { | 
 |     return base::subtle::NoBarrier_Load(&constructor_called_); | 
 |   } | 
 |  | 
 |   // Instructs BlockingConstructor() that it may now unblock its construction. | 
 |   static void CompleteConstructionNow() { | 
 |     base::subtle::NoBarrier_Store(&complete_construction_, 1); | 
 |   } | 
 |  | 
 |   bool done_construction() { return done_construction_; } | 
 |  | 
 |  private: | 
 |   // Use Atomic32 instead of AtomicFlag for them to be trivially initialized. | 
 |   static base::subtle::Atomic32 constructor_called_; | 
 |   static base::subtle::Atomic32 complete_construction_; | 
 |  | 
 |   bool done_construction_ = false; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(BlockingConstructor); | 
 | }; | 
 |  | 
 | // A SimpleThread running at |thread_priority| which invokes |before_get| | 
 | // (optional) and then invokes Get() on the LazyInstance it's assigned. | 
 | class BlockingConstructorThread : public base::SimpleThread { | 
 |  public: | 
 |   BlockingConstructorThread( | 
 |       base::ThreadPriority thread_priority, | 
 |       base::LazyInstance<BlockingConstructor>::DestructorAtExit* lazy, | 
 |       base::OnceClosure before_get) | 
 |       : SimpleThread("BlockingConstructorThread", Options(thread_priority)), | 
 |         lazy_(lazy), | 
 |         before_get_(std::move(before_get)) {} | 
 |  | 
 |   void Run() override { | 
 |     if (before_get_) | 
 |       std::move(before_get_).Run(); | 
 |     EXPECT_TRUE(lazy_->Get().done_construction()); | 
 |   } | 
 |  | 
 |  private: | 
 |   base::LazyInstance<BlockingConstructor>::DestructorAtExit* lazy_; | 
 |   base::OnceClosure before_get_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(BlockingConstructorThread); | 
 | }; | 
 |  | 
 | // static | 
 | base::subtle::Atomic32 BlockingConstructor::constructor_called_ = 0; | 
 | // static | 
 | base::subtle::Atomic32 BlockingConstructor::complete_construction_ = 0; | 
 |  | 
 | base::LazyInstance<BlockingConstructor>::DestructorAtExit lazy_blocking = | 
 |     LAZY_INSTANCE_INITIALIZER; | 
 |  | 
 | }  // namespace | 
 |  | 
 | // Tests that if the thread assigned to construct the LazyInstance runs at | 
 | // background priority : the foreground threads will yield to it enough for it | 
 | // to eventually complete construction. | 
 | // This is a regression test for https://crbug.com/797129. | 
 | TEST(LazyInstanceTest, PriorityInversionAtInitializationResolves) { | 
 |   base::TimeTicks test_begin = base::TimeTicks::Now(); | 
 |  | 
 |   // Construct BlockingConstructor from a background thread. | 
 |   BlockingConstructorThread background_getter( | 
 |       base::ThreadPriority::BACKGROUND, &lazy_blocking, base::OnceClosure()); | 
 |   background_getter.Start(); | 
 |  | 
 |   while (!BlockingConstructor::WasConstructorCalled()) | 
 |     base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); | 
 |  | 
 |   // Spin 4 foreground thread per core contending to get the already under | 
 |   // construction LazyInstance. When they are all running and poking at it : | 
 |   // allow the background thread to complete its work. | 
 |   const int kNumForegroundThreads = 4 * base::SysInfo::NumberOfProcessors(); | 
 |   std::vector<std::unique_ptr<base::SimpleThread>> foreground_threads; | 
 |   base::RepeatingClosure foreground_thread_ready_callback = | 
 |       base::BarrierClosure( | 
 |           kNumForegroundThreads, | 
 |           base::BindOnce(&BlockingConstructor::CompleteConstructionNow)); | 
 |   for (int i = 0; i < kNumForegroundThreads; ++i) { | 
 |     foreground_threads.push_back(std::make_unique<BlockingConstructorThread>( | 
 |         base::ThreadPriority::NORMAL, &lazy_blocking, | 
 |         foreground_thread_ready_callback)); | 
 |     foreground_threads.back()->Start(); | 
 |   } | 
 |  | 
 |   // This test will hang if the foreground threads become stuck in | 
 |   // LazyInstance::Get() per the background thread never being scheduled to | 
 |   // complete construction. | 
 |   for (auto& foreground_thread : foreground_threads) | 
 |     foreground_thread->Join(); | 
 |   background_getter.Join(); | 
 |  | 
 |   // Fail if this test takes more than 5 seconds (it takes 5-10 seconds on a | 
 |   // Z840 without r527445 but is expected to be fast (~30ms) with the fix). | 
 |   EXPECT_LT(base::TimeTicks::Now() - test_begin, | 
 |             base::TimeDelta::FromSeconds(5)); | 
 | } |