• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ConstructAndDestructLogger()21   ConstructAndDestructLogger() {
22     constructed_seq_.GetNext();
23   }
~ConstructAndDestructLogger()24   ~ConstructAndDestructLogger() {
25     destructed_seq_.GetNext();
26   }
27 };
28 
29 class SlowConstructor {
30  public:
SlowConstructor()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   }
some_int() const37   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:
SlowDelegate(base::LazyInstance<SlowConstructor> * lazy)48   explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy)
49       : lazy_(lazy) {}
50 
Run()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 
62 static base::LazyInstance<ConstructAndDestructLogger> lazy_logger =
63     LAZY_INSTANCE_INITIALIZER;
64 
TEST(LazyInstanceTest,Basic)65 TEST(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 
84 static base::LazyInstance<SlowConstructor> lazy_slow =
85     LAZY_INSTANCE_INITIALIZER;
86 
TEST(LazyInstanceTest,ConstructorThreadSafety)87 TEST(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 
104 namespace {
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.
108 class DeleteLogger {
109  public:
DeleteLogger()110   DeleteLogger() : deleted_(NULL) {}
~DeleteLogger()111   ~DeleteLogger() { *deleted_ = true; }
112 
SetDeletedPtr(bool * deleted)113   void SetDeletedPtr(bool* deleted) {
114     deleted_ = deleted;
115   }
116 
117  private:
118   bool* deleted_;
119 };
120 
121 }  // anonymous namespace
122 
TEST(LazyInstanceTest,LeakyLazyInstance)123 TEST(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 
146 namespace {
147 
148 template <size_t alignment>
149 class AlignedData {
150  public:
AlignedData()151   AlignedData() {}
~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 
TEST(LazyInstanceTest,Alignment)161 TEST(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