1 // Copyright (c) 2008 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/threading/simple_thread.h" 9 #include "testing/gtest/include/gtest/gtest.h" 10 11 namespace { 12 13 base::AtomicSequenceNumber constructed_seq_(base::LINKER_INITIALIZED); 14 base::AtomicSequenceNumber destructed_seq_(base::LINKER_INITIALIZED); 15 16 class ConstructAndDestructLogger { 17 public: 18 ConstructAndDestructLogger() { 19 constructed_seq_.GetNext(); 20 } 21 ~ConstructAndDestructLogger() { 22 destructed_seq_.GetNext(); 23 } 24 }; 25 26 class SlowConstructor { 27 public: 28 SlowConstructor() : some_int_(0) { 29 // Sleep for 1 second to try to cause a race. 30 base::PlatformThread::Sleep(1000); 31 ++constructed; 32 some_int_ = 12; 33 } 34 int some_int() const { return some_int_; } 35 36 static int constructed; 37 private: 38 int some_int_; 39 }; 40 41 int SlowConstructor::constructed = 0; 42 43 class SlowDelegate : public base::DelegateSimpleThread::Delegate { 44 public: 45 explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy) 46 : lazy_(lazy) {} 47 48 virtual void Run() { 49 EXPECT_EQ(12, lazy_->Get().some_int()); 50 EXPECT_EQ(12, lazy_->Pointer()->some_int()); 51 } 52 53 private: 54 base::LazyInstance<SlowConstructor>* lazy_; 55 }; 56 57 } // namespace 58 59 static base::LazyInstance<ConstructAndDestructLogger> lazy_logger( 60 base::LINKER_INITIALIZED); 61 62 TEST(LazyInstanceTest, Basic) { 63 { 64 base::ShadowingAtExitManager shadow; 65 66 EXPECT_EQ(0, constructed_seq_.GetNext()); 67 EXPECT_EQ(0, destructed_seq_.GetNext()); 68 69 lazy_logger.Get(); 70 EXPECT_EQ(2, constructed_seq_.GetNext()); 71 EXPECT_EQ(1, destructed_seq_.GetNext()); 72 73 lazy_logger.Pointer(); 74 EXPECT_EQ(3, constructed_seq_.GetNext()); 75 EXPECT_EQ(2, destructed_seq_.GetNext()); 76 } 77 EXPECT_EQ(4, constructed_seq_.GetNext()); 78 EXPECT_EQ(4, destructed_seq_.GetNext()); 79 } 80 81 static base::LazyInstance<SlowConstructor> lazy_slow(base::LINKER_INITIALIZED); 82 83 TEST(LazyInstanceTest, ConstructorThreadSafety) { 84 { 85 base::ShadowingAtExitManager shadow; 86 87 SlowDelegate delegate(&lazy_slow); 88 EXPECT_EQ(0, SlowConstructor::constructed); 89 90 base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5); 91 pool.AddWork(&delegate, 20); 92 EXPECT_EQ(0, SlowConstructor::constructed); 93 94 pool.Start(); 95 pool.JoinAll(); 96 EXPECT_EQ(1, SlowConstructor::constructed); 97 } 98 } 99 100 namespace { 101 102 // DeleteLogger is an object which sets a flag when it's destroyed. 103 // It accepts a bool* and sets the bool to true when the dtor runs. 104 class DeleteLogger { 105 public: 106 DeleteLogger() : deleted_(NULL) {} 107 ~DeleteLogger() { *deleted_ = true; } 108 109 void SetDeletedPtr(bool* deleted) { 110 deleted_ = deleted; 111 } 112 113 private: 114 bool* deleted_; 115 }; 116 117 } // anonymous namespace 118 119 TEST(LazyInstanceTest, LeakyLazyInstance) { 120 // Check that using a plain LazyInstance causes the dtor to run 121 // when the AtExitManager finishes. 122 bool deleted1 = false; 123 { 124 base::ShadowingAtExitManager shadow; 125 static base::LazyInstance<DeleteLogger> test(base::LINKER_INITIALIZED); 126 test.Get().SetDeletedPtr(&deleted1); 127 } 128 EXPECT_TRUE(deleted1); 129 130 // Check that using a *leaky* LazyInstance makes the dtor not run 131 // when the AtExitManager finishes. 132 bool deleted2 = false; 133 { 134 base::ShadowingAtExitManager shadow; 135 static base::LazyInstance<DeleteLogger, 136 base::LeakyLazyInstanceTraits<DeleteLogger> > 137 test(base::LINKER_INITIALIZED); 138 test.Get().SetDeletedPtr(&deleted2); 139 } 140 EXPECT_FALSE(deleted2); 141 } 142