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 "base/at_exit.h" 6 #include "base/atomic_sequence_num.h" 7 #include "base/lazy_instance.h" 8 #include "base/memory/aligned_memory.h" 9 #include "base/threading/simple_thread.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 namespace { 13 14 base::StaticAtomicSequenceNumber constructed_seq_; 15 base::StaticAtomicSequenceNumber destructed_seq_; 16 17 class ConstructAndDestructLogger { 18 public: 19 ConstructAndDestructLogger() { 20 constructed_seq_.GetNext(); 21 } 22 ~ConstructAndDestructLogger() { 23 destructed_seq_.GetNext(); 24 } 25 }; 26 27 class SlowConstructor { 28 public: 29 SlowConstructor() : some_int_(0) { 30 // Sleep for 1 second to try to cause a race. 31 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); 32 ++constructed; 33 some_int_ = 12; 34 } 35 int some_int() const { return some_int_; } 36 37 static int constructed; 38 private: 39 int some_int_; 40 }; 41 42 int SlowConstructor::constructed = 0; 43 44 class SlowDelegate : public base::DelegateSimpleThread::Delegate { 45 public: 46 explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy) 47 : lazy_(lazy) {} 48 49 virtual void Run() OVERRIDE { 50 EXPECT_EQ(12, lazy_->Get().some_int()); 51 EXPECT_EQ(12, lazy_->Pointer()->some_int()); 52 } 53 54 private: 55 base::LazyInstance<SlowConstructor>* lazy_; 56 }; 57 58 } // namespace 59 60 static base::LazyInstance<ConstructAndDestructLogger> lazy_logger = 61 LAZY_INSTANCE_INITIALIZER; 62 63 TEST(LazyInstanceTest, Basic) { 64 { 65 base::ShadowingAtExitManager shadow; 66 67 EXPECT_EQ(0, constructed_seq_.GetNext()); 68 EXPECT_EQ(0, destructed_seq_.GetNext()); 69 70 lazy_logger.Get(); 71 EXPECT_EQ(2, constructed_seq_.GetNext()); 72 EXPECT_EQ(1, destructed_seq_.GetNext()); 73 74 lazy_logger.Pointer(); 75 EXPECT_EQ(3, constructed_seq_.GetNext()); 76 EXPECT_EQ(2, destructed_seq_.GetNext()); 77 } 78 EXPECT_EQ(4, constructed_seq_.GetNext()); 79 EXPECT_EQ(4, destructed_seq_.GetNext()); 80 } 81 82 static base::LazyInstance<SlowConstructor> lazy_slow = 83 LAZY_INSTANCE_INITIALIZER; 84 85 TEST(LazyInstanceTest, ConstructorThreadSafety) { 86 { 87 base::ShadowingAtExitManager shadow; 88 89 SlowDelegate delegate(&lazy_slow); 90 EXPECT_EQ(0, SlowConstructor::constructed); 91 92 base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5); 93 pool.AddWork(&delegate, 20); 94 EXPECT_EQ(0, SlowConstructor::constructed); 95 96 pool.Start(); 97 pool.JoinAll(); 98 EXPECT_EQ(1, SlowConstructor::constructed); 99 } 100 } 101 102 namespace { 103 104 // DeleteLogger is an object which sets a flag when it's destroyed. 105 // It accepts a bool* and sets the bool to true when the dtor runs. 106 class DeleteLogger { 107 public: 108 DeleteLogger() : deleted_(NULL) {} 109 ~DeleteLogger() { *deleted_ = true; } 110 111 void SetDeletedPtr(bool* deleted) { 112 deleted_ = deleted; 113 } 114 115 private: 116 bool* deleted_; 117 }; 118 119 } // anonymous namespace 120 121 TEST(LazyInstanceTest, LeakyLazyInstance) { 122 // Check that using a plain LazyInstance causes the dtor to run 123 // when the AtExitManager finishes. 124 bool deleted1 = false; 125 { 126 base::ShadowingAtExitManager shadow; 127 static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER; 128 test.Get().SetDeletedPtr(&deleted1); 129 } 130 EXPECT_TRUE(deleted1); 131 132 // Check that using a *leaky* LazyInstance makes the dtor not run 133 // when the AtExitManager finishes. 134 bool deleted2 = false; 135 { 136 base::ShadowingAtExitManager shadow; 137 static base::LazyInstance<DeleteLogger>::Leaky 138 test = LAZY_INSTANCE_INITIALIZER; 139 test.Get().SetDeletedPtr(&deleted2); 140 } 141 EXPECT_FALSE(deleted2); 142 } 143 144 namespace { 145 146 template <size_t alignment> 147 class AlignedData { 148 public: 149 AlignedData() {} 150 ~AlignedData() {} 151 base::AlignedMemory<alignment, alignment> data_; 152 }; 153 154 } // anonymous namespace 155 156 #define EXPECT_ALIGNED(ptr, align) \ 157 EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1)) 158 159 TEST(LazyInstanceTest, Alignment) { 160 using base::LazyInstance; 161 162 // Create some static instances with increasing sizes and alignment 163 // requirements. By ordering this way, the linker will need to do some work to 164 // ensure proper alignment of the static data. 165 static LazyInstance<AlignedData<4> > align4 = LAZY_INSTANCE_INITIALIZER; 166 static LazyInstance<AlignedData<32> > align32 = LAZY_INSTANCE_INITIALIZER; 167 static LazyInstance<AlignedData<4096> > align4096 = LAZY_INSTANCE_INITIALIZER; 168 169 EXPECT_ALIGNED(align4.Pointer(), 4); 170 EXPECT_ALIGNED(align32.Pointer(), 32); 171 EXPECT_ALIGNED(align4096.Pointer(), 4096); 172 } 173