/*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <folly/RWSpinLock.h>
#include <folly/Demangle.h>
#include <folly/Executor.h>
-#include <folly/io/async/Request.h>
#include <folly/experimental/ReadMostlySharedPtr.h>
+#include <folly/detail/StaticSingletonManager.h>
#include <algorithm>
#include <atomic>
// SingletonHolders.
class SingletonHolderBase {
public:
+ explicit SingletonHolderBase(TypeDescriptor typeDesc) : type_(typeDesc) {}
virtual ~SingletonHolderBase() = default;
- virtual TypeDescriptor type() = 0;
+ TypeDescriptor type() const {
+ return type_;
+ }
virtual bool hasLiveInstance() = 0;
virtual void createInstance() = 0;
virtual bool creationStarted() = 0;
+ virtual void preDestroyInstance(ReadMostlyMainPtrDeleter<>&) = 0;
virtual void destroyInstance() = 0;
- protected:
- static constexpr std::chrono::seconds kDestroyWaitTime{5};
+ private:
+ TypeDescriptor type_;
};
// An actual instance of a singleton, tracking the instance itself,
void registerSingleton(CreateFunc c, TeardownFunc t);
void registerSingletonMock(CreateFunc c, TeardownFunc t);
- virtual TypeDescriptor type() override;
virtual bool hasLiveInstance() override;
virtual void createInstance() override;
virtual bool creationStarted() override;
+ virtual void preDestroyInstance(ReadMostlyMainPtrDeleter<>&) override;
virtual void destroyInstance() override;
private:
Living,
};
- TypeDescriptor type_;
SingletonVault& vault_;
// mutex protects the entire entry during construction/destruction
// holds a ReadMostlyMainPtr to singleton instance, set when state is changed
// from Dead to Living. Reset when state is changed from Living to Dead.
folly::ReadMostlyMainPtr<T> instance_;
+ // used to release all ReadMostlyMainPtrs at once
+ folly::ReadMostlySharedPtr<T> instance_copy_;
// weak_ptr to the singleton instance, set when state is changed from Dead
// to Living. We never write to this object after initialization, so it is
// safe to read it from different threads w/o synchronization if we know
// 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;
+ }
+
+ void setType(Type type) {
+ type_ = type;
}
private:
}
};
+template <typename T, typename Tag = detail::DefaultTag>
+class LeakySingleton {
+ public:
+ using CreateFunc = std::function<T*()>;
+
+ LeakySingleton() : LeakySingleton([] { return new T(); }) {}
+
+ explicit LeakySingleton(CreateFunc createFunc) {
+ auto& entry = entryInstance();
+ if (entry.state != State::NotRegistered) {
+ LOG(FATAL) << "Double registration of singletons of the same "
+ << "underlying type; check for multiple definitions "
+ << "of type folly::LeakySingleton<" + entry.type_.name() + ">";
+ }
+ entry.createFunc = createFunc;
+ entry.state = State::Dead;
+ }
+
+ static T& get() { return instance(); }
+
+ private:
+ enum class State { NotRegistered, Dead, Living };
+
+ struct Entry {
+ Entry() {}
+ Entry(const Entry&) = delete;
+ Entry& operator=(const Entry&) = delete;
+
+ std::atomic<State> state{State::NotRegistered};
+ T* ptr{nullptr};
+ CreateFunc createFunc;
+ std::mutex mutex;
+ detail::TypeDescriptor type_{typeid(T), typeid(Tag)};
+ };
+
+ static Entry& entryInstance() {
+ static auto entry = detail::createGlobal<Entry, Tag>();
+ return *entry;
+ }
+
+ static T& instance() {
+ auto& entry = entryInstance();
+ if (UNLIKELY(entry.state != State::Living)) {
+ createInstance();
+ }
+
+ return *entry.ptr;
+ }
+
+ static void createInstance() {
+ auto& entry = entryInstance();
+
+ std::lock_guard<std::mutex> lg(entry.mutex);
+ if (entry.state == State::Living) {
+ return;
+ }
+
+ if (entry.state == State::NotRegistered) {
+ auto ptr = SingletonVault::stackTraceGetter().load();
+ LOG(FATAL) << "Creating instance for unregistered singleton: "
+ << entry.type_.name() << "\n"
+ << "Stacktrace:"
+ << "\n" << (ptr ? (*ptr)() : "(not available)");
+ }
+
+ entry.ptr = entry.createFunc();
+ entry.state = State::Living;
+ }
+};
}
#include <folly/Singleton-inl.h>