blob: ba18ddd28019f57cfd5744dd4499edde5f174e87 [file] [log] [blame]
fischman@chromium.org998561e2012-01-24 07:56:41 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
deanm@google.coma6deb002008-09-08 23:11:13 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
avia6a6a682015-12-27 07:15:14 +09005#include <stddef.h>
6
deanm@google.coma6deb002008-09-08 23:11:13 +09007#include "base/at_exit.h"
8#include "base/atomic_sequence_num.h"
9#include "base/lazy_instance.h"
brettw@chromium.org34f964f2010-12-31 03:08:36 +090010#include "base/threading/simple_thread.h"
brettwdd9392c2017-06-14 06:58:40 +090011#include "build/build_config.h"
deanm@google.coma6deb002008-09-08 23:11:13 +090012#include "testing/gtest/include/gtest/gtest.h"
13
14namespace {
15
pliard@chromium.orgac1f41d2012-03-13 21:07:19 +090016base::StaticAtomicSequenceNumber constructed_seq_;
17base::StaticAtomicSequenceNumber destructed_seq_;
deanm@google.coma6deb002008-09-08 23:11:13 +090018
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) {
brettw@chromium.org61391822011-01-01 05:02:16 +090032 // Sleep for 1 second to try to cause a race.
tedvessenes@gmail.comaaa63032012-01-01 07:53:51 +090033 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
deanm@google.coma6deb002008-09-08 23:11:13 +090034 ++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:
scottmg7a1ef762017-03-08 17:48:46 +090048 explicit SlowDelegate(
49 base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy)
erg@google.combf6ce9f2010-01-27 08:08:02 +090050 : lazy_(lazy) {}
51
dcheng7dc8df52014-10-21 19:54:51 +090052 void Run() override {
deanm@google.coma6deb002008-09-08 23:11:13 +090053 EXPECT_EQ(12, lazy_->Get().some_int());
54 EXPECT_EQ(12, lazy_->Pointer()->some_int());
55 }
56
57 private:
scottmg7a1ef762017-03-08 17:48:46 +090058 base::LazyInstance<SlowConstructor>::DestructorAtExit* lazy_;
deanm@google.coma6deb002008-09-08 23:11:13 +090059};
60
61} // namespace
62
scottmg7a1ef762017-03-08 17:48:46 +090063static base::LazyInstance<ConstructAndDestructLogger>::DestructorAtExit
64 lazy_logger = LAZY_INSTANCE_INITIALIZER;
deanm@google.coma6deb002008-09-08 23:11:13 +090065
66TEST(LazyInstanceTest, Basic) {
67 {
phajdan.jr@chromium.orge7f133a2009-11-19 18:11:39 +090068 base::ShadowingAtExitManager shadow;
deanm@google.coma6deb002008-09-08 23:11:13 +090069
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());
maruel@chromium.org8fe7adc2009-03-04 00:01:12 +090080 }
deanm@google.coma6deb002008-09-08 23:11:13 +090081 EXPECT_EQ(4, constructed_seq_.GetNext());
82 EXPECT_EQ(4, destructed_seq_.GetNext());
83}
84
scottmg7a1ef762017-03-08 17:48:46 +090085static base::LazyInstance<SlowConstructor>::DestructorAtExit lazy_slow =
joth@chromium.orgb24883c2011-11-15 22:31:49 +090086 LAZY_INSTANCE_INITIALIZER;
deanm@google.coma6deb002008-09-08 23:11:13 +090087
88TEST(LazyInstanceTest, ConstructorThreadSafety) {
89 {
phajdan.jr@chromium.orge7f133a2009-11-19 18:11:39 +090090 base::ShadowingAtExitManager shadow;
deanm@google.coma6deb002008-09-08 23:11:13 +090091
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}
evan@chromium.orga04f70c2010-10-22 05:41:47 +0900104
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;
scottmg7a1ef762017-03-08 17:48:46 +0900130 static base::LazyInstance<DeleteLogger>::DestructorAtExit test =
131 LAZY_INSTANCE_INITIALIZER;
evan@chromium.orga04f70c2010-10-22 05:41:47 +0900132 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;
fischman@chromium.org998561e2012-01-24 07:56:41 +0900141 static base::LazyInstance<DeleteLogger>::Leaky
joth@chromium.orgb24883c2011-11-15 22:31:49 +0900142 test = LAZY_INSTANCE_INITIALIZER;
evan@chromium.orga04f70c2010-10-22 05:41:47 +0900143 test.Get().SetDeletedPtr(&deleted2);
144 }
145 EXPECT_FALSE(deleted2);
146}
jbates@chromium.orgdde8e302012-02-24 02:52:20 +0900147
148namespace {
149
150template <size_t alignment>
151class AlignedData {
152 public:
153 AlignedData() {}
154 ~AlignedData() {}
brettwdd9392c2017-06-14 06:58:40 +0900155 alignas(alignment) char data_[alignment];
jbates@chromium.orgdde8e302012-02-24 02:52:20 +0900156};
157
brettwdd9392c2017-06-14 06:58:40 +0900158} // namespace
jbates@chromium.orgdde8e302012-02-24 02:52:20 +0900159
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.
scottmg7a1ef762017-03-08 17:48:46 +0900169 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;
jbates@chromium.orgdde8e302012-02-24 02:52:20 +0900175
176 EXPECT_ALIGNED(align4.Pointer(), 4);
177 EXPECT_ALIGNED(align32.Pointer(), 32);
178 EXPECT_ALIGNED(align4096.Pointer(), 4096);
179}