2 * Copyright 2016 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 #include <folly/FileUtil.h>
26 #include <folly/ScopeGuard.h>
32 [[noreturn]] void singletonWarnDoubleRegistrationAndAbort(
33 const TypeDescriptor& type) {
34 // Not using LOG(FATAL) or std::cerr because they may not be initialized yet.
36 o << "Double registration of singletons of the same "
37 << "underlying type; check for multiple definitions "
38 << "of type folly::Singleton<" << type.name() << ">" << std::endl;
40 writeFull(STDERR_FILENO, s.data(), s.size());
49 if (!leakedSingletons_.empty()) {
50 std::string leakedTypes;
51 for (const auto& singleton : leakedSingletons_) {
52 leakedTypes += "\t" + singleton.name() + "\n";
54 LOG(DFATAL) << "Singletons of the following types had living references "
55 << "after destroyInstances was finished:\n" << leakedTypes
56 << "beware! It is very likely that those singleton instances "
61 std::vector<detail::TypeDescriptor> leakedSingletons_;
64 #if defined(__APPLE__) || defined(_MSC_VER)
65 // OS X doesn't support constructor priorities.
66 FatalHelper fatalHelper;
68 FatalHelper __attribute__ ((__init_priority__ (101))) fatalHelper;
73 SingletonVault::~SingletonVault() { destroyInstances(); }
75 void SingletonVault::registerSingleton(detail::SingletonHolderBase* entry) {
76 auto state = state_.rlock();
77 stateCheck(SingletonVaultState::Running, *state);
79 if (UNLIKELY(state->registrationComplete)) {
80 LOG(ERROR) << "Registering singleton after registrationComplete().";
83 auto singletons = singletons_.wlock();
85 singletons->emplace(entry->type(), entry).second, std::logic_error);
88 void SingletonVault::addEagerInitSingleton(detail::SingletonHolderBase* entry) {
89 auto state = state_.rlock();
90 stateCheck(SingletonVaultState::Running, *state);
92 if (UNLIKELY(state->registrationComplete)) {
93 LOG(ERROR) << "Registering for eager-load after registrationComplete().";
96 CHECK_THROW(singletons_.rlock()->count(entry->type()), std::logic_error);
98 auto eagerInitSingletons = eagerInitSingletons_.wlock();
99 eagerInitSingletons->insert(entry);
102 void SingletonVault::registrationComplete() {
103 std::atexit([](){ SingletonVault::singleton()->destroyInstances(); });
105 auto state = state_.wlock();
106 stateCheck(SingletonVaultState::Running, *state);
108 auto singletons = singletons_.rlock();
109 if (type_ == Type::Strict) {
110 for (const auto& p : *singletons) {
111 if (p.second->hasLiveInstance()) {
112 throw std::runtime_error(
113 "Singleton created before registration was complete.");
118 state->registrationComplete = true;
121 void SingletonVault::doEagerInit() {
123 auto state = state_.rlock();
124 stateCheck(SingletonVaultState::Running, *state);
125 if (UNLIKELY(!state->registrationComplete)) {
126 throw std::logic_error("registrationComplete() not yet called");
130 auto eagerInitSingletons = eagerInitSingletons_.rlock();
131 for (auto* single : *eagerInitSingletons) {
132 single->createInstance();
136 void SingletonVault::doEagerInitVia(Executor& exe, folly::Baton<>* done) {
138 auto state = state_.rlock();
139 stateCheck(SingletonVaultState::Running, *state);
140 if (UNLIKELY(!state->registrationComplete)) {
141 throw std::logic_error("registrationComplete() not yet called");
145 auto eagerInitSingletons = eagerInitSingletons_.rlock();
147 std::make_shared<std::atomic<size_t>>(eagerInitSingletons->size());
148 for (auto* single : *eagerInitSingletons) {
149 // countdown is retained by shared_ptr, and will be alive until last lambda
150 // is done. notifyBaton is provided by the caller, and expected to remain
151 // present (if it's non-nullptr). singletonSet can go out of scope but
152 // its values, which are SingletonHolderBase pointers, are alive as long as
153 // SingletonVault is not being destroyed.
155 // decrement counter and notify if requested, whether initialization
156 // was successful, was skipped (already initialized), or exception thrown.
158 if (--(*countdown) == 0) {
159 if (done != nullptr) {
164 // if initialization is in progress in another thread, don't try to init
165 // here. Otherwise the current thread will block on 'createInstance'.
166 if (!single->creationStarted()) {
167 single->createInstance();
173 void SingletonVault::destroyInstances() {
174 auto stateW = state_.wlock();
175 if (stateW->state == SingletonVaultState::Quiescing) {
178 stateW->state = SingletonVaultState::Quiescing;
180 auto stateR = stateW.moveFromWriteToRead();
182 auto singletons = singletons_.rlock();
183 auto creationOrder = creationOrder_.rlock();
185 CHECK_GE(singletons->size(), creationOrder->size());
187 // Release all ReadMostlyMainPtrs at once
189 ReadMostlyMainPtrDeleter<> deleter;
190 for (auto& singleton_type : *creationOrder) {
191 singletons->at(singleton_type)->preDestroyInstance(deleter);
195 for (auto type_iter = creationOrder->rbegin();
196 type_iter != creationOrder->rend();
198 singletons->at(*type_iter)->destroyInstance();
201 for (auto& singleton_type : *creationOrder) {
202 auto singleton = singletons->at(singleton_type);
203 if (!singleton->hasLiveInstance()) {
207 fatalHelper.leakedSingletons_.push_back(singleton->type());
212 auto creationOrder = creationOrder_.wlock();
213 creationOrder->clear();
217 void SingletonVault::reenableInstances() {
218 auto state = state_.wlock();
220 stateCheck(SingletonVaultState::Quiescing, *state);
222 state->state = SingletonVaultState::Running;
225 void SingletonVault::scheduleDestroyInstances() {
226 // Add a dependency on folly::ThreadLocal to make sure all its static
227 // singletons are initalized first.
228 threadlocal_detail::StaticMeta<void, void>::instance();
230 class SingletonVaultDestructor {
232 ~SingletonVaultDestructor() {
233 SingletonVault::singleton()->destroyInstances();
237 // Here we intialize a singleton, which calls destroyInstances in its
238 // destructor. Because of singleton destruction order - it will be destroyed
239 // before all the singletons, which were initialized before it and after all
240 // the singletons initialized after it.
241 static SingletonVaultDestructor singletonVaultDestructor;