2 * Copyright 2015 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <folly/Singleton.h>
25 constexpr std::chrono::seconds SingletonHolderBase::kDestroyWaitTime;
33 if (!leakedSingletons_.empty()) {
34 std::string leakedTypes;
35 for (const auto& singleton : leakedSingletons_) {
36 leakedTypes += "\t" + singleton.name() + "\n";
38 LOG(DFATAL) << "Singletons of the following types had living references "
39 << "after destroyInstances was finished:\n" << leakedTypes
40 << "beware! It is very likely that those singleton instances "
45 std::vector<detail::TypeDescriptor> leakedSingletons_;
48 #if defined(__APPLE__) || defined(_MSC_VER)
49 // OS X doesn't support constructor priorities.
50 FatalHelper fatalHelper;
52 FatalHelper __attribute__ ((__init_priority__ (101))) fatalHelper;
57 SingletonVault::~SingletonVault() { destroyInstances(); }
59 void SingletonVault::registerSingleton(detail::SingletonHolderBase* entry) {
60 RWSpinLock::ReadHolder rh(&stateMutex_);
62 stateCheck(SingletonVaultState::Running);
64 if (UNLIKELY(registrationComplete_)) {
65 throw std::logic_error(
66 "Registering singleton after registrationComplete().");
69 RWSpinLock::ReadHolder rhMutex(&mutex_);
70 CHECK_THROW(singletons_.find(entry->type()) == singletons_.end(),
73 RWSpinLock::UpgradedHolder wh(&mutex_);
74 singletons_[entry->type()] = entry;
77 void SingletonVault::addEagerInitSingleton(detail::SingletonHolderBase* entry) {
78 RWSpinLock::ReadHolder rh(&stateMutex_);
80 stateCheck(SingletonVaultState::Running);
82 if (UNLIKELY(registrationComplete_)) {
83 throw std::logic_error(
84 "Registering for eager-load after registrationComplete().");
87 RWSpinLock::ReadHolder rhMutex(&mutex_);
88 CHECK_THROW(singletons_.find(entry->type()) != singletons_.end(),
91 RWSpinLock::UpgradedHolder wh(&mutex_);
92 eagerInitSingletons_.insert(entry);
95 void SingletonVault::registrationComplete() {
96 RequestContext::saveContext();
97 std::atexit([](){ SingletonVault::singleton()->destroyInstances(); });
99 RWSpinLock::WriteHolder wh(&stateMutex_);
101 stateCheck(SingletonVaultState::Running);
103 if (type_ == Type::Strict) {
104 for (const auto& p : singletons_) {
105 if (p.second->hasLiveInstance()) {
106 throw std::runtime_error(
107 "Singleton created before registration was complete.");
112 registrationComplete_ = true;
115 void SingletonVault::doEagerInit() {
116 std::unordered_set<detail::SingletonHolderBase*> singletonSet;
118 RWSpinLock::ReadHolder rh(&stateMutex_);
119 stateCheck(SingletonVaultState::Running);
120 if (UNLIKELY(!registrationComplete_)) {
121 throw std::logic_error("registrationComplete() not yet called");
123 singletonSet = eagerInitSingletons_; // copy set of pointers
126 for (auto *single : singletonSet) {
127 single->createInstance();
131 Future<Unit> SingletonVault::doEagerInitVia(Executor* exe) {
132 std::unordered_set<detail::SingletonHolderBase*> singletonSet;
134 RWSpinLock::ReadHolder rh(&stateMutex_);
135 stateCheck(SingletonVaultState::Running);
136 if (UNLIKELY(!registrationComplete_)) {
137 throw std::logic_error("registrationComplete() not yet called");
139 singletonSet = eagerInitSingletons_; // copy set of pointers
142 std::vector<Future<Unit>> resultFutures;
143 for (auto* single : singletonSet) {
144 resultFutures.emplace_back(via(exe).then([single] {
145 if (!single->creationStarted()) {
146 single->createInstance();
151 return collectAll(resultFutures).via(exe).then();
154 void SingletonVault::destroyInstances() {
155 RWSpinLock::WriteHolder state_wh(&stateMutex_);
157 if (state_ == SingletonVaultState::Quiescing) {
160 state_ = SingletonVaultState::Quiescing;
162 RWSpinLock::ReadHolder state_rh(std::move(state_wh));
165 RWSpinLock::ReadHolder rh(&mutex_);
167 CHECK_GE(singletons_.size(), creation_order_.size());
169 for (auto type_iter = creation_order_.rbegin();
170 type_iter != creation_order_.rend();
172 singletons_[*type_iter]->destroyInstance();
175 for (auto& singleton_type: creation_order_) {
176 auto singleton = singletons_[singleton_type];
177 if (!singleton->hasLiveInstance()) {
181 fatalHelper.leakedSingletons_.push_back(singleton->type());
186 RWSpinLock::WriteHolder wh(&mutex_);
187 creation_order_.clear();
191 void SingletonVault::reenableInstances() {
192 RWSpinLock::WriteHolder state_wh(&stateMutex_);
194 stateCheck(SingletonVaultState::Quiescing);
196 state_ = SingletonVaultState::Running;
199 void SingletonVault::scheduleDestroyInstances() {
200 RequestContext::saveContext();
202 class SingletonVaultDestructor {
204 ~SingletonVaultDestructor() {
205 SingletonVault::singleton()->destroyInstances();
209 // Here we intialize a singleton, which calls destroyInstances in its
210 // destructor. Because of singleton destruction order - it will be destroyed
211 // before all the singletons, which were initialized before it and after all
212 // the singletons initialized after it.
213 static SingletonVaultDestructor singletonVaultDestructor;