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