diff options
author | siggi@chromium.org <siggi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-07 15:24:49 +0000 |
---|---|---|
committer | siggi@chromium.org <siggi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-07 15:24:49 +0000 |
commit | 297d0e5e3659a6d4a80906e4fc8e757ababae82d (patch) | |
tree | 08b75a511be120bf4b553965d161173e262bde6c /base | |
parent | c90e135d0a9097774779813189f4bcea0f16ce91 (diff) | |
download | chromium_src-297d0e5e3659a6d4a80906e4fc8e757ababae82d.zip chromium_src-297d0e5e3659a6d4a80906e4fc8e757ababae82d.tar.gz chromium_src-297d0e5e3659a6d4a80906e4fc8e757ababae82d.tar.bz2 |
Add a StaticMemorySingletonTraits class to allow constructing singletons in data segment.
Change logging_win to use same.
BUG=none
TEST=Unittests in this change.
Review URL: http://codereview.chromium.org/2023003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46686 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/logging_win.cc | 36 | ||||
-rw-r--r-- | base/singleton.h | 49 | ||||
-rw-r--r-- | base/singleton_unittest.cc | 40 |
3 files changed, 91 insertions, 34 deletions
diff --git a/base/logging_win.cc b/base/logging_win.cc index d28ce91..2c2d6b0 100644 --- a/base/logging_win.cc +++ b/base/logging_win.cc @@ -9,39 +9,9 @@ namespace { -struct LogEventProviderTraits { - // WARNING: User has to deal with get() returning NULL. - static logging::LogEventProvider* New() { - if (base::subtle::NoBarrier_AtomicExchange(&dead_, 1)) - return NULL; - logging::LogEventProvider* ptr = - reinterpret_cast<logging::LogEventProvider*>(buffer_); - // We are protected by a memory barrier. - new(ptr) logging::LogEventProvider(); - return ptr; - } - - static void Delete(logging::LogEventProvider* p) { - base::subtle::NoBarrier_Store(&dead_, 1); - MemoryBarrier(); - p->logging::LogEventProvider::~LogEventProvider(); - } - - static const bool kRegisterAtExit = true; - - private: - static const size_t kBufferSize = (sizeof(logging::LogEventProvider) + - sizeof(intptr_t) - 1) / sizeof(intptr_t); - static intptr_t buffer_[kBufferSize]; - - // Signal the object was already deleted, so it is not revived. - static base::subtle::Atomic32 dead_; -}; - -intptr_t LogEventProviderTraits::buffer_[kBufferSize]; -base::subtle::Atomic32 LogEventProviderTraits::dead_ = 0; - -Singleton<logging::LogEventProvider, LogEventProviderTraits> log_provider; +typedef StaticMemorySingletonTraits<logging::LogEventProvider> + LogEventSingletonTraits; +Singleton<logging::LogEventProvider, LogEventSingletonTraits> log_provider; } // namespace diff --git a/base/singleton.h b/base/singleton.h index 3272fce..4532098 100644 --- a/base/singleton.h +++ b/base/singleton.h @@ -42,6 +42,53 @@ struct LeakySingletonTraits : public DefaultSingletonTraits<Type> { }; +// Alternate traits for use with the Singleton<Type>. Allocates memory +// for the singleton instance from a static buffer. The singleton will +// be cleaned up at exit, but can't be revived after destruction unless +// the Resurrect() method is called. +template <typename Type> +struct StaticMemorySingletonTraits { + // WARNING: User has to deal with get() in the singleton class + // this is traits for returning NULL. + static Type* New() { + if (base::subtle::NoBarrier_AtomicExchange(&dead_, 1)) + return NULL; + Type* ptr = reinterpret_cast<Type*>(buffer_); + + // We are protected by a memory barrier. + new(ptr) Type(); + return ptr; + } + + static void Delete(Type* p) { + base::subtle::NoBarrier_Store(&dead_, 1); + base::subtle::MemoryBarrier(); + if (p != NULL) + p->Type::~Type(); + } + + static const bool kRegisterAtExit = true; + + // Exposed for unittesting. + static void Resurrect() { + base::subtle::NoBarrier_Store(&dead_, 0); + } + + private: + static const size_t kBufferSize = (sizeof(Type) + + sizeof(intptr_t) - 1) / sizeof(intptr_t); + static intptr_t buffer_[kBufferSize]; + + // Signal the object was already deleted, so it is not revived. + static base::subtle::Atomic32 dead_; +}; + +template <typename Type> intptr_t + StaticMemorySingletonTraits<Type>::buffer_[kBufferSize]; +template <typename Type> base::subtle::Atomic32 + StaticMemorySingletonTraits<Type>::dead_ = 0; + + // The Singleton<Type, Traits, DifferentiatingType> class manages a single // instance of Type which will be created on first use and will be destroyed at // normal process exit). The Trait::Delete function will not be called on @@ -139,7 +186,7 @@ class Singleton { base::subtle::Release_Store( &instance_, reinterpret_cast<base::subtle::AtomicWord>(newval)); - if (Traits::kRegisterAtExit) + if (newval != NULL && Traits::kRegisterAtExit) base::AtExitManager::RegisterCallback(OnExit, NULL); return newval; diff --git a/base/singleton_unittest.cc b/base/singleton_unittest.cc index bb46bee..acb1247 100644 --- a/base/singleton_unittest.cc +++ b/base/singleton_unittest.cc @@ -32,6 +32,15 @@ struct CallbackTrait : public DefaultSingletonTraits<CallbackFunc> { } }; +struct StaticCallbackTrait : public StaticMemorySingletonTraits<CallbackFunc> { + static void Delete(CallbackFunc* p) { + if (*p) + (*p)(); + StaticMemorySingletonTraits<CallbackFunc>::Delete(p); + } +}; + + struct NoLeakTrait : public CallbackTrait { }; @@ -78,6 +87,14 @@ CallbackFunc* GetLeakySingleton() { return Singleton<CallbackFunc, LeakTrait>::get(); } +void SingletonStatic(CallbackFunc CallOnQuit) { + *Singleton<CallbackFunc, StaticCallbackTrait>::get() = CallOnQuit; +} + +CallbackFunc* GetStaticSingleton() { + return Singleton<CallbackFunc, StaticCallbackTrait>::get(); +} + } // namespace class SingletonTest : public testing::Test { @@ -87,21 +104,26 @@ class SingletonTest : public testing::Test { virtual void SetUp() { 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() { @@ -112,13 +134,19 @@ class SingletonTest : public testing::Test { 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_1; @@ -127,6 +155,7 @@ TEST_F(SingletonTest, Basic) { int* singleton_int_4; int* singleton_int_5; CallbackFunc* leaky_singleton; + CallbackFunc* static_singleton; { base::ShadowingAtExitManager sem; @@ -177,6 +206,8 @@ TEST_F(SingletonTest, Basic) { SingletonNoLeak(&CallbackNoLeak); SingletonLeak(&CallbackLeak); + SingletonStatic(&CallbackStatic); + static_singleton = GetStaticSingleton(); leaky_singleton = GetLeakySingleton(); EXPECT_TRUE(leaky_singleton); } @@ -187,6 +218,9 @@ TEST_F(SingletonTest, Basic) { // *not* detect the leak when this call is commented out. :( DefaultSingletonTraits<CallbackFunc>::Delete(leaky_singleton); + // The static singleton can't be acquired post-atexit. + EXPECT_EQ(NULL, GetStaticSingleton()); + { base::ShadowingAtExitManager sem; // Verifiy that the variables were reset. @@ -198,6 +232,12 @@ TEST_F(SingletonTest, Basic) { 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. + StaticMemorySingletonTraits<CallbackFunc>::Resurrect(); + EXPECT_EQ(GetStaticSingleton(), static_singleton); + } } // The leaky singleton shouldn't leak since SingletonLeak has not been called. VerifiesCallbacksNotCalled(); |