Remove SingletonVault C bindings
[folly.git] / folly / Singleton.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <folly/Singleton.h>
18
19 #ifndef _WIN32
20 #include <dlfcn.h>
21 #endif
22
23 #include <atomic>
24 #include <cstdio>
25 #include <cstdlib>
26 #include <iostream>
27 #include <string>
28
29 #include <folly/Demangle.h>
30 #include <folly/Format.h>
31 #include <folly/ScopeGuard.h>
32
33 #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__ANDROID__)
34 #define FOLLY_SINGLETON_HAVE_DLSYM 1
35 #endif
36
37 namespace folly {
38
39 #if FOLLY_SINGLETON_HAVE_DLSYM
40 namespace detail {
41 static void singleton_hs_init_weak(int* argc, char** argv[])
42     __attribute__((__weakref__("hs_init")));
43 } // namespace detail
44 #endif
45
46 SingletonVault::Type SingletonVault::defaultVaultType() {
47 #if FOLLY_SINGLETON_HAVE_DLSYM
48   bool isPython = dlsym(RTLD_DEFAULT, "Py_Main");
49   bool isHaskel =
50       detail::singleton_hs_init_weak || dlsym(RTLD_DEFAULT, "hs_init");
51   bool isJVM = dlsym(RTLD_DEFAULT, "JNI_GetCreatedJavaVMs");
52   bool isD = dlsym(RTLD_DEFAULT, "_d_run_main");
53
54   return isPython || isHaskel || isJVM || isD ? Type::Relaxed : Type::Strict;
55 #else
56   return Type::Relaxed;
57 #endif
58 }
59
60 namespace detail {
61
62 std::string TypeDescriptor::name() const {
63   auto ret = demangle(ti_.name());
64   if (tag_ti_ != std::type_index(typeid(DefaultTag))) {
65     ret += "/";
66     ret += demangle(tag_ti_.name());
67   }
68   return ret.toStdString();
69 }
70
71 [[noreturn]] void singletonWarnDoubleRegistrationAndAbort(
72     const TypeDescriptor& type) {
73   // Ensure the availability of std::cerr
74   std::ios_base::Init ioInit;
75   std::cerr << "Double registration of singletons of the same "
76                "underlying type; check for multiple definitions "
77                "of type folly::Singleton<"
78             << type.name() << ">\n";
79   std::abort();
80 }
81
82 [[noreturn]] void singletonWarnLeakyDoubleRegistrationAndAbort(
83     const TypeDescriptor& type) {
84   // Ensure the availability of std::cerr
85   std::ios_base::Init ioInit;
86   std::cerr << "Double registration of singletons of the same "
87                "underlying type; check for multiple definitions "
88                "of type folly::LeakySingleton<"
89             << type.name() << ">\n";
90   std::abort();
91 }
92
93 [[noreturn]] void singletonWarnLeakyInstantiatingNotRegisteredAndAbort(
94     const TypeDescriptor& type) {
95   auto ptr = SingletonVault::stackTraceGetter().load();
96   LOG(FATAL) << "Creating instance for unregistered singleton: "
97              << type.name() << "\n"
98              << "Stacktrace:"
99              << "\n" << (ptr ? (*ptr)() : "(not available)");
100 }
101
102 [[noreturn]] void singletonWarnRegisterMockEarlyAndAbort(
103     const TypeDescriptor& type) {
104   LOG(FATAL) << "Registering mock before singleton was registered: "
105              << type.name();
106 }
107
108 void singletonWarnDestroyInstanceLeak(
109     const TypeDescriptor& type,
110     const void* ptr) {
111   LOG(ERROR) << "Singleton of type " << type.name() << " has a "
112              << "living reference at destroyInstances time; beware! Raw "
113              << "pointer is " << ptr << ". It is very likely "
114              << "that some other singleton is holding a shared_ptr to it. "
115              << "This singleton will be leaked (even if a shared_ptr to it "
116              << "is eventually released)."
117              << "Make sure dependencies between these singletons are "
118              << "properly defined.";
119 }
120
121 [[noreturn]] void singletonWarnCreateCircularDependencyAndAbort(
122     const TypeDescriptor& type) {
123   LOG(FATAL) << "circular singleton dependency: " << type.name();
124 }
125
126 [[noreturn]] void singletonWarnCreateUnregisteredAndAbort(
127     const TypeDescriptor& type) {
128   auto ptr = SingletonVault::stackTraceGetter().load();
129   LOG(FATAL) << "Creating instance for unregistered singleton: "
130              << type.name() << "\n"
131              << "Stacktrace:"
132              << "\n"
133              << (ptr ? (*ptr)() : "(not available)");
134 }
135
136 [[noreturn]] void singletonWarnCreateBeforeRegistrationCompleteAndAbort(
137     const TypeDescriptor& type) {
138   auto stack_trace_getter = SingletonVault::stackTraceGetter().load();
139   auto stack_trace = stack_trace_getter ? stack_trace_getter() : "";
140   if (!stack_trace.empty()) {
141     stack_trace = "Stack trace:\n" + stack_trace;
142   }
143
144   LOG(FATAL) << "Singleton " << type.name() << " requested before "
145              << "registrationComplete() call.\n"
146              << "This usually means that either main() never called "
147              << "folly::init, or singleton was requested before main() "
148              << "(which is not allowed).\n"
149              << stack_trace;
150 }
151
152 void singletonPrintDestructionStackTrace(const TypeDescriptor& type) {
153   std::string output = "Singleton " + type.name() + " was released.\n";
154
155   auto stack_trace_getter = SingletonVault::stackTraceGetter().load();
156   auto stack_trace = stack_trace_getter ? stack_trace_getter() : "";
157   if (stack_trace.empty()) {
158     output += "Failed to get release stack trace.";
159   } else {
160     output += "Release stack trace:\n";
161     output += stack_trace;
162   }
163
164   LOG(ERROR) << output;
165 }
166
167 [[noreturn]] void singletonThrowNullCreator(const std::type_info& type) {
168   auto const msg = sformat(
169       "nullptr_t should be passed if you want {} to be default constructed",
170       demangle(type));
171   throw std::logic_error(msg);
172 }
173
174 [[noreturn]] void singletonThrowGetInvokedAfterDestruction(
175     const TypeDescriptor& type) {
176   throw std::runtime_error(
177       "Raw pointer to a singleton requested after its destruction."
178       " Singleton type is: " +
179       type.name());
180 }
181
182 [[noreturn]] void SingletonVaultState::throwUnexpectedState(const char* msg) {
183   throw std::logic_error(msg);
184 }
185
186 } // namespace detail
187
188 namespace {
189
190 struct FatalHelper {
191   ~FatalHelper() {
192     if (!leakedSingletons_.empty()) {
193       std::string leakedTypes;
194       for (const auto& singleton : leakedSingletons_) {
195         leakedTypes += "\t" + singleton.name() + "\n";
196       }
197       LOG(DFATAL) << "Singletons of the following types had living references "
198                   << "after destroyInstances was finished:\n" << leakedTypes
199                   << "beware! It is very likely that those singleton instances "
200                   << "are leaked.";
201     }
202   }
203
204   std::vector<detail::TypeDescriptor> leakedSingletons_;
205 };
206
207 #if defined(__APPLE__) || defined(_MSC_VER)
208 // OS X doesn't support constructor priorities.
209 FatalHelper fatalHelper;
210 #else
211 FatalHelper __attribute__ ((__init_priority__ (101))) fatalHelper;
212 #endif
213
214 } // namespace
215
216 SingletonVault::~SingletonVault() { destroyInstances(); }
217
218 void SingletonVault::registerSingleton(detail::SingletonHolderBase* entry) {
219   auto state = state_.rlock();
220   state->check(detail::SingletonVaultState::Type::Running);
221
222   if (UNLIKELY(state->registrationComplete)) {
223     LOG(ERROR) << "Registering singleton after registrationComplete().";
224   }
225
226   auto singletons = singletons_.wlock();
227   CHECK_THROW(
228       singletons->emplace(entry->type(), entry).second, std::logic_error);
229 }
230
231 void SingletonVault::addEagerInitSingleton(detail::SingletonHolderBase* entry) {
232   auto state = state_.rlock();
233   state->check(detail::SingletonVaultState::Type::Running);
234
235   if (UNLIKELY(state->registrationComplete)) {
236     LOG(ERROR) << "Registering for eager-load after registrationComplete().";
237   }
238
239   CHECK_THROW(singletons_.rlock()->count(entry->type()), std::logic_error);
240
241   auto eagerInitSingletons = eagerInitSingletons_.wlock();
242   eagerInitSingletons->insert(entry);
243 }
244
245 void SingletonVault::registrationComplete() {
246   std::atexit([](){ SingletonVault::singleton()->destroyInstances(); });
247
248   auto state = state_.wlock();
249   state->check(detail::SingletonVaultState::Type::Running);
250
251   if (state->registrationComplete) {
252     return;
253   }
254
255   auto singletons = singletons_.rlock();
256   if (type_ == Type::Strict) {
257     for (const auto& p : *singletons) {
258       if (p.second->hasLiveInstance()) {
259         throw std::runtime_error(
260             "Singleton " + p.first.name() +
261             " created before registration was complete.");
262       }
263     }
264   }
265
266   state->registrationComplete = true;
267 }
268
269 void SingletonVault::doEagerInit() {
270   {
271     auto state = state_.rlock();
272     state->check(detail::SingletonVaultState::Type::Running);
273     if (UNLIKELY(!state->registrationComplete)) {
274       throw std::logic_error("registrationComplete() not yet called");
275     }
276   }
277
278   auto eagerInitSingletons = eagerInitSingletons_.rlock();
279   for (auto* single : *eagerInitSingletons) {
280     single->createInstance();
281   }
282 }
283
284 void SingletonVault::doEagerInitVia(Executor& exe, folly::Baton<>* done) {
285   {
286     auto state = state_.rlock();
287     state->check(detail::SingletonVaultState::Type::Running);
288     if (UNLIKELY(!state->registrationComplete)) {
289       throw std::logic_error("registrationComplete() not yet called");
290     }
291   }
292
293   auto eagerInitSingletons = eagerInitSingletons_.rlock();
294   auto countdown =
295       std::make_shared<std::atomic<size_t>>(eagerInitSingletons->size());
296   for (auto* single : *eagerInitSingletons) {
297     // countdown is retained by shared_ptr, and will be alive until last lambda
298     // is done.  notifyBaton is provided by the caller, and expected to remain
299     // present (if it's non-nullptr).  singletonSet can go out of scope but
300     // its values, which are SingletonHolderBase pointers, are alive as long as
301     // SingletonVault is not being destroyed.
302     exe.add([=] {
303       // decrement counter and notify if requested, whether initialization
304       // was successful, was skipped (already initialized), or exception thrown.
305       SCOPE_EXIT {
306         if (--(*countdown) == 0) {
307           if (done != nullptr) {
308             done->post();
309           }
310         }
311       };
312       // if initialization is in progress in another thread, don't try to init
313       // here.  Otherwise the current thread will block on 'createInstance'.
314       if (!single->creationStarted()) {
315         single->createInstance();
316       }
317     });
318   }
319 }
320
321 void SingletonVault::destroyInstances() {
322   auto stateW = state_.wlock();
323   if (stateW->state == detail::SingletonVaultState::Type::Quiescing) {
324     return;
325   }
326   stateW->state = detail::SingletonVaultState::Type::Quiescing;
327
328   auto stateR = stateW.moveFromWriteToRead();
329   {
330     auto singletons = singletons_.rlock();
331     auto creationOrder = creationOrder_.rlock();
332
333     CHECK_GE(singletons->size(), creationOrder->size());
334
335     // Release all ReadMostlyMainPtrs at once
336     {
337       ReadMostlyMainPtrDeleter<> deleter;
338       for (auto& singleton_type : *creationOrder) {
339         singletons->at(singleton_type)->preDestroyInstance(deleter);
340       }
341     }
342
343     for (auto type_iter = creationOrder->rbegin();
344          type_iter != creationOrder->rend();
345          ++type_iter) {
346       singletons->at(*type_iter)->destroyInstance();
347     }
348
349     for (auto& singleton_type : *creationOrder) {
350       auto singleton = singletons->at(singleton_type);
351       if (!singleton->hasLiveInstance()) {
352         continue;
353       }
354
355       fatalHelper.leakedSingletons_.push_back(singleton->type());
356     }
357   }
358
359   {
360     auto creationOrder = creationOrder_.wlock();
361     creationOrder->clear();
362   }
363 }
364
365 void SingletonVault::reenableInstances() {
366   auto state = state_.wlock();
367
368   state->check(detail::SingletonVaultState::Type::Quiescing);
369
370   state->state = detail::SingletonVaultState::Type::Running;
371 }
372
373 void SingletonVault::scheduleDestroyInstances() {
374   // Add a dependency on folly::ThreadLocal to make sure all its static
375   // singletons are initalized first.
376   threadlocal_detail::StaticMeta<void, void>::instance();
377
378   class SingletonVaultDestructor {
379    public:
380     ~SingletonVaultDestructor() {
381       SingletonVault::singleton()->destroyInstances();
382     }
383   };
384
385   // Here we intialize a singleton, which calls destroyInstances in its
386   // destructor. Because of singleton destruction order - it will be destroyed
387   // before all the singletons, which were initialized before it and after all
388   // the singletons initialized after it.
389   static SingletonVaultDestructor singletonVaultDestructor;
390 }
391
392 } // namespace folly