X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=blobdiff_plain;f=folly%2FSingleton.cpp;h=7d3eeac61cf377d8cce358251c227c48ddfd2e7d;hp=52f3957f03719fd6a6fc38c6f7fbd92670cd0d06;hb=1672380910a8c21cd36095661eb1360f43c93332;hpb=f54fbf88038aacc4bcc0f3bf98995375fddcde78 diff --git a/folly/Singleton.cpp b/folly/Singleton.cpp index 52f3957f..7d3eeac6 100644 --- a/folly/Singleton.cpp +++ b/folly/Singleton.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2015 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,50 @@ #include +#ifndef _WIN32 +#include +#endif + +#include +#include +#include +#include #include +#include + +#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__ANDROID__) +static void hs_init_weak(int* argc, char** argv[]) + __attribute__((__weakref__("hs_init"))); +#endif + namespace folly { -namespace detail { +SingletonVault::Type SingletonVault::defaultVaultType() { +#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__ANDROID__) + bool isPython = dlsym(RTLD_DEFAULT, "Py_Main"); + bool isHaskel = &::hs_init_weak || dlsym(RTLD_DEFAULT, "hs_init"); + bool isJVM = dlsym(RTLD_DEFAULT, "JNI_GetCreatedJavaVMs"); + bool isD = dlsym(RTLD_DEFAULT, "_d_run_main"); -constexpr std::chrono::seconds SingletonHolderBase::kDestroyWaitTime; + return isPython || isHaskel || isJVM || isD ? Type::Relaxed : Type::Strict; +#else + return Type::Relaxed; +#endif +} + +namespace detail { +[[noreturn]] void singletonWarnDoubleRegistrationAndAbort( + const TypeDescriptor& type) { + // Ensure the availability of std::cerr + std::ios_base::Init ioInit; + std::cerr << "Double registration of singletons of the same " + "underlying type; check for multiple definitions " + "of type folly::Singleton<" + << type.name() << ">\n"; + std::abort(); +} } namespace { @@ -57,90 +93,101 @@ FatalHelper __attribute__ ((__init_priority__ (101))) fatalHelper; SingletonVault::~SingletonVault() { destroyInstances(); } void SingletonVault::registerSingleton(detail::SingletonHolderBase* entry) { - RWSpinLock::ReadHolder rh(&stateMutex_); - - stateCheck(SingletonVaultState::Running); + auto state = state_.rlock(); + stateCheck(SingletonVaultState::Running, *state); - if (UNLIKELY(registrationComplete_)) { - throw std::logic_error( - "Registering singleton after 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_); + auto state = state_.rlock(); + stateCheck(SingletonVaultState::Running, *state); - stateCheck(SingletonVaultState::Running); - - if (UNLIKELY(registrationComplete_)) { - throw std::logic_error( - "Registering for eager-load after 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() { - RequestContext::saveContext(); std::atexit([](){ SingletonVault::singleton()->destroyInstances(); }); - RWSpinLock::WriteHolder wh(&stateMutex_); + auto state = state_.wlock(); + stateCheck(SingletonVaultState::Running, *state); - stateCheck(SingletonVaultState::Running); + if (state->registrationComplete) { + return; + } + 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."); + "Singleton " + p.first.name() + + " created before registration was complete."); } } } - registrationComplete_ = true; + state->registrationComplete = true; } void SingletonVault::doEagerInit() { - std::unordered_set 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) { - std::unordered_set singletonSet; +void SingletonVault::doEagerInitVia(Executor& exe, folly::Baton<>* done) { { - 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) { - exe->add([single] { + auto eagerInitSingletons = eagerInitSingletons_.rlock(); + auto countdown = + std::make_shared>(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 + // its values, which are SingletonHolderBase pointers, are alive as long as + // SingletonVault is not being destroyed. + exe.add([=] { + // decrement counter and notify if requested, whether initialization + // was successful, was skipped (already initialized), or exception thrown. + SCOPE_EXIT { + if (--(*countdown) == 0) { + if (done != nullptr) { + done->post(); + } + } + }; + // if initialization is in progress in another thread, don't try to init + // here. Otherwise the current thread will block on 'createInstance'. if (!single->creationStarted()) { single->createInstance(); } @@ -149,28 +196,35 @@ void SingletonVault::doEagerInitVia(Executor* exe) { } 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(), creationOrder->size()); - CHECK_GE(singletons_.size(), creation_order_.size()); + // Release all ReadMostlyMainPtrs at once + { + ReadMostlyMainPtrDeleter<> 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; } @@ -180,21 +234,23 @@ void SingletonVault::destroyInstances() { } { - 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() { - RequestContext::saveContext(); + // Add a dependency on folly::ThreadLocal to make sure all its static + // singletons are initalized first. + threadlocal_detail::StaticMeta::instance(); class SingletonVaultDestructor { public: