blob: be2253f27f0c85f29cbb7527360eacc6dc12e613 [file] [log] [blame]
[email protected]44106182012-04-06 03:53:021// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
avi9beac252015-12-24 08:44:475#include <stdint.h>
6
[email protected]4ac8f672008-08-11 14:02:067#include "base/at_exit.h"
Lei Zhang25c9ff62020-06-19 02:30:438#include "base/memory/aligned_memory.h"
[email protected]3b63f8f42011-03-28 01:54:159#include "base/memory/singleton.h"
[email protected]4ac8f672008-08-11 14:02:0610#include "testing/gtest/include/gtest/gtest.h"
11
olli.raula36aa8be2015-09-10 11:14:2212namespace base {
[email protected]4ac8f672008-08-11 14:02:0613namespace {
14
avi4ec0dff2015-11-24 14:26:2415static_assert(DefaultSingletonTraits<int>::kRegisterAtExit == true,
16 "object must be deleted on process exit");
[email protected]4ac8f672008-08-11 14:02:0617
[email protected]4ac8f672008-08-11 14:02:0618typedef void (*CallbackFunc)();
19
brettw16289b3e2017-06-13 21:58:4020template <size_t alignment>
21class AlignedData {
22 public:
Chris Watkinsbb7211c2017-11-29 07:16:3823 AlignedData() = default;
24 ~AlignedData() = default;
brettw16289b3e2017-06-13 21:58:4025 alignas(alignment) char data_[alignment];
26};
27
[email protected]625332e02010-12-14 07:48:4928class IntSingleton {
29 public:
30 static IntSingleton* GetInstance() {
31 return Singleton<IntSingleton>::get();
32 }
33
34 int value_;
35};
36
37class Init5Singleton {
38 public:
39 struct Trait;
40
41 static Init5Singleton* GetInstance() {
42 return Singleton<Init5Singleton, Trait>::get();
43 }
44
45 int value_;
46};
47
48struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
49 static Init5Singleton* New() {
50 Init5Singleton* instance = new Init5Singleton();
51 instance->value_ = 5;
52 return instance;
[email protected]5820d2f02010-12-11 10:23:3753 }
54};
[email protected]49ab5562010-12-11 09:13:5455
[email protected]625332e02010-12-14 07:48:4956int* SingletonInt() {
57 return &IntSingleton::GetInstance()->value_;
[email protected]4ac8f672008-08-11 14:02:0658}
59
60int* SingletonInt5() {
[email protected]625332e02010-12-14 07:48:4961 return &Init5Singleton::GetInstance()->value_;
[email protected]4ac8f672008-08-11 14:02:0662}
63
[email protected]625332e02010-12-14 07:48:4964template <typename Type>
65struct CallbackTrait : public DefaultSingletonTraits<Type> {
66 static void Delete(Type* instance) {
67 if (instance->callback_)
68 (instance->callback_)();
69 DefaultSingletonTraits<Type>::Delete(instance);
70 }
71};
72
73class CallbackSingleton {
74 public:
Ivan Kotenkova16212a52017-11-08 12:37:3375 CallbackSingleton() : callback_(nullptr) {}
[email protected]625332e02010-12-14 07:48:4976 CallbackFunc callback_;
77};
78
79class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
80 public:
81 struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
82
83 CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
84
85 static CallbackSingletonWithNoLeakTrait* GetInstance() {
86 return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
87 }
88};
89
90class CallbackSingletonWithLeakTrait : public CallbackSingleton {
91 public:
92 struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
93 static const bool kRegisterAtExit = false;
94 };
95
96 CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
97
98 static CallbackSingletonWithLeakTrait* GetInstance() {
99 return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
100 }
101};
102
103class CallbackSingletonWithStaticTrait : public CallbackSingleton {
104 public:
105 struct Trait;
106
107 CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
108
109 static CallbackSingletonWithStaticTrait* GetInstance() {
110 return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
111 }
112};
113
114struct CallbackSingletonWithStaticTrait::Trait
115 : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
116 static void Delete(CallbackSingletonWithStaticTrait* instance) {
117 if (instance->callback_)
118 (instance->callback_)();
119 StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
120 instance);
121 }
122};
123
[email protected]cd924d62012-02-23 17:52:20124template <class Type>
125class AlignedTestSingleton {
126 public:
Chris Watkinsbb7211c2017-11-29 07:16:38127 AlignedTestSingleton() = default;
128 ~AlignedTestSingleton() = default;
[email protected]cd924d62012-02-23 17:52:20129 static AlignedTestSingleton* GetInstance() {
130 return Singleton<AlignedTestSingleton,
olli.raula36aa8be2015-09-10 11:14:22131 StaticMemorySingletonTraits<AlignedTestSingleton>>::get();
[email protected]cd924d62012-02-23 17:52:20132 }
133
134 Type type_;
135};
136
[email protected]625332e02010-12-14 07:48:49137
[email protected]4ac8f672008-08-11 14:02:06138void SingletonNoLeak(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49139 CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]4ac8f672008-08-11 14:02:06140}
141
142void SingletonLeak(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49143 CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]4ac8f672008-08-11 14:02:06144}
145
146CallbackFunc* GetLeakySingleton() {
[email protected]625332e02010-12-14 07:48:49147 return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
148}
149
150void DeleteLeakySingleton() {
151 DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
152 CallbackSingletonWithLeakTrait::GetInstance());
[email protected]4ac8f672008-08-11 14:02:06153}
154
[email protected]297d0e52010-05-07 15:24:49155void SingletonStatic(CallbackFunc CallOnQuit) {
[email protected]625332e02010-12-14 07:48:49156 CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
[email protected]297d0e52010-05-07 15:24:49157}
158
159CallbackFunc* GetStaticSingleton() {
Sergei Datsenkoca37cc62020-06-08 18:59:59160 CallbackSingletonWithStaticTrait* instance =
161 CallbackSingletonWithStaticTrait::GetInstance();
162 if (instance == nullptr) {
163 return nullptr;
164 } else {
165 return &instance->callback_;
166 }
[email protected]625332e02010-12-14 07:48:49167}
168
initial.commitd7cae122008-07-26 21:49:38169class SingletonTest : public testing::Test {
170 public:
Chris Watkinsbb7211c2017-11-29 07:16:38171 SingletonTest() = default;
initial.commitd7cae122008-07-26 21:49:38172
dcheng8aef37612014-12-23 02:56:47173 void SetUp() override {
initial.commitd7cae122008-07-26 21:49:38174 non_leak_called_ = false;
175 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49176 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38177 }
178
initial.commitd7cae122008-07-26 21:49:38179 protected:
initial.commitd7cae122008-07-26 21:49:38180 void VerifiesCallbacks() {
181 EXPECT_TRUE(non_leak_called_);
182 EXPECT_FALSE(leaky_called_);
[email protected]297d0e52010-05-07 15:24:49183 EXPECT_TRUE(static_called_);
initial.commitd7cae122008-07-26 21:49:38184 non_leak_called_ = false;
185 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49186 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38187 }
188
189 void VerifiesCallbacksNotCalled() {
190 EXPECT_FALSE(non_leak_called_);
191 EXPECT_FALSE(leaky_called_);
[email protected]297d0e52010-05-07 15:24:49192 EXPECT_FALSE(static_called_);
initial.commitd7cae122008-07-26 21:49:38193 non_leak_called_ = false;
194 leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49195 static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38196 }
197
[email protected]4ac8f672008-08-11 14:02:06198 static void CallbackNoLeak() {
initial.commitd7cae122008-07-26 21:49:38199 non_leak_called_ = true;
200 }
201
[email protected]4ac8f672008-08-11 14:02:06202 static void CallbackLeak() {
initial.commitd7cae122008-07-26 21:49:38203 leaky_called_ = true;
204 }
205
[email protected]297d0e52010-05-07 15:24:49206 static void CallbackStatic() {
207 static_called_ = true;
208 }
209
initial.commitd7cae122008-07-26 21:49:38210 private:
initial.commitd7cae122008-07-26 21:49:38211 static bool non_leak_called_;
212 static bool leaky_called_;
[email protected]297d0e52010-05-07 15:24:49213 static bool static_called_;
initial.commitd7cae122008-07-26 21:49:38214};
215
216bool SingletonTest::non_leak_called_ = false;
217bool SingletonTest::leaky_called_ = false;
[email protected]297d0e52010-05-07 15:24:49218bool SingletonTest::static_called_ = false;
initial.commitd7cae122008-07-26 21:49:38219
initial.commitd7cae122008-07-26 21:49:38220TEST_F(SingletonTest, Basic) {
[email protected]625332e02010-12-14 07:48:49221 int* singleton_int;
initial.commitd7cae122008-07-26 21:49:38222 int* singleton_int_5;
[email protected]4ac8f672008-08-11 14:02:06223 CallbackFunc* leaky_singleton;
[email protected]297d0e52010-05-07 15:24:49224 CallbackFunc* static_singleton;
initial.commitd7cae122008-07-26 21:49:38225
initial.commitd7cae122008-07-26 21:49:38226 {
olli.raula36aa8be2015-09-10 11:14:22227 ShadowingAtExitManager sem;
initial.commitd7cae122008-07-26 21:49:38228 {
[email protected]625332e02010-12-14 07:48:49229 singleton_int = SingletonInt();
initial.commitd7cae122008-07-26 21:49:38230 }
231 // Ensure POD type initialization.
[email protected]625332e02010-12-14 07:48:49232 EXPECT_EQ(*singleton_int, 0);
233 *singleton_int = 1;
initial.commitd7cae122008-07-26 21:49:38234
[email protected]625332e02010-12-14 07:48:49235 EXPECT_EQ(singleton_int, SingletonInt());
236 EXPECT_EQ(*singleton_int, 1);
initial.commitd7cae122008-07-26 21:49:38237
238 {
[email protected]4ac8f672008-08-11 14:02:06239 singleton_int_5 = SingletonInt5();
initial.commitd7cae122008-07-26 21:49:38240 }
241 // Is default initialized to 5.
242 EXPECT_EQ(*singleton_int_5, 5);
initial.commitd7cae122008-07-26 21:49:38243
[email protected]4ac8f672008-08-11 14:02:06244 SingletonNoLeak(&CallbackNoLeak);
245 SingletonLeak(&CallbackLeak);
[email protected]297d0e52010-05-07 15:24:49246 SingletonStatic(&CallbackStatic);
247 static_singleton = GetStaticSingleton();
[email protected]4ac8f672008-08-11 14:02:06248 leaky_singleton = GetLeakySingleton();
initial.commitd7cae122008-07-26 21:49:38249 EXPECT_TRUE(leaky_singleton);
250 }
initial.commitd7cae122008-07-26 21:49:38251
252 // Verify that only the expected callback has been called.
253 VerifiesCallbacks();
[email protected]64e95e12011-08-17 17:41:02254 // Delete the leaky singleton.
[email protected]625332e02010-12-14 07:48:49255 DeleteLeakySingleton();
initial.commitd7cae122008-07-26 21:49:38256
[email protected]297d0e52010-05-07 15:24:49257 // The static singleton can't be acquired post-atexit.
Ivan Kotenkova16212a52017-11-08 12:37:33258 EXPECT_EQ(nullptr, GetStaticSingleton());
[email protected]297d0e52010-05-07 15:24:49259
initial.commitd7cae122008-07-26 21:49:38260 {
olli.raula36aa8be2015-09-10 11:14:22261 ShadowingAtExitManager sem;
initial.commitd7cae122008-07-26 21:49:38262 // Verifiy that the variables were reset.
263 {
[email protected]625332e02010-12-14 07:48:49264 singleton_int = SingletonInt();
265 EXPECT_EQ(*singleton_int, 0);
initial.commitd7cae122008-07-26 21:49:38266 }
267 {
[email protected]4ac8f672008-08-11 14:02:06268 singleton_int_5 = SingletonInt5();
initial.commitd7cae122008-07-26 21:49:38269 EXPECT_EQ(*singleton_int_5, 5);
270 }
[email protected]297d0e52010-05-07 15:24:49271 {
272 // Resurrect the static singleton, and assert that it
273 // still points to the same (static) memory.
Gabriel Charettef297f012018-01-17 20:59:07274 CallbackSingletonWithStaticTrait::Trait::ResurrectForTesting();
[email protected]297d0e52010-05-07 15:24:49275 EXPECT_EQ(GetStaticSingleton(), static_singleton);
276 }
initial.commitd7cae122008-07-26 21:49:38277 }
278 // The leaky singleton shouldn't leak since SingletonLeak has not been called.
initial.commitd7cae122008-07-26 21:49:38279 VerifiesCallbacksNotCalled();
280}
[email protected]cd924d62012-02-23 17:52:20281
[email protected]cd924d62012-02-23 17:52:20282TEST_F(SingletonTest, Alignment) {
[email protected]cd924d62012-02-23 17:52:20283 // Create some static singletons with increasing sizes and alignment
284 // requirements. By ordering this way, the linker will need to do some work to
285 // ensure proper alignment of the static data.
avi9beac252015-12-24 08:44:47286 AlignedTestSingleton<int32_t>* align4 =
287 AlignedTestSingleton<int32_t>::GetInstance();
brettw16289b3e2017-06-13 21:58:40288 AlignedTestSingleton<AlignedData<32>>* align32 =
289 AlignedTestSingleton<AlignedData<32>>::GetInstance();
290 AlignedTestSingleton<AlignedData<128>>* align128 =
291 AlignedTestSingleton<AlignedData<128>>::GetInstance();
292 AlignedTestSingleton<AlignedData<4096>>* align4096 =
293 AlignedTestSingleton<AlignedData<4096>>::GetInstance();
[email protected]cd924d62012-02-23 17:52:20294
Lei Zhang25c9ff62020-06-19 02:30:43295 EXPECT_TRUE(IsAligned(align4, 4));
296 EXPECT_TRUE(IsAligned(align32, 32));
297 EXPECT_TRUE(IsAligned(align128, 128));
298 EXPECT_TRUE(IsAligned(align4096, 4096));
[email protected]cd924d62012-02-23 17:52:20299}
olli.raula36aa8be2015-09-10 11:14:22300
301} // namespace
302} // namespace base