summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorsiggi@chromium.org <siggi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-07 15:24:49 +0000
committersiggi@chromium.org <siggi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-07 15:24:49 +0000
commit297d0e5e3659a6d4a80906e4fc8e757ababae82d (patch)
tree08b75a511be120bf4b553965d161173e262bde6c /base
parentc90e135d0a9097774779813189f4bcea0f16ce91 (diff)
downloadchromium_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.cc36
-rw-r--r--base/singleton.h49
-rw-r--r--base/singleton_unittest.cc40
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();