Commit f390a90d authored by Andrii Grynenko's avatar Andrii Grynenko Committed by facebook-github-bot-0

Fix folly::Singleton to work in dynamically linked binaries

Summary:This implements StaticSingletonManager which is then used to create all leaked Meyers singletons.

StaticSingletonManager is a singleton itself, which is created in a separate compilation unit (Singleton.cpp) and so we can be sure that other compilation units will always see a single instance of StaticSingletonManager, even if linked dynamically.

StaticSingletonManager then keeps a dictionary of typeid -> object pointer, which is used to de-duplicate same singleton being re-created from different compilation units (linked dynamically), usually because of code inlining.

override-unit-failures

Reviewed By: yfeldblum

Differential Revision: D2913027

fb-gh-sync-id: 1f5015a79a7a8297ebf5f0fe3fd0cc7eb44f706b
shipit-source-id: 1f5015a79a7a8297ebf5f0fe3fd0cc7eb44f706b
parent ac31e5f5
......@@ -21,9 +21,11 @@ namespace detail {
template <typename T>
template <typename Tag, typename VaultTag>
SingletonHolder<T>& SingletonHolder<T>::singleton() {
static auto entry = new SingletonHolder<T>(
{typeid(T), typeid(Tag)},
static auto entry =
createGlobal<SingletonHolder<T>, std::pair<Tag, VaultTag>>([]() {
return new SingletonHolder<T>({typeid(T), typeid(Tag)},
*SingletonVault::singleton<VaultTag>());
});
return *entry;
}
......
......@@ -25,6 +25,12 @@ namespace folly {
namespace detail {
// This implementation should always live in .cpp file.
StaticSingletonManager& StaticSingletonManager::instance() {
static StaticSingletonManager* instance = new StaticSingletonManager();
return *instance;
}
constexpr std::chrono::seconds SingletonHolderBase::kDestroyWaitTime;
}
......
......@@ -160,6 +160,47 @@ class SingletonVault;
namespace detail {
// This internal-use-only class is used to create all leaked Meyers singletons.
// It guarantees that only one instance of every such singleton will ever be
// created, even when requested from different compilation units linked
// dynamically.
class StaticSingletonManager {
public:
static StaticSingletonManager& instance();
template <typename T, typename Tag, typename F>
inline T* create(F&& creator) {
std::lock_guard<std::mutex> lg(mutex_);
auto& id = typeid(TypePair<T, Tag>);
auto& ptr = reinterpret_cast<T*&>(map_[id]);
if (!ptr) {
ptr = creator();
}
return ptr;
}
private:
template <typename A, typename B>
class TypePair {};
StaticSingletonManager() {}
std::unordered_map<std::type_index, intptr_t> map_;
std::mutex mutex_;
};
template <typename T, typename Tag, typename F>
inline T* createGlobal(F&& creator) {
return StaticSingletonManager::instance().create<T, Tag>(
std::forward<F>(creator));
}
template <typename T, typename Tag>
inline T* createGlobal() {
return createGlobal<T, Tag>([]() { return new T(); });
}
struct DefaultTag {};
// A TypeDescriptor is the unique handle for a given singleton. It is
......@@ -428,15 +469,18 @@ class SingletonVault {
// tests only.
template <typename VaultTag = detail::DefaultTag>
static SingletonVault* singleton() {
static SingletonVault* vault = new SingletonVault();
static SingletonVault* vault =
detail::createGlobal<SingletonVault, VaultTag>();
return vault;
}
typedef std::string(*StackTraceGetterPtr)();
static std::atomic<StackTraceGetterPtr>& stackTraceGetter() {
static std::atomic<StackTraceGetterPtr> stackTraceGetterPtr;
return stackTraceGetterPtr;
static std::atomic<StackTraceGetterPtr>* stackTraceGetterPtr =
detail::createGlobal<std::atomic<StackTraceGetterPtr>,
SingletonVault>();
return *stackTraceGetterPtr;
}
private:
......@@ -644,7 +688,7 @@ class LeakySingleton {
};
static Entry& entryInstance() {
static auto entry = new Entry();
static auto entry = detail::createGlobal<Entry, Tag>();
return *entry;
}
......
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