blob: 8947b1291f60d54112fba0f13c72c86c9b29961a [file] [log] [blame]
[email protected]9fc44162012-01-23 22:56:411// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]30039e62008-09-08 14:11:132// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
avi9b6f42932015-12-26 22:15:145#include <stddef.h>
6
[email protected]30039e62008-09-08 14:11:137#include "base/at_exit.h"
8#include "base/atomic_sequence_num.h"
9#include "base/lazy_instance.h"
[email protected]cd924d62012-02-23 17:52:2010#include "base/memory/aligned_memory.h"
[email protected]ac9ba8fe2010-12-30 18:08:3611#include "base/threading/simple_thread.h"
[email protected]30039e62008-09-08 14:11:1312#include "testing/gtest/include/gtest/gtest.h"
13
14namespace {
15
[email protected]8a8443f2012-03-13 12:07:1916base::StaticAtomicSequenceNumber constructed_seq_;
17base::StaticAtomicSequenceNumber destructed_seq_;
[email protected]30039e62008-09-08 14:11:1318
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) {
[email protected]ce072a72010-12-31 20:02:1632 // Sleep for 1 second to try to cause a race.
[email protected]a1b75b942011-12-31 22:53:5133 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
[email protected]30039e62008-09-08 14:11:1334 ++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:
[email protected]2fdc86a2010-01-26 23:08:0248 explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy)
49 : lazy_(lazy) {}
50
dcheng56488182014-10-21 10:54:5151 void Run() override {
[email protected]30039e62008-09-08 14:11:1352 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
[email protected]6de0fd1d2011-11-15 13:31:4962static base::LazyInstance<ConstructAndDestructLogger> lazy_logger =
63 LAZY_INSTANCE_INITIALIZER;
[email protected]30039e62008-09-08 14:11:1364
65TEST(LazyInstanceTest, Basic) {
66 {
[email protected]4ea927b2009-11-19 09:11:3967 base::ShadowingAtExitManager shadow;
[email protected]30039e62008-09-08 14:11:1368
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());
[email protected]52a261f2009-03-03 15:01:1279 }
[email protected]30039e62008-09-08 14:11:1380 EXPECT_EQ(4, constructed_seq_.GetNext());
81 EXPECT_EQ(4, destructed_seq_.GetNext());
82}
83
[email protected]6de0fd1d2011-11-15 13:31:4984static base::LazyInstance<SlowConstructor> lazy_slow =
85 LAZY_INSTANCE_INITIALIZER;
[email protected]30039e62008-09-08 14:11:1386
87TEST(LazyInstanceTest, ConstructorThreadSafety) {
88 {
[email protected]4ea927b2009-11-19 09:11:3989 base::ShadowingAtExitManager shadow;
[email protected]30039e62008-09-08 14:11:1390
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}
[email protected]dcc69332010-10-21 20:41:47103
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;
[email protected]6de0fd1d2011-11-15 13:31:49129 static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER;
[email protected]dcc69332010-10-21 20:41:47130 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;
[email protected]9fc44162012-01-23 22:56:41139 static base::LazyInstance<DeleteLogger>::Leaky
[email protected]6de0fd1d2011-11-15 13:31:49140 test = LAZY_INSTANCE_INITIALIZER;
[email protected]dcc69332010-10-21 20:41:47141 test.Get().SetDeletedPtr(&deleted2);
142 }
143 EXPECT_FALSE(deleted2);
144}
[email protected]cd924d62012-02-23 17:52:20145
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}