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/ScopeGuard.h>
31 [[noreturn]] void singletonWarnDoubleRegistrationAndAbort(
32 const TypeDescriptor& type) {
33 // Ensure the availability of std::cerr
34 std::ios_base::Init ioInit;
35 std::cerr << "Double registration of singletons of the same "
36 "underlying type; check for multiple definitions "
37 "of type folly::Singleton<"
38 << type.name() << ">\n";
47 if (!leakedSingletons_.empty()) {
48 std::string leakedTypes;
49 for (const auto& singleton : leakedSingletons_) {
50 leakedTypes += "\t" + singleton.name() + "\n";
52 LOG(DFATAL) << "Singletons of the following types had living references "
53 << "after destroyInstances was finished:\n" << leakedTypes
54 << "beware! It is very likely that those singleton instances "
59 std::vector<detail::TypeDescriptor> leakedSingletons_;
62 #if defined(__APPLE__) || defined(_MSC_VER)
63 // OS X doesn't support constructor priorities.
64 FatalHelper fatalHelper;
66 FatalHelper __attribute__ ((__init_priority__ (101))) fatalHelper;
71 SingletonVault::~SingletonVault() { destroyInstances(); }
73 void SingletonVault::registerSingleton(detail::SingletonHolderBase* entry) {
74 auto state = state_.rlock();
75 stateCheck(SingletonVaultState::Running, *state);
77 if (UNLIKELY(state->registrationComplete)) {
78 LOG(ERROR) << "Registering singleton after registrationComplete().";
81 auto singletons = singletons_.wlock();
83 singletons->emplace(entry->type(), entry).second, std::logic_error);
86 void SingletonVault::addEagerInitSingleton(detail::SingletonHolderBase* entry) {
87 auto state = state_.rlock();
88 stateCheck(SingletonVaultState::Running, *state);
90 if (UNLIKELY(state->registrationComplete)) {
91 LOG(ERROR) << "Registering for eager-load after registrationComplete().";
94 CHECK_THROW(singletons_.rlock()->count(entry->type()), std::logic_error);
96 auto eagerInitSingletons = eagerInitSingletons_.wlock();
97 eagerInitSingletons->insert(entry);
100 void SingletonVault::registrationComplete() {
101 std::atexit([](){ SingletonVault::singleton()->destroyInstances(); });
103 auto state = state_.wlock();
104 stateCheck(SingletonVaultState::Running, *state);
106 auto singletons = singletons_.rlock();
107 if (type_ == Type::Strict) {
108 for (const auto& p : *singletons) {
109 if (p.second->hasLiveInstance()) {
110 throw std::runtime_error(
111 "Singleton created before registration was complete.");
116 state->registrationComplete = true;
119 void SingletonVault::doEagerInit() {
121 auto state = state_.rlock();
122 stateCheck(SingletonVaultState::Running, *state);
123 if (UNLIKELY(!state->registrationComplete)) {
124 throw std::logic_error("registrationComplete() not yet called");
128 auto eagerInitSingletons = eagerInitSingletons_.rlock();
129 for (auto* single : *eagerInitSingletons) {
130 single->createInstance();
134 void SingletonVault::doEagerInitVia(Executor& exe, folly::Baton<>* done) {
136 auto state = state_.rlock();
137 stateCheck(SingletonVaultState::Running, *state);
138 if (UNLIKELY(!state->registrationComplete)) {
139 throw std::logic_error("registrationComplete() not yet called");
143 auto eagerInitSingletons = eagerInitSingletons_.rlock();
145 std::make_shared<std::atomic<size_t>>(eagerInitSingletons->size());
146 for (auto* single : *eagerInitSingletons) {
147 // countdown is retained by shared_ptr, and will be alive until last lambda
148 // is done. notifyBaton is provided by the caller, and expected to remain
149 // present (if it's non-nullptr). singletonSet can go out of scope but
150 // its values, which are SingletonHolderBase pointers, are alive as long as
151 // SingletonVault is not being destroyed.
153 // decrement counter and notify if requested, whether initialization
154 // was successful, was skipped (already initialized), or exception thrown.
156 if (--(*countdown) == 0) {
157 if (done != nullptr) {
162 // if initialization is in progress in another thread, don't try to init
163 // here. Otherwise the current thread will block on 'createInstance'.
164 if (!single->creationStarted()) {
165 single->createInstance();
171 void SingletonVault::destroyInstances() {
172 auto stateW = state_.wlock();
173 if (stateW->state == SingletonVaultState::Quiescing) {
176 stateW->state = SingletonVaultState::Quiescing;
178 auto stateR = stateW.moveFromWriteToRead();
180 auto singletons = singletons_.rlock();
181 auto creationOrder = creationOrder_.rlock();
183 CHECK_GE(singletons->size(), creationOrder->size());
185 // Release all ReadMostlyMainPtrs at once
187 ReadMostlyMainPtrDeleter<> deleter;
188 for (auto& singleton_type : *creationOrder) {
189 singletons->at(singleton_type)->preDestroyInstance(deleter);
193 for (auto type_iter = creationOrder->rbegin();
194 type_iter != creationOrder->rend();
196 singletons->at(*type_iter)->destroyInstance();
199 for (auto& singleton_type : *creationOrder) {
200 auto singleton = singletons->at(singleton_type);
201 if (!singleton->hasLiveInstance()) {
205 fatalHelper.leakedSingletons_.push_back(singleton->type());
210 auto creationOrder = creationOrder_.wlock();
211 creationOrder->clear();
215 void SingletonVault::reenableInstances() {
216 auto state = state_.wlock();
218 stateCheck(SingletonVaultState::Quiescing, *state);
220 state->state = SingletonVaultState::Running;
223 void SingletonVault::scheduleDestroyInstances() {
224 // Add a dependency on folly::ThreadLocal to make sure all its static
225 // singletons are initalized first.
226 threadlocal_detail::StaticMeta<void, void>::instance();
228 class SingletonVaultDestructor {
230 ~SingletonVaultDestructor() {
231 SingletonVault::singleton()->destroyInstances();
235 // Here we intialize a singleton, which calls destroyInstances in its
236 // destructor. Because of singleton destruction order - it will be destroyed
237 // before all the singletons, which were initialized before it and after all
238 // the singletons initialized after it.
239 static SingletonVaultDestructor singletonVaultDestructor;