123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include <stdint.h>
- #include "base/at_exit.h"
- #include "base/memory/aligned_memory.h"
- #include "base/memory/singleton.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace base {
- namespace {
- static_assert(DefaultSingletonTraits<int>::kRegisterAtExit == true,
- "object must be deleted on process exit");
- typedef void (*CallbackFunc)();
- template <size_t alignment>
- class AlignedData {
- public:
- AlignedData() = default;
- ~AlignedData() = default;
- alignas(alignment) char data_[alignment];
- };
- class IntSingleton {
- public:
- static IntSingleton* GetInstance() {
- return Singleton<IntSingleton>::get();
- }
- int value_;
- };
- class Init5Singleton {
- public:
- struct Trait;
- static Init5Singleton* GetInstance() {
- return Singleton<Init5Singleton, Trait>::get();
- }
- int value_;
- };
- struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
- static Init5Singleton* New() {
- Init5Singleton* instance = new Init5Singleton();
- instance->value_ = 5;
- return instance;
- }
- };
- int* SingletonInt() {
- return &IntSingleton::GetInstance()->value_;
- }
- int* SingletonInt5() {
- return &Init5Singleton::GetInstance()->value_;
- }
- template <typename Type>
- struct CallbackTrait : public DefaultSingletonTraits<Type> {
- static void Delete(Type* instance) {
- if (instance->callback_)
- (instance->callback_)();
- DefaultSingletonTraits<Type>::Delete(instance);
- }
- };
- class CallbackSingleton {
- public:
- CallbackSingleton() : callback_(nullptr) {}
- CallbackFunc callback_;
- };
- class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
- public:
- struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
- CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
- static CallbackSingletonWithNoLeakTrait* GetInstance() {
- return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
- }
- };
- class CallbackSingletonWithLeakTrait : public CallbackSingleton {
- public:
- struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
- static const bool kRegisterAtExit = false;
- };
- CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
- static CallbackSingletonWithLeakTrait* GetInstance() {
- return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
- }
- };
- class CallbackSingletonWithStaticTrait : public CallbackSingleton {
- public:
- struct Trait;
- CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
- static CallbackSingletonWithStaticTrait* GetInstance() {
- return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
- }
- };
- struct CallbackSingletonWithStaticTrait::Trait
- : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
- static void Delete(CallbackSingletonWithStaticTrait* instance) {
- if (instance->callback_)
- (instance->callback_)();
- StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
- instance);
- }
- };
- template <class Type>
- class AlignedTestSingleton {
- public:
- AlignedTestSingleton() = default;
- ~AlignedTestSingleton() = default;
- static AlignedTestSingleton* GetInstance() {
- return Singleton<AlignedTestSingleton,
- StaticMemorySingletonTraits<AlignedTestSingleton>>::get();
- }
- Type type_;
- };
- void SingletonNoLeak(CallbackFunc CallOnQuit) {
- CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
- }
- void SingletonLeak(CallbackFunc CallOnQuit) {
- CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
- }
- CallbackFunc* GetLeakySingleton() {
- return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
- }
- void DeleteLeakySingleton() {
- DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
- CallbackSingletonWithLeakTrait::GetInstance());
- }
- void SingletonStatic(CallbackFunc CallOnQuit) {
- CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
- }
- CallbackFunc* GetStaticSingleton() {
- CallbackSingletonWithStaticTrait* instance =
- CallbackSingletonWithStaticTrait::GetInstance();
- if (instance == nullptr) {
- return nullptr;
- } else {
- return &instance->callback_;
- }
- }
- class SingletonTest : public testing::Test {
- public:
- SingletonTest() = default;
- void SetUp() override {
- non_leak_called_ = false;
- leaky_called_ = false;
- static_called_ = false;
- }
- protected:
- void VerifiesCallbacks() {
- EXPECT_TRUE(non_leak_called_);
- EXPECT_FALSE(leaky_called_);
- EXPECT_TRUE(static_called_);
- non_leak_called_ = false;
- leaky_called_ = false;
- static_called_ = false;
- }
- void VerifiesCallbacksNotCalled() {
- EXPECT_FALSE(non_leak_called_);
- EXPECT_FALSE(leaky_called_);
- EXPECT_FALSE(static_called_);
- non_leak_called_ = false;
- leaky_called_ = false;
- static_called_ = false;
- }
- static void CallbackNoLeak() {
- non_leak_called_ = true;
- }
- static void CallbackLeak() {
- leaky_called_ = true;
- }
- static void CallbackStatic() {
- static_called_ = true;
- }
- private:
- static bool non_leak_called_;
- static bool leaky_called_;
- static bool static_called_;
- };
- bool SingletonTest::non_leak_called_ = false;
- bool SingletonTest::leaky_called_ = false;
- bool SingletonTest::static_called_ = false;
- TEST_F(SingletonTest, Basic) {
- int* singleton_int;
- int* singleton_int_5;
- CallbackFunc* leaky_singleton;
- CallbackFunc* static_singleton;
- {
- ShadowingAtExitManager sem;
- {
- singleton_int = SingletonInt();
- }
- // Ensure POD type initialization.
- EXPECT_EQ(*singleton_int, 0);
- *singleton_int = 1;
- EXPECT_EQ(singleton_int, SingletonInt());
- EXPECT_EQ(*singleton_int, 1);
- {
- singleton_int_5 = SingletonInt5();
- }
- // Is default initialized to 5.
- EXPECT_EQ(*singleton_int_5, 5);
- SingletonNoLeak(&CallbackNoLeak);
- SingletonLeak(&CallbackLeak);
- SingletonStatic(&CallbackStatic);
- static_singleton = GetStaticSingleton();
- leaky_singleton = GetLeakySingleton();
- EXPECT_TRUE(leaky_singleton);
- }
- // Verify that only the expected callback has been called.
- VerifiesCallbacks();
- // Delete the leaky singleton.
- DeleteLeakySingleton();
- // The static singleton can't be acquired post-atexit.
- EXPECT_EQ(nullptr, GetStaticSingleton());
- {
- ShadowingAtExitManager sem;
- // Verifiy that the variables were reset.
- {
- singleton_int = SingletonInt();
- EXPECT_EQ(*singleton_int, 0);
- }
- {
- singleton_int_5 = SingletonInt5();
- EXPECT_EQ(*singleton_int_5, 5);
- }
- {
- // Resurrect the static singleton, and assert that it
- // still points to the same (static) memory.
- CallbackSingletonWithStaticTrait::Trait::ResurrectForTesting();
- EXPECT_EQ(GetStaticSingleton(), static_singleton);
- }
- }
- // The leaky singleton shouldn't leak since SingletonLeak has not been called.
- VerifiesCallbacksNotCalled();
- }
- TEST_F(SingletonTest, Alignment) {
- // Create some static singletons with increasing sizes and alignment
- // requirements. By ordering this way, the linker will need to do some work to
- // ensure proper alignment of the static data.
- AlignedTestSingleton<int32_t>* align4 =
- AlignedTestSingleton<int32_t>::GetInstance();
- AlignedTestSingleton<AlignedData<32>>* align32 =
- AlignedTestSingleton<AlignedData<32>>::GetInstance();
- AlignedTestSingleton<AlignedData<128>>* align128 =
- AlignedTestSingleton<AlignedData<128>>::GetInstance();
- AlignedTestSingleton<AlignedData<4096>>* align4096 =
- AlignedTestSingleton<AlignedData<4096>>::GetInstance();
- EXPECT_TRUE(IsAligned(align4, 4));
- EXPECT_TRUE(IsAligned(align32, 32));
- EXPECT_TRUE(IsAligned(align128, 128));
- EXPECT_TRUE(IsAligned(align4096, 4096));
- }
- } // namespace
- } // namespace base
|