2 * Copyright 2017 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>
29 #include <folly/ScopeGuard.h>
31 #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__ANDROID__)
32 #define FOLLY_SINGLETON_HAVE_DLSYM 1
37 #if FOLLY_SINGLETON_HAVE_DLSYM
39 static void singleton_hs_init_weak(int* argc, char** argv[])
40 __attribute__((__weakref__("hs_init")));
44 SingletonVault::Type SingletonVault::defaultVaultType() {
45 #if FOLLY_SINGLETON_HAVE_DLSYM
46 bool isPython = dlsym(RTLD_DEFAULT, "Py_Main");
48 detail::singleton_hs_init_weak || dlsym(RTLD_DEFAULT, "hs_init");
49 bool isJVM = dlsym(RTLD_DEFAULT, "JNI_GetCreatedJavaVMs");
50 bool isD = dlsym(RTLD_DEFAULT, "_d_run_main");
52 return isPython || isHaskel || isJVM || isD ? Type::Relaxed : Type::Strict;
60 [[noreturn]] void singletonWarnDoubleRegistrationAndAbort(
61 const TypeDescriptor& type) {
62 // Ensure the availability of std::cerr
63 std::ios_base::Init ioInit;
64 std::cerr << "Double registration of singletons of the same "
65 "underlying type; check for multiple definitions "
66 "of type folly::Singleton<"
67 << type.name() << ">\n";
76 if (!leakedSingletons_.empty()) {
77 std::string leakedTypes;
78 for (const auto& singleton : leakedSingletons_) {
79 leakedTypes += "\t" + singleton.name() + "\n";
81 LOG(DFATAL) << "Singletons of the following types had living references "
82 << "after destroyInstances was finished:\n" << leakedTypes
83 << "beware! It is very likely that those singleton instances "
88 std::vector<detail::TypeDescriptor> leakedSingletons_;
91 #if defined(__APPLE__) || defined(_MSC_VER)
92 // OS X doesn't support constructor priorities.
93 FatalHelper fatalHelper;
95 FatalHelper __attribute__ ((__init_priority__ (101))) fatalHelper;
100 SingletonVault::~SingletonVault() { destroyInstances(); }
102 void SingletonVault::registerSingleton(detail::SingletonHolderBase* entry) {
103 auto state = state_.rlock();
104 stateCheck(SingletonVaultState::Running, *state);
106 if (UNLIKELY(state->registrationComplete)) {
107 LOG(ERROR) << "Registering singleton after registrationComplete().";
110 auto singletons = singletons_.wlock();
112 singletons->emplace(entry->type(), entry).second, std::logic_error);
115 void SingletonVault::addEagerInitSingleton(detail::SingletonHolderBase* entry) {
116 auto state = state_.rlock();
117 stateCheck(SingletonVaultState::Running, *state);
119 if (UNLIKELY(state->registrationComplete)) {
120 LOG(ERROR) << "Registering for eager-load after registrationComplete().";
123 CHECK_THROW(singletons_.rlock()->count(entry->type()), std::logic_error);
125 auto eagerInitSingletons = eagerInitSingletons_.wlock();
126 eagerInitSingletons->insert(entry);
129 void SingletonVault::registrationComplete() {
130 std::atexit([](){ SingletonVault::singleton()->destroyInstances(); });
132 auto state = state_.wlock();
133 stateCheck(SingletonVaultState::Running, *state);
135 if (state->registrationComplete) {
139 auto singletons = singletons_.rlock();
140 if (type_ == Type::Strict) {
141 for (const auto& p : *singletons) {
142 if (p.second->hasLiveInstance()) {
143 throw std::runtime_error(
144 "Singleton " + p.first.name() +
145 " created before registration was complete.");
150 state->registrationComplete = true;
153 void SingletonVault::doEagerInit() {
155 auto state = state_.rlock();
156 stateCheck(SingletonVaultState::Running, *state);
157 if (UNLIKELY(!state->registrationComplete)) {
158 throw std::logic_error("registrationComplete() not yet called");
162 auto eagerInitSingletons = eagerInitSingletons_.rlock();
163 for (auto* single : *eagerInitSingletons) {
164 single->createInstance();
168 void SingletonVault::doEagerInitVia(Executor& exe, folly::Baton<>* done) {
170 auto state = state_.rlock();
171 stateCheck(SingletonVaultState::Running, *state);
172 if (UNLIKELY(!state->registrationComplete)) {
173 throw std::logic_error("registrationComplete() not yet called");
177 auto eagerInitSingletons = eagerInitSingletons_.rlock();
179 std::make_shared<std::atomic<size_t>>(eagerInitSingletons->size());
180 for (auto* single : *eagerInitSingletons) {
181 // countdown is retained by shared_ptr, and will be alive until last lambda
182 // is done. notifyBaton is provided by the caller, and expected to remain
183 // present (if it's non-nullptr). singletonSet can go out of scope but
184 // its values, which are SingletonHolderBase pointers, are alive as long as
185 // SingletonVault is not being destroyed.
187 // decrement counter and notify if requested, whether initialization
188 // was successful, was skipped (already initialized), or exception thrown.
190 if (--(*countdown) == 0) {
191 if (done != nullptr) {
196 // if initialization is in progress in another thread, don't try to init
197 // here. Otherwise the current thread will block on 'createInstance'.
198 if (!single->creationStarted()) {
199 single->createInstance();
205 void SingletonVault::destroyInstances() {
206 auto stateW = state_.wlock();
207 if (stateW->state == SingletonVaultState::Quiescing) {
210 stateW->state = SingletonVaultState::Quiescing;
212 auto stateR = stateW.moveFromWriteToRead();
214 auto singletons = singletons_.rlock();
215 auto creationOrder = creationOrder_.rlock();
217 CHECK_GE(singletons->size(), creationOrder->size());
219 // Release all ReadMostlyMainPtrs at once
221 ReadMostlyMainPtrDeleter<> deleter;
222 for (auto& singleton_type : *creationOrder) {
223 singletons->at(singleton_type)->preDestroyInstance(deleter);
227 for (auto type_iter = creationOrder->rbegin();
228 type_iter != creationOrder->rend();
230 singletons->at(*type_iter)->destroyInstance();
233 for (auto& singleton_type : *creationOrder) {
234 auto singleton = singletons->at(singleton_type);
235 if (!singleton->hasLiveInstance()) {
239 fatalHelper.leakedSingletons_.push_back(singleton->type());
244 auto creationOrder = creationOrder_.wlock();
245 creationOrder->clear();
249 void SingletonVault::reenableInstances() {
250 auto state = state_.wlock();
252 stateCheck(SingletonVaultState::Quiescing, *state);
254 state->state = SingletonVaultState::Running;
257 void SingletonVault::scheduleDestroyInstances() {
258 // Add a dependency on folly::ThreadLocal to make sure all its static
259 // singletons are initalized first.
260 threadlocal_detail::StaticMeta<void, void>::instance();
262 class SingletonVaultDestructor {
264 ~SingletonVaultDestructor() {
265 SingletonVault::singleton()->destroyInstances();
269 // Here we intialize a singleton, which calls destroyInstances in its
270 // destructor. Because of singleton destruction order - it will be destroyed
271 // before all the singletons, which were initialized before it and after all
272 // the singletons initialized after it.
273 static SingletonVaultDestructor singletonVaultDestructor;