Commit 4092256e authored by Andrii Grynenko's avatar Andrii Grynenko Committed by Facebook Github Bot

Make SingletonVault state use ReadPriority mutex

Summary: This fixes a deadlock possible when singleton chain is created concurrently with destroyInstances().

Reviewed By: lbrandy, yfeldblum

Differential Revision: D4329028

fbshipit-source-id: a11b3ff42d164ead2f8e3e77e0e17be43a8ad306
parent 6ed9b4c6
...@@ -507,7 +507,10 @@ class SingletonVault { ...@@ -507,7 +507,10 @@ class SingletonVault {
eagerInitSingletons_; eagerInitSingletons_;
folly::Synchronized<std::vector<detail::TypeDescriptor>> creationOrder_; folly::Synchronized<std::vector<detail::TypeDescriptor>> creationOrder_;
folly::Synchronized<State> state_; // Using SharedMutexReadPriority is important here, because we want to make
// sure we don't block nested singleton creation happening concurrently with
// destroyInstances().
folly::Synchronized<State, folly::SharedMutexReadPriority> state_;
Type type_; Type type_;
}; };
......
...@@ -641,3 +641,36 @@ TEST(Singleton, CustomCreator) { ...@@ -641,3 +641,36 @@ TEST(Singleton, CustomCreator) {
EXPECT_EQ(42, x2p->a1); EXPECT_EQ(42, x2p->a1);
EXPECT_EQ(std::string("foo"), x2p->a2); EXPECT_EQ(std::string("foo"), x2p->a2);
} }
struct ConcurrentCreationDestructionTag {};
template <typename T, typename Tag = detail::DefaultTag>
using SingletonConcurrentCreationDestruction =
Singleton<T, Tag, ConcurrentCreationDestructionTag>;
folly::Baton<> slowpokeNeedySingletonBaton;
struct SlowpokeNeedySingleton {
SlowpokeNeedySingleton() {
slowpokeNeedySingletonBaton.post();
/* sleep override */ std::this_thread::sleep_for(
std::chrono::milliseconds(100));
auto unused =
SingletonConcurrentCreationDestruction<NeededSingleton>::try_get();
EXPECT_NE(unused, nullptr);
}
};
TEST(Singleton, ConcurrentCreationDestruction) {
auto& vault = *SingletonVault::singleton<ConcurrentCreationDestructionTag>();
SingletonConcurrentCreationDestruction<NeededSingleton> neededSingleton;
SingletonConcurrentCreationDestruction<SlowpokeNeedySingleton> needySingleton;
vault.registrationComplete();
std::thread needyThread([&] { needySingleton.try_get(); });
slowpokeNeedySingletonBaton.wait();
vault.destroyInstances();
needyThread.join();
}
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