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(base::LazyInstance<SlowConstructor>* lazy) 49 : lazy_(lazy) {} 50 51 void Run() override { 52 EXPECT_EQ(12, lazy_->Get().some_int()); 53 EXPECT_EQ(12, lazy_->Pointer()->some_int()); 54 } 55 56 private: 57 base::LazyInstance<SlowConstructor>* lazy_; 58}; 59 60} // namespace 61 62static base::LazyInstance<ConstructAndDestructLogger> lazy_logger = 63 LAZY_INSTANCE_INITIALIZER; 64 65TEST(LazyInstanceTest, Basic) { 66 { 67 base::ShadowingAtExitManager shadow; 68 69 EXPECT_EQ(0, constructed_seq_.GetNext()); 70 EXPECT_EQ(0, destructed_seq_.GetNext()); 71 72 lazy_logger.Get(); 73 EXPECT_EQ(2, constructed_seq_.GetNext()); 74 EXPECT_EQ(1, destructed_seq_.GetNext()); 75 76 lazy_logger.Pointer(); 77 EXPECT_EQ(3, constructed_seq_.GetNext()); 78 EXPECT_EQ(2, destructed_seq_.GetNext()); 79 } 80 EXPECT_EQ(4, constructed_seq_.GetNext()); 81 EXPECT_EQ(4, destructed_seq_.GetNext()); 82} 83 84static base::LazyInstance<SlowConstructor> lazy_slow = 85 LAZY_INSTANCE_INITIALIZER; 86 87TEST(LazyInstanceTest, ConstructorThreadSafety) { 88 { 89 base::ShadowingAtExitManager shadow; 90 91 SlowDelegate delegate(&lazy_slow); 92 EXPECT_EQ(0, SlowConstructor::constructed); 93 94 base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5); 95 pool.AddWork(&delegate, 20); 96 EXPECT_EQ(0, SlowConstructor::constructed); 97 98 pool.Start(); 99 pool.JoinAll(); 100 EXPECT_EQ(1, SlowConstructor::constructed); 101 } 102} 103 104namespace { 105 106// DeleteLogger is an object which sets a flag when it's destroyed. 107// It accepts a bool* and sets the bool to true when the dtor runs. 108class DeleteLogger { 109 public: 110 DeleteLogger() : deleted_(NULL) {} 111 ~DeleteLogger() { *deleted_ = true; } 112 113 void SetDeletedPtr(bool* deleted) { 114 deleted_ = deleted; 115 } 116 117 private: 118 bool* deleted_; 119}; 120 121} // anonymous namespace 122 123TEST(LazyInstanceTest, LeakyLazyInstance) { 124 // Check that using a plain LazyInstance causes the dtor to run 125 // when the AtExitManager finishes. 126 bool deleted1 = false; 127 { 128 base::ShadowingAtExitManager shadow; 129 static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER; 130 test.Get().SetDeletedPtr(&deleted1); 131 } 132 EXPECT_TRUE(deleted1); 133 134 // Check that using a *leaky* LazyInstance makes the dtor not run 135 // when the AtExitManager finishes. 136 bool deleted2 = false; 137 { 138 base::ShadowingAtExitManager shadow; 139 static base::LazyInstance<DeleteLogger>::Leaky 140 test = LAZY_INSTANCE_INITIALIZER; 141 test.Get().SetDeletedPtr(&deleted2); 142 } 143 EXPECT_FALSE(deleted2); 144} 145 146namespace { 147 148template <size_t alignment> 149class AlignedData { 150 public: 151 AlignedData() {} 152 ~AlignedData() {} 153 base::AlignedMemory<alignment, alignment> data_; 154}; 155 156} // anonymous namespace 157 158#define EXPECT_ALIGNED(ptr, align) \ 159 EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1)) 160 161TEST(LazyInstanceTest, Alignment) { 162 using base::LazyInstance; 163 164 // Create some static instances with increasing sizes and alignment 165 // requirements. By ordering this way, the linker will need to do some work to 166 // ensure proper alignment of the static data. 167 static LazyInstance<AlignedData<4> > align4 = LAZY_INSTANCE_INITIALIZER; 168 static LazyInstance<AlignedData<32> > align32 = LAZY_INSTANCE_INITIALIZER; 169 static LazyInstance<AlignedData<4096> > align4096 = LAZY_INSTANCE_INITIALIZER; 170 171 EXPECT_ALIGNED(align4.Pointer(), 4); 172 EXPECT_ALIGNED(align32.Pointer(), 32); 173 EXPECT_ALIGNED(align4096.Pointer(), 4096); 174} 175