|  | // 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 "base/at_exit.h" | 
|  | #include "base/atomic_sequence_num.h" | 
|  | #include "base/lazy_instance.h" | 
|  | #include "base/memory/aligned_memory.h" | 
|  | #include "base/threading/simple_thread.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | base::StaticAtomicSequenceNumber constructed_seq_; | 
|  | base::StaticAtomicSequenceNumber destructed_seq_; | 
|  |  | 
|  | class ConstructAndDestructLogger { | 
|  | public: | 
|  | ConstructAndDestructLogger() { | 
|  | constructed_seq_.GetNext(); | 
|  | } | 
|  | ~ConstructAndDestructLogger() { | 
|  | destructed_seq_.GetNext(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | 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_; | 
|  | }; | 
|  |  | 
|  | int SlowConstructor::constructed = 0; | 
|  |  | 
|  | class SlowDelegate : public base::DelegateSimpleThread::Delegate { | 
|  | public: | 
|  | explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy) | 
|  | : lazy_(lazy) {} | 
|  |  | 
|  | void Run() override { | 
|  | EXPECT_EQ(12, lazy_->Get().some_int()); | 
|  | EXPECT_EQ(12, lazy_->Pointer()->some_int()); | 
|  | } | 
|  |  | 
|  | private: | 
|  | base::LazyInstance<SlowConstructor>* lazy_; | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | static base::LazyInstance<ConstructAndDestructLogger> lazy_logger = | 
|  | LAZY_INSTANCE_INITIALIZER; | 
|  |  | 
|  | TEST(LazyInstanceTest, Basic) { | 
|  | { | 
|  | base::ShadowingAtExitManager shadow; | 
|  |  | 
|  | EXPECT_EQ(0, constructed_seq_.GetNext()); | 
|  | EXPECT_EQ(0, destructed_seq_.GetNext()); | 
|  |  | 
|  | lazy_logger.Get(); | 
|  | EXPECT_EQ(2, constructed_seq_.GetNext()); | 
|  | EXPECT_EQ(1, destructed_seq_.GetNext()); | 
|  |  | 
|  | lazy_logger.Pointer(); | 
|  | EXPECT_EQ(3, constructed_seq_.GetNext()); | 
|  | EXPECT_EQ(2, destructed_seq_.GetNext()); | 
|  | } | 
|  | EXPECT_EQ(4, constructed_seq_.GetNext()); | 
|  | EXPECT_EQ(4, destructed_seq_.GetNext()); | 
|  | } | 
|  |  | 
|  | static base::LazyInstance<SlowConstructor> 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_(NULL) {} | 
|  | ~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> 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() {} | 
|  | ~AlignedData() {} | 
|  | base::AlignedMemory<alignment, alignment> data_; | 
|  | }; | 
|  |  | 
|  | }  // anonymous 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> > align4 = LAZY_INSTANCE_INITIALIZER; | 
|  | static LazyInstance<AlignedData<32> > align32 = LAZY_INSTANCE_INITIALIZER; | 
|  | static LazyInstance<AlignedData<4096> > align4096 = LAZY_INSTANCE_INITIALIZER; | 
|  |  | 
|  | EXPECT_ALIGNED(align4.Pointer(), 4); | 
|  | EXPECT_ALIGNED(align32.Pointer(), 32); | 
|  | EXPECT_ALIGNED(align4096.Pointer(), 4096); | 
|  | } |