SingletonVault::~SingletonVault() { destroyInstances(); }
void SingletonVault::registerSingleton(detail::SingletonHolderBase* entry) {
- RWSpinLock::ReadHolder rh(&stateMutex_);
+ auto state = state_.rlock();
+ stateCheck(SingletonVaultState::Running, *state);
- stateCheck(SingletonVaultState::Running);
-
- if (UNLIKELY(registrationComplete_)) {
+ if (UNLIKELY(state->registrationComplete)) {
LOG(ERROR) << "Registering singleton after registrationComplete().";
}
- RWSpinLock::ReadHolder rhMutex(&mutex_);
- CHECK_THROW(singletons_.find(entry->type()) == singletons_.end(),
- std::logic_error);
-
- RWSpinLock::UpgradedHolder wh(&mutex_);
- singletons_[entry->type()] = entry;
+ auto singletons = singletons_.wlock();
+ CHECK_THROW(
+ singletons->emplace(entry->type(), entry).second, std::logic_error);
}
void SingletonVault::addEagerInitSingleton(detail::SingletonHolderBase* entry) {
- RWSpinLock::ReadHolder rh(&stateMutex_);
-
- stateCheck(SingletonVaultState::Running);
+ auto state = state_.rlock();
+ stateCheck(SingletonVaultState::Running, *state);
- if (UNLIKELY(registrationComplete_)) {
+ if (UNLIKELY(state->registrationComplete)) {
LOG(ERROR) << "Registering for eager-load after registrationComplete().";
}
- RWSpinLock::ReadHolder rhMutex(&mutex_);
- CHECK_THROW(singletons_.find(entry->type()) != singletons_.end(),
- std::logic_error);
+ CHECK_THROW(singletons_.rlock()->count(entry->type()), std::logic_error);
- RWSpinLock::UpgradedHolder wh(&mutex_);
- eagerInitSingletons_.insert(entry);
+ auto eagerInitSingletons = eagerInitSingletons_.wlock();
+ eagerInitSingletons->insert(entry);
}
void SingletonVault::registrationComplete() {
std::atexit([](){ SingletonVault::singleton()->destroyInstances(); });
- RWSpinLock::WriteHolder wh(&stateMutex_);
-
- stateCheck(SingletonVaultState::Running);
+ auto state = state_.wlock();
+ stateCheck(SingletonVaultState::Running, *state);
+ auto singletons = singletons_.rlock();
if (type_ == Type::Strict) {
- for (const auto& p : singletons_) {
+ for (const auto& p : *singletons) {
if (p.second->hasLiveInstance()) {
throw std::runtime_error(
"Singleton created before registration was complete.");
}
}
- registrationComplete_ = true;
+ state->registrationComplete = true;
}
void SingletonVault::doEagerInit() {
- std::unordered_set<detail::SingletonHolderBase*> singletonSet;
{
- RWSpinLock::ReadHolder rh(&stateMutex_);
- stateCheck(SingletonVaultState::Running);
- if (UNLIKELY(!registrationComplete_)) {
+ auto state = state_.rlock();
+ stateCheck(SingletonVaultState::Running, *state);
+ if (UNLIKELY(!state->registrationComplete)) {
throw std::logic_error("registrationComplete() not yet called");
}
- singletonSet = eagerInitSingletons_; // copy set of pointers
}
- for (auto *single : singletonSet) {
+ auto eagerInitSingletons = eagerInitSingletons_.rlock();
+ for (auto* single : *eagerInitSingletons) {
single->createInstance();
}
}
void SingletonVault::doEagerInitVia(Executor& exe, folly::Baton<>* done) {
- std::unordered_set<detail::SingletonHolderBase*> singletonSet;
{
- RWSpinLock::ReadHolder rh(&stateMutex_);
- stateCheck(SingletonVaultState::Running);
- if (UNLIKELY(!registrationComplete_)) {
+ auto state = state_.rlock();
+ stateCheck(SingletonVaultState::Running, *state);
+ if (UNLIKELY(!state->registrationComplete)) {
throw std::logic_error("registrationComplete() not yet called");
}
- singletonSet = eagerInitSingletons_; // copy set of pointers
}
- auto countdown = std::make_shared<std::atomic<size_t>>(singletonSet.size());
- for (auto* single : singletonSet) {
+ auto eagerInitSingletons = eagerInitSingletons_.rlock();
+ auto countdown =
+ std::make_shared<std::atomic<size_t>>(eagerInitSingletons->size());
+ for (auto* single : *eagerInitSingletons) {
// countdown is retained by shared_ptr, and will be alive until last lambda
// is done. notifyBaton is provided by the caller, and expected to remain
// present (if it's non-nullptr). singletonSet can go out of scope but
}
void SingletonVault::destroyInstances() {
- RWSpinLock::WriteHolder state_wh(&stateMutex_);
-
- if (state_ == SingletonVaultState::Quiescing) {
+ auto stateW = state_.wlock();
+ if (stateW->state == SingletonVaultState::Quiescing) {
return;
}
- state_ = SingletonVaultState::Quiescing;
-
- RWSpinLock::ReadHolder state_rh(std::move(state_wh));
+ stateW->state = SingletonVaultState::Quiescing;
+ auto stateR = stateW.moveFromWriteToRead();
{
- RWSpinLock::ReadHolder rh(&mutex_);
+ auto singletons = singletons_.rlock();
+ auto creationOrder = creationOrder_.rlock();
- CHECK_GE(singletons_.size(), creation_order_.size());
+ CHECK_GE(singletons->size(), creationOrder->size());
// Release all ReadMostlyMainPtrs at once
{
ReadMostlyMainPtrDeleter<> deleter;
- for (auto& singleton_type : creation_order_) {
- singletons_[singleton_type]->preDestroyInstance(deleter);
+ for (auto& singleton_type : *creationOrder) {
+ singletons->at(singleton_type)->preDestroyInstance(deleter);
}
}
- for (auto type_iter = creation_order_.rbegin();
- type_iter != creation_order_.rend();
+ for (auto type_iter = creationOrder->rbegin();
+ type_iter != creationOrder->rend();
++type_iter) {
- singletons_[*type_iter]->destroyInstance();
+ singletons->at(*type_iter)->destroyInstance();
}
- for (auto& singleton_type: creation_order_) {
- auto singleton = singletons_[singleton_type];
+ for (auto& singleton_type : *creationOrder) {
+ auto singleton = singletons->at(singleton_type);
if (!singleton->hasLiveInstance()) {
continue;
}
}
{
- RWSpinLock::WriteHolder wh(&mutex_);
- creation_order_.clear();
+ auto creationOrder = creationOrder_.wlock();
+ creationOrder->clear();
}
}
void SingletonVault::reenableInstances() {
- RWSpinLock::WriteHolder state_wh(&stateMutex_);
+ auto state = state_.wlock();
- stateCheck(SingletonVaultState::Quiescing);
+ stateCheck(SingletonVaultState::Quiescing, *state);
- state_ = SingletonVaultState::Running;
+ state->state = SingletonVaultState::Running;
}
void SingletonVault::scheduleDestroyInstances() {
#pragma once
#include <folly/Baton.h>
+#include <folly/Demangle.h>
#include <folly/Exception.h>
+#include <folly/Executor.h>
#include <folly/Hash.h>
#include <folly/Memory.h>
#include <folly/RWSpinLock.h>
-#include <folly/Demangle.h>
-#include <folly/Executor.h>
-#include <folly/experimental/ReadMostlySharedPtr.h>
+#include <folly/Synchronized.h>
#include <folly/detail/StaticSingletonManager.h>
+#include <folly/experimental/ReadMostlySharedPtr.h>
#include <algorithm>
#include <atomic>
// For testing; how many registered and living singletons we have.
size_t registeredSingletonCount() const {
- RWSpinLock::ReadHolder rh(&mutex_);
-
- return singletons_.size();
+ return singletons_.rlock()->size();
}
/**
bool eagerInitComplete() const;
size_t livingSingletonCount() const {
- RWSpinLock::ReadHolder rh(&mutex_);
+ auto singletons = singletons_.rlock();
size_t ret = 0;
- for (const auto& p : singletons_) {
+ for (const auto& p : *singletons) {
if (p.second->hasLiveInstance()) {
++ret;
}
Quiescing,
};
+ struct State {
+ SingletonVaultState state{SingletonVaultState::Running};
+ bool registrationComplete{false};
+ };
+
// Each singleton in the vault can be in two states: dead
// (registered but never created), living (CreateFunc returned an instance).
- void stateCheck(SingletonVaultState expected,
- const char* msg="Unexpected singleton state change") {
- if (expected != state_) {
- throw std::logic_error(msg);
+ static void stateCheck(
+ SingletonVaultState expected,
+ const State& state,
+ const char* msg = "Unexpected singleton state change") {
+ if (expected != state.state) {
+ throw std::logic_error(msg);
}
}
typedef std::unordered_map<detail::TypeDescriptor,
detail::SingletonHolderBase*,
detail::TypeDescriptorHasher> SingletonMap;
+ folly::Synchronized<SingletonMap> singletons_;
+ folly::Synchronized<std::unordered_set<detail::SingletonHolderBase*>>
+ eagerInitSingletons_;
+ folly::Synchronized<std::vector<detail::TypeDescriptor>> creationOrder_;
+
+ folly::Synchronized<State> state_;
- mutable folly::RWSpinLock mutex_;
- SingletonMap singletons_;
- std::unordered_set<detail::SingletonHolderBase*> eagerInitSingletons_;
- std::vector<detail::TypeDescriptor> creation_order_;
- SingletonVaultState state_{SingletonVaultState::Running};
- bool registrationComplete_{false};
- folly::RWSpinLock stateMutex_;
Type type_{Type::Relaxed};
};