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 14namespace { 15 16base::StaticAtomicSequenceNumber constructed_seq_; 17base::StaticAtomicSequenceNumber destructed_seq_; 18 19class ConstructAndDestructLogger { 20 public: 21 ConstructAndDestructLogger() { 22 constructed_seq_.GetNext(); 23 } 24 ~ConstructAndDestructLogger() { 25 destructed_seq_.GetNext(); 26 } 27}; 28 29class 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 44int SlowConstructor::constructed = 0; 45 46class 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 63static base::LazyInstance<ConstructAndDestructLogger>::DestructorAtExit 64 lazy_logger = LAZY_INSTANCE_INITIALIZER; 65 66TEST(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 85static base::LazyInstance<SlowConstructor>::DestructorAtExit lazy_slow = 86 LAZY_INSTANCE_INITIALIZER; 87 88TEST(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 105namespace { 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. 109class 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 124TEST(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 148namespace { 149 150template <size_t alignment> 151class 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 163TEST(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