19 #include <boost/thread/barrier.hpp> 20 #include <glog/logging.h> 35 using namespace
folly;
43 template <
typename T,
typename Tag = detail::DefaultTag>
50 auto& vault = *SingletonVault::singleton<BasicUsageTag>();
52 EXPECT_EQ(vault.registeredSingletonCount(), 0);
54 EXPECT_EQ(vault.registeredSingletonCount(), 1);
57 EXPECT_EQ(vault.registeredSingletonCount(), 2);
59 vault.registrationComplete();
72 std::shared_ptr<ChildWatchdog> s3 =
77 EXPECT_EQ(vault.registeredSingletonCount(), 2);
78 EXPECT_EQ(vault.livingSingletonCount(), 2);
81 vault.destroyInstances();
82 EXPECT_EQ(vault.registeredSingletonCount(), 2);
83 EXPECT_EQ(vault.livingSingletonCount(), 0);
87 template <
typename T,
typename Tag = detail::DefaultTag>
91 auto& vault = *SingletonVault::singleton<DirectUsageTag>();
93 EXPECT_EQ(vault.registeredSingletonCount(), 0);
100 EXPECT_EQ(vault.registeredSingletonCount(), 2);
101 vault.registrationComplete();
106 EXPECT_EQ(watchdog.try_get()->livingWatchdogCount(), 2);
108 vault.destroyInstances();
112 template <
typename T,
typename Tag = detail::DefaultTag>
116 auto& vault = *SingletonVault::singleton<NamedUsageTag>();
118 EXPECT_EQ(vault.registeredSingletonCount(), 0);
123 typedef detail::DefaultTag Watchdog3;
125 EXPECT_EQ(vault.registeredSingletonCount(), 1);
127 EXPECT_EQ(vault.registeredSingletonCount(), 2);
129 EXPECT_EQ(vault.registeredSingletonCount(), 3);
131 vault.registrationComplete();
137 EXPECT_EQ(s2, watchdog2_singleton.try_get());
140 EXPECT_EQ(s3, watchdog3_singleton.try_get());
147 EXPECT_EQ(s4, watchdog3_singleton.try_get());
150 vault.destroyInstances();
154 template <
typename T,
typename Tag = detail::DefaultTag>
157 template <
typename T,
typename Tag = detail::DefaultTag>
163 auto& vault = *SingletonVault::singleton<NaughtyUsageTag>();
165 vault.registrationComplete();
171 vault.destroyInstances();
173 auto& vault2 = *SingletonVault::singleton<NaughtyUsageTag2>();
180 vault2.destroyInstances();
187 template <
typename T,
typename Tag = detail::DefaultTag>
192 struct WatchdogHolder {
195 LOG(ERROR) <<
"The following log message with stack trace is expected";
199 std::shared_ptr<Watchdog> watchdog;
202 auto& vault = *SingletonVault::singleton<SharedPtrUsageTag>();
204 EXPECT_EQ(vault.registeredSingletonCount(), 0);
205 std::vector<std::unique_ptr<Watchdog>> watchdog_instances;
208 watchdog_instances.push_back(std::make_unique<Watchdog>());
209 return watchdog_instances.back().get();
215 watchdog_instances[1].reset();
217 EXPECT_EQ(vault.registeredSingletonCount(), 1);
220 EXPECT_EQ(vault.registeredSingletonCount(), 2);
227 vault.registrationComplete();
231 watchdog_holder_singleton.
try_get();
243 auto shared_s1 = weak_s1.lock();
247 auto old_serial = shared_s1->serial_number;
251 auto locked = named_weak_s1.lock();
252 EXPECT_NE(locked.get(), shared_s1.get());
259 LOG(ERROR) <<
"The following log message regarding shared_ptr is expected";
262 vault.destroyInstances();
265 duration > std::chrono::seconds{4} &&
268 EXPECT_EQ(vault.registeredSingletonCount(), 4);
269 EXPECT_EQ(vault.livingSingletonCount(), 0);
276 vault.reenableInstances();
283 EXPECT_NE(new_s1->serial_number, old_serial);
287 auto new_s1_shared = new_s1_weak.lock();
288 std::thread
t([new_s1_shared]()
mutable {
289 std::this_thread::sleep_for(std::chrono::seconds{2});
290 new_s1_shared.reset();
292 new_s1_shared.reset();
295 vault.destroyInstances();
298 duration > std::chrono::seconds{1} &&
299 duration < std::chrono::seconds{3});
309 template <
typename T,
typename Tag = detail::DefaultTag>
322 template <
typename T,
typename Tag = detail::DefaultTag>
335 auto& needy_vault = *SingletonVault::singleton<NeedyTag>();
337 needy_vault.registrationComplete();
339 EXPECT_EQ(needy_vault.registeredSingletonCount(), 2);
340 EXPECT_EQ(needy_vault.livingSingletonCount(), 0);
343 EXPECT_EQ(needy_vault.livingSingletonCount(), 2);
346 auto& self_needy_vault = *SingletonVault::singleton<SelfNeedyTag>();
348 self_needy_vault.registrationComplete();
359 std::this_thread::sleep_for(std::chrono::milliseconds(10));
364 template <
typename T,
typename Tag = detail::DefaultTag>
368 auto& vault = *SingletonVault::singleton<ConcurrencyTag>();
370 vault.registrationComplete();
374 auto func = [&gatekeeper]() {
380 EXPECT_EQ(vault.livingSingletonCount(), 0);
381 std::vector<std::thread>
threads;
382 for (
int i = 0;
i < 100; ++
i) {
383 threads.emplace_back(func);
389 for (
auto&
t : threads) {
392 EXPECT_EQ(vault.livingSingletonCount(), 1);
398 if ((constructCount_++) == 0) {
399 throw std::runtime_error(
"first time fails");
406 template <
typename T,
typename Tag = detail::DefaultTag>
411 SingletonVault::singleton<CreationErrorTag>()->registrationComplete();
417 error_once_singleton.
try_get();
422 template <
typename T,
typename Tag = detail::DefaultTag>
426 auto& vault = *SingletonVault::singleton<ConcurrencyStressTag>();
428 vault.registrationComplete();
430 std::vector<std::thread> ts;
431 for (
size_t i = 0;
i < 100; ++
i) {
432 ts.emplace_back([&]() { slowpoke_singleton.try_get(); });
435 for (
size_t i = 0;
i < 100; ++
i) {
436 std::chrono::milliseconds d(20);
438 std::this_thread::sleep_for(d);
439 vault.destroyInstances();
440 std::this_thread::sleep_for(d);
441 vault.destroyInstances();
450 struct EagerInitSyncTag {};
452 template <
typename T,
typename Tag = detail::DefaultTag>
455 auto& vault = *SingletonVault::singleton<EagerInitSyncTag>();
456 bool didEagerInit =
false;
462 vault.registrationComplete();
470 struct EagerInitAsyncTag {};
472 template <
typename T,
typename Tag = detail::DefaultTag>
475 auto& vault = *SingletonVault::singleton<EagerInitAsyncTag>();
476 bool didEagerInit =
false;
484 vault.registrationComplete();
486 vault.doEagerInitVia(eb, &done);
496 explicit TestEagerInitParallelExecutor(
const size_t threadCount) {
497 eventBases_.reserve(threadCount);
498 threads_.reserve(threadCount);
499 for (
size_t i = 0;
i < threadCount;
i++) {
500 eventBases_.push_back(std::make_shared<folly::EventBase>());
501 auto eb = eventBases_.back();
502 threads_.emplace_back(
503 std::make_shared<std::thread>([eb] { eb->loopForever(); }));
507 ~TestEagerInitParallelExecutor()
override {
508 for (
auto eb : eventBases_) {
509 eb->runInEventBaseThread([eb] { eb->terminateLoopSoon(); });
511 for (
auto thread : threads_) {
517 const auto index = (
counter_++) % eventBases_.size();
518 eventBases_[index]->add(
std::move(func));
522 std::vector<std::shared_ptr<folly::EventBase>> eventBases_;
523 std::vector<std::shared_ptr<std::thread>> threads_;
529 struct EagerInitParallelTag {};
531 template <
typename T,
typename Tag = detail::DefaultTag>
534 const static size_t kIters = 1000;
535 const static size_t kThreads = 20;
537 std::atomic<size_t> initCounter{0};
539 auto& vault = *SingletonVault::singleton<EagerInitParallelTag>();
547 for (
size_t i = 0;
i < kIters;
i++) {
550 vault.destroyInstances();
551 vault.reenableInstances();
554 initCounter.store(0);
557 std::vector<std::shared_ptr<std::thread>>
threads;
558 boost::barrier barrier(kThreads);
559 TestEagerInitParallelExecutor
exe(kThreads);
560 vault.registrationComplete();
564 for (
size_t j = 0; j < kThreads; j++) {
565 threads.push_back(std::make_shared<std::thread>([&] {
567 vault.doEagerInitVia(exe);
571 for (
auto thread : threads) {
583 template <
typename T,
typename Tag = detail::DefaultTag>
589 auto& vault = *SingletonVault::singleton<MockTag>();
592 vault.registrationComplete();
596 EXPECT_EQ(vault.registeredSingletonCount(), 1);
602 EXPECT_EQ(vault.registeredSingletonCount(), 1);
606 EXPECT_NE(serial_count_first, serial_count_mock);
611 EXPECT_EQ(vault.registeredSingletonCount(), 1);
615 EXPECT_NE(serial_count_first, serial_count_mock2);
616 EXPECT_NE(serial_count_mock, serial_count_mock2);
618 vault.destroyInstances();
624 const auto basename =
"singleton_double_registration";
627 std::vector<std::string>{
sub.string()},
633 auto err = p.communicate(
"").second;
635 EXPECT_EQ(ProcessReturnCode::KILLED, res.state());
643 X() :
X(-1,
"unset") {}
645 LOG(
INFO) <<
"X(" << a1 <<
"," << a2 <<
")";
664 template <
typename T,
typename Tag = detail::DefaultTag>
672 slowpokeNeedySingletonBaton.
post();
673 std::this_thread::sleep_for(
674 std::chrono::milliseconds(100));
682 auto& vault = *SingletonVault::singleton<ConcurrentCreationDestructionTag>();
685 vault.registrationComplete();
687 std::thread needyThread([&] { needySingleton.
try_get(); });
689 slowpokeNeedySingletonBaton.
wait();
691 vault.destroyInstances();
697 template <
typename T,
typename Tag = detail::DefaultTag>
703 initThread = std::this_thread::get_id();
707 destroyThread = std::this_thread::get_id();
717 auto& vault = *SingletonVault::singleton<MainThreadDestructorTag>();
720 vault.registrationComplete();
726 std::thread
t([instance = singleton.try_get()] {
727 std::this_thread::sleep_for(
728 std::chrono::milliseconds{100});
733 vault.destroyInstances();
748 struct PrivateTag {};
750 explicit Object(Counts& counts) : counts_(counts) {
762 auto& vault = *SingletonVault::singleton<VaultTag>();
763 auto new_object = [&] {
return new Object(counts); };
764 SingletonObject object_(new_object);
765 vault.registrationComplete();
772 SingletonObject::try_get();
777 SingletonObject::make_mock(new_object);
782 SingletonObject::make_mock(new_object);
static std::thread::id initThread
#define FOLLY_GNU_DISABLE_WARNING(warningName)
#define EXPECT_THROW(statement, expected_exception)
PolymorphicMatcher< internal::StartsWithMatcher< internal::string > > StartsWith(const internal::string &prefix)
static Singleton< ShutdownSocketSet, PrivateTag > singleton
static void make_mock(std::nullptr_t=nullptr, typename Singleton< T >::TeardownFunc t=nullptr)
Options & stdinFd(int action)
#define EXPECT_EQ(val1, val2)
std::chrono::steady_clock::time_point now()
constexpr detail::Map< Move > move
constexpr bool kIsSanitizeAddress
—— Concurrent Priority Queue Implementation ——
X(int a1_, std::string a2_)
std::vector< std::thread::id > threads
FOLLY_ALWAYS_INLINE void wait(const WaitOptions &opt=wait_options()) noexcept
TEST(Singleton, MissingSingleton)
folly::Singleton< X > singleton_x([](){return new X(42,"foo");})
Options & closeOtherFds()
static std::shared_ptr< T > try_get()
#define EXPECT_TRUE(condition)
~ThreadLoggingSingleton()
#define EXPECT_THAT(value, matcher)
folly::Baton slowpokeNeedySingletonBaton
#define EXPECT_NE(val1, val2)
static std::thread::id destroyThread
Options & stdoutFd(int action)
static folly::ReadMostlySharedPtr< T > try_get_fast()
folly::detail::CompressionCounter * counter_
#define EXPECT_FALSE(condition)
static std::weak_ptr< T > get_weak()
static size_t constructCount_