Commit ec8d84ff authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

A small inline fast path for StaticSingletonManager::create

Summary: [Folly] A small inline fast path for `StaticSingletonManager::create`.

Reviewed By: andriigrynenko

Differential Revision: D13114824

fbshipit-source-id: b72b6066b7ff5401e37e75aa1c8102e6536e9740
parent 592b2621
...@@ -27,9 +27,7 @@ SingletonHolder<T>& SingletonHolder<T>::singleton() { ...@@ -27,9 +27,7 @@ SingletonHolder<T>& SingletonHolder<T>::singleton() {
{typeid(T), typeid(Tag)}, {typeid(T), typeid(Tag)},
*SingletonVault::singleton<VaultTag>()) {} *SingletonVault::singleton<VaultTag>()) {}
}; };
/* library-local */ static auto entry = return *createGlobal<SingletonHolderImpl, void>();
createGlobal<SingletonHolderImpl, void>();
return *entry;
} }
[[noreturn]] void singletonWarnDoubleRegistrationAndAbort( [[noreturn]] void singletonWarnDoubleRegistrationAndAbort(
......
...@@ -500,17 +500,14 @@ class SingletonVault { ...@@ -500,17 +500,14 @@ class SingletonVault {
// tests only. // tests only.
template <typename VaultTag = detail::DefaultTag> template <typename VaultTag = detail::DefaultTag>
static SingletonVault* singleton() { static SingletonVault* singleton() {
/* library-local */ static auto vault = return detail::createGlobal<SingletonVault, VaultTag>();
detail::createGlobal<SingletonVault, VaultTag>();
return vault;
} }
typedef std::string (*StackTraceGetterPtr)(); typedef std::string (*StackTraceGetterPtr)();
static std::atomic<StackTraceGetterPtr>& stackTraceGetter() { static std::atomic<StackTraceGetterPtr>& stackTraceGetter() {
/* library-local */ static auto stackTraceGetterPtr = detail:: struct Result : std::atomic<StackTraceGetterPtr> {};
createGlobal<std::atomic<StackTraceGetterPtr>, SingletonVault>(); return *detail::createGlobal<Result, void>();
return *stackTraceGetterPtr;
} }
void setType(Type type) { void setType(Type type) {
...@@ -746,8 +743,7 @@ class LeakySingleton { ...@@ -746,8 +743,7 @@ class LeakySingleton {
}; };
static Entry& entryInstance() { static Entry& entryInstance() {
/* library-local */ static auto entry = detail::createGlobal<Entry, Tag>(); return *detail::createGlobal<Entry, Tag>();
return *entry;
} }
static T& instance() { static T& instance() {
......
...@@ -132,9 +132,8 @@ class SingletonThreadLocal { ...@@ -132,9 +132,8 @@ class SingletonThreadLocal {
SingletonThreadLocal() = delete; SingletonThreadLocal() = delete;
FOLLY_EXPORT FOLLY_NOINLINE static WrapperTL& getWrapperTL() { FOLLY_ALWAYS_INLINE static WrapperTL& getWrapperTL() {
static auto& entry = *detail::createGlobal<WrapperTL, Tag>(); return *detail::createGlobal<WrapperTL, Tag>();
return entry;
} }
FOLLY_NOINLINE static Wrapper& getWrapper() { FOLLY_NOINLINE static Wrapper& getWrapper() {
......
...@@ -27,16 +27,24 @@ namespace { ...@@ -27,16 +27,24 @@ namespace {
class StaticSingletonManagerImpl { class StaticSingletonManagerImpl {
public: public:
void* create(std::type_info const& key, void* (*make)()) { using Make = void*();
auto& e = entry(key); using Cache = std::atomic<void*>;
std::lock_guard<std::mutex> lock(e.mutex);
return e.ptr ? e.ptr : (e.ptr = make()); void* create(std::type_info const& key, Make& make, Cache& cache) {
auto const ptr = entry(key).get(make);
cache.store(ptr, std::memory_order_release);
return ptr;
} }
private: private:
struct Entry { struct Entry {
void* ptr{}; void* ptr{};
std::mutex mutex; std::mutex mutex;
void* get(Make& make) {
std::lock_guard<std::mutex> lock(mutex);
return ptr ? ptr : (ptr = make());
}
}; };
Entry& entry(std::type_info const& key) { Entry& entry(std::type_info const& key) {
...@@ -51,10 +59,13 @@ class StaticSingletonManagerImpl { ...@@ -51,10 +59,13 @@ class StaticSingletonManagerImpl {
} // namespace } // namespace
void* StaticSingletonManager::create_(Key const& key, Make* make) { void* StaticSingletonManager::create_(
Key const& key,
Make& make,
Cache& cache) {
// This Leaky Meyers Singleton must always live in the .cpp file. // This Leaky Meyers Singleton must always live in the .cpp file.
static auto& instance = *new StaticSingletonManagerImpl(); static auto& instance = *new StaticSingletonManagerImpl();
return instance.create(key, make); return instance.create(key, make, cache);
} }
} // namespace detail } // namespace detail
......
...@@ -16,9 +16,11 @@ ...@@ -16,9 +16,11 @@
#pragma once #pragma once
#include <atomic>
#include <typeinfo> #include <typeinfo>
#include <folly/CPortability.h> #include <folly/CPortability.h>
#include <folly/Likely.h>
namespace folly { namespace folly {
namespace detail { namespace detail {
...@@ -30,9 +32,12 @@ namespace detail { ...@@ -30,9 +32,12 @@ namespace detail {
class StaticSingletonManager { class StaticSingletonManager {
public: public:
template <typename T, typename Tag> template <typename T, typename Tag>
FOLLY_ALWAYS_INLINE FOLLY_ATTR_VISIBILITY_HIDDEN static T* create() { FOLLY_EXPORT FOLLY_ALWAYS_INLINE static T* create() {
static Cache cache;
auto const& key = typeid(TypePair<T, Tag>); auto const& key = typeid(TypePair<T, Tag>);
return static_cast<T*>(create_(key, &Creator<T>::create)); auto const v = cache.load(std::memory_order_acquire);
auto const p = FOLLY_LIKELY(!!v) ? v : create_(key, make<T>, cache);
return static_cast<T*>(p);
} }
private: private:
...@@ -41,15 +46,14 @@ class StaticSingletonManager { ...@@ -41,15 +46,14 @@ class StaticSingletonManager {
using Key = std::type_info; using Key = std::type_info;
using Make = void*(); using Make = void*();
using Cache = std::atomic<void*>;
template <typename T> template <typename T>
struct Creator { static void* make() {
static void* create() { return new T();
return new T(); }
}
};
FOLLY_NOINLINE static void* create_(Key const& key, Make* make); FOLLY_NOINLINE static void* create_(Key const& key, Make& make, Cache& cache);
}; };
template <typename T, typename Tag> template <typename T, typename Tag>
......
...@@ -93,7 +93,7 @@ ThreadEntryList* StaticMetaBase::getThreadEntryList() { ...@@ -93,7 +93,7 @@ ThreadEntryList* StaticMetaBase::getThreadEntryList() {
pthread_key_t pthreadKey_; pthread_key_t pthreadKey_;
}; };
static auto instance = detail::createGlobal<PthreadKey, void>(); auto instance = detail::createGlobal<PthreadKey, void>();
ThreadEntryList* threadEntryList = ThreadEntryList* threadEntryList =
static_cast<ThreadEntryList*>(pthread_getspecific(instance->get())); static_cast<ThreadEntryList*>(pthread_getspecific(instance->get()));
......
...@@ -428,9 +428,7 @@ struct StaticMeta final : StaticMetaBase { ...@@ -428,9 +428,7 @@ struct StaticMeta final : StaticMetaBase {
static StaticMeta<Tag, AccessMode>& instance() { static StaticMeta<Tag, AccessMode>& instance() {
// Leak it on exit, there's only one per process and we don't have to // Leak it on exit, there's only one per process and we don't have to
// worry about synchronization with exiting threads. // worry about synchronization with exiting threads.
/* library-local */ static auto instance = return *detail::createGlobal<StaticMeta<Tag, AccessMode>, void>();
detail::createGlobal<StaticMeta<Tag, AccessMode>, void>();
return *instance;
} }
FOLLY_EXPORT FOLLY_ALWAYS_INLINE static ElementWrapper& get(EntryID* ent) { FOLLY_EXPORT FOLLY_ALWAYS_INLINE static ElementWrapper& get(EntryID* ent) {
......
...@@ -21,6 +21,10 @@ ...@@ -21,6 +21,10 @@
namespace folly { namespace folly {
namespace detail { namespace detail {
extern "C" int* check() {
return createGlobal<int, void>();
}
struct StaticSingletonManagerTest : public testing::Test {}; struct StaticSingletonManagerTest : public testing::Test {};
template <typename T> template <typename T>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment