auto state = vault_.state_.rlock();
if (state->state == SingletonVault::SingletonVaultState::Quiescing) {
- if (vault_.type_ != SingletonVault::Type::Relaxed) {
- LOG(FATAL) << "Requesting singleton after vault was destroyed.";
- }
return;
}
auto state = state_.wlock();
stateCheck(SingletonVaultState::Running, *state);
+ if (state->registrationComplete) {
+ return;
+ }
+
auto singletons = singletons_.rlock();
if (type_ == Type::Strict) {
for (const auto& p : *singletons) {
if (p.second->hasLiveInstance()) {
throw std::runtime_error(
- "Singleton created before registration was complete.");
+ "Singleton " + p.first.name() +
+ " created before registration was complete.");
}
}
}
}
};
- explicit SingletonVault(Type type = Type::Relaxed) : type_(type) {}
+ explicit SingletonVault(Type type = Type::Strict) : type_(type) {}
// Destructor is only called by unit tests to check destroyInstances.
~SingletonVault();
folly::Synchronized<State> state_;
- Type type_{Type::Relaxed};
+ Type type_;
};
// This is the wrapper class that most users actually interact with.
using SingletonCreationError = Singleton<T, Tag, CreationErrorTag>;
TEST(Singleton, SingletonCreationError) {
- SingletonVault::singleton<CreationErrorTag>();
SingletonCreationError<ErrorConstructor> error_once_singleton;
+ SingletonVault::singleton<CreationErrorTag>()->registrationComplete();
// first time should error out
EXPECT_THROW(error_once_singleton.try_get(), std::runtime_error);
TEST(Singleton, SingletonConcurrencyStress) {
auto& vault = *SingletonVault::singleton<ConcurrencyStressTag>();
SingletonConcurrencyStress<Slowpoke> slowpoke_singleton;
+ vault.registrationComplete();
std::vector<std::thread> ts;
for (size_t i = 0; i < 100; ++i) {