proxygen
Singleton.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2014-present 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>
19 
20 #ifndef _WIN32
21 #include <dlfcn.h>
22 #endif
23 
24 #include <atomic>
25 #include <cstdio>
26 #include <cstdlib>
27 #include <iostream>
28 #include <string>
29 
30 #include <folly/Demangle.h>
31 #include <folly/Format.h>
32 #include <folly/ScopeGuard.h>
33 
34 #if FOLLY_USE_SYMBOLIZER
36 #endif
37 
38 #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__ANDROID__)
39 #define FOLLY_SINGLETON_HAVE_DLSYM 1
40 #endif
41 
42 namespace folly {
43 
44 #if FOLLY_SINGLETON_HAVE_DLSYM
45 namespace detail {
46 static void singleton_hs_init_weak(int* argc, char** argv[])
47  __attribute__((__weakref__("hs_init")));
48 } // namespace detail
49 #endif
50 
52 #if FOLLY_SINGLETON_HAVE_DLSYM
53  bool isPython = dlsym(RTLD_DEFAULT, "Py_Main");
54  bool isHaskel =
55  detail::singleton_hs_init_weak || dlsym(RTLD_DEFAULT, "hs_init");
56  bool isJVM = dlsym(RTLD_DEFAULT, "JNI_GetCreatedJavaVMs");
57  bool isD = dlsym(RTLD_DEFAULT, "_d_run_main");
58 
59  return isPython || isHaskel || isJVM || isD ? Type::Relaxed : Type::Strict;
60 #else
61  return Type::Relaxed;
62 #endif
63 }
64 
65 namespace detail {
66 
68  auto ret = demangle(ti_.name());
69  if (tag_ti_ != std::type_index(typeid(DefaultTag))) {
70  ret += "/";
71  ret += demangle(tag_ti_.name());
72  }
73  return ret.toStdString();
74 }
75 
76 // clang-format off
78  const TypeDescriptor& type) {
79  // Ensure the availability of std::cerr
80  std::ios_base::Init ioInit;
81  std::cerr << "Double registration of singletons of the same "
82  "underlying type; check for multiple definitions "
83  "of type folly::Singleton<"
84  << type.name() << ">\n";
85  std::abort();
86 }
87 
89  const TypeDescriptor& type) {
90  // Ensure the availability of std::cerr
91  std::ios_base::Init ioInit;
92  std::cerr << "Double registration of singletons of the same "
93  "underlying type; check for multiple definitions "
94  "of type folly::LeakySingleton<"
95  << type.name() << ">\n";
96  std::abort();
97 }
98 
100  const TypeDescriptor& type) {
101  auto ptr = SingletonVault::stackTraceGetter().load();
102  LOG(FATAL) << "Creating instance for unregistered singleton: " << type.name()
103  << "\n"
104  << "Stacktrace:"
105  << "\n"
106  << (ptr ? (*ptr)() : "(not available)");
107 }
108 
110  const TypeDescriptor& type) {
111  LOG(FATAL) << "Registering mock before singleton was registered: "
112  << type.name();
113 }
114 
116  const TypeDescriptor& type,
117  const void* ptr) {
118  LOG(ERROR) << "Singleton of type " << type.name() << " has a "
119  << "living reference at destroyInstances time; beware! Raw "
120  << "pointer is " << ptr << ". It is very likely "
121  << "that some other singleton is holding a shared_ptr to it. "
122  << "This singleton will be leaked (even if a shared_ptr to it "
123  << "is eventually released)."
124  << "Make sure dependencies between these singletons are "
125  << "properly defined.";
126 }
127 
129  const TypeDescriptor& type) {
130  LOG(FATAL) << "circular singleton dependency: " << type.name();
131 }
132 
134  const TypeDescriptor& type) {
135  auto ptr = SingletonVault::stackTraceGetter().load();
136  LOG(FATAL) << "Creating instance for unregistered singleton: " << type.name()
137  << "\n"
138  << "Stacktrace:"
139  << "\n"
140  << (ptr ? (*ptr)() : "(not available)");
141 }
142 
144  const TypeDescriptor& type) {
145  auto stack_trace_getter = SingletonVault::stackTraceGetter().load();
146  auto stack_trace = stack_trace_getter ? stack_trace_getter() : "";
147  if (!stack_trace.empty()) {
148  stack_trace = "Stack trace:\n" + stack_trace;
149  }
150 
151  LOG(FATAL) << "Singleton " << type.name() << " requested before "
152  << "registrationComplete() call.\n"
153  << "This usually means that either main() never called "
154  << "folly::init, or singleton was requested before main() "
155  << "(which is not allowed).\n"
156  << stack_trace;
157 }
158 
160  std::string output = "Singleton " + type.name() + " was released.\n";
161 
162  auto stack_trace_getter = SingletonVault::stackTraceGetter().load();
163  auto stack_trace = stack_trace_getter ? stack_trace_getter() : "";
164  if (stack_trace.empty()) {
165  output += "Failed to get release stack trace.";
166  } else {
167  output += "Release stack trace:\n";
168  output += stack_trace;
169  }
170 
171  LOG(ERROR) << output;
172 }
173 
174 [[noreturn]] void singletonThrowNullCreator(const std::type_info& type) {
175  auto const msg = sformat(
176  "nullptr_t should be passed if you want {} to be default constructed",
177  demangle(type));
178  throw std::logic_error(msg);
179 }
180 
182  const TypeDescriptor& type) {
183  throw std::runtime_error(
184  "Raw pointer to a singleton requested after its destruction."
185  " Singleton type is: " +
186  type.name());
187 }
188 // clang-format on
189 
190 } // namespace detail
191 
192 namespace {
193 
194 struct FatalHelper {
195  ~FatalHelper() {
196  if (!leakedSingletons_.empty()) {
197  std::string leakedTypes;
198  for (const auto& singleton : leakedSingletons_) {
199  leakedTypes += "\t" + singleton.name() + "\n";
200  }
201  LOG(DFATAL) << "Singletons of the following types had living references "
202  << "after destroyInstances was finished:\n"
203  << leakedTypes
204  << "beware! It is very likely that those singleton instances "
205  << "are leaked.";
206  }
207  }
208 
209  std::vector<detail::TypeDescriptor> leakedSingletons_;
210 };
211 
212 #if defined(__APPLE__) || defined(_MSC_VER)
213 // OS X doesn't support constructor priorities.
214 FatalHelper fatalHelper;
215 #else
216 FatalHelper __attribute__((__init_priority__(101))) fatalHelper;
217 #endif
218 
219 } // namespace
220 
222  destroyInstances();
223 }
224 
226  auto state = state_.rlock();
228 
229  if (UNLIKELY(state->registrationComplete)) {
230  LOG(ERROR) << "Registering singleton after registrationComplete().";
231  }
232 
233  auto singletons = singletons_.wlock();
234  CHECK_THROW(
235  singletons->emplace(entry->type(), entry).second, std::logic_error);
236 }
237 
239  auto state = state_.rlock();
241 
242  if (UNLIKELY(state->registrationComplete)) {
243  LOG(ERROR) << "Registering for eager-load after registrationComplete().";
244  }
245 
246  CHECK_THROW(singletons_.rlock()->count(entry->type()), std::logic_error);
247 
248  auto eagerInitSingletons = eagerInitSingletons_.wlock();
249  eagerInitSingletons->insert(entry);
250 }
251 
253  std::atexit([]() { SingletonVault::singleton()->destroyInstances(); });
254 
255  auto state = state_.wlock();
257 
258  if (state->registrationComplete) {
259  return;
260  }
261 
262  auto singletons = singletons_.rlock();
263  if (type_ == Type::Strict) {
264  for (const auto& p : *singletons) {
265  if (p.second->hasLiveInstance()) {
266  throw std::runtime_error(
267  "Singleton " + p.first.name() +
268  " created before registration was complete.");
269  }
270  }
271  }
272 
273  state->registrationComplete = true;
274 }
275 
277  {
278  auto state = state_.rlock();
280  if (UNLIKELY(!state->registrationComplete)) {
281  throw std::logic_error("registrationComplete() not yet called");
282  }
283  }
284 
285  auto eagerInitSingletons = eagerInitSingletons_.rlock();
286  for (auto* single : *eagerInitSingletons) {
287  single->createInstance();
288  }
289 }
290 
292  {
293  auto state = state_.rlock();
295  if (UNLIKELY(!state->registrationComplete)) {
296  throw std::logic_error("registrationComplete() not yet called");
297  }
298  }
299 
300  auto eagerInitSingletons = eagerInitSingletons_.rlock();
301  auto countdown =
302  std::make_shared<std::atomic<size_t>>(eagerInitSingletons->size());
303  for (auto* single : *eagerInitSingletons) {
304  // countdown is retained by shared_ptr, and will be alive until last lambda
305  // is done. notifyBaton is provided by the caller, and expected to remain
306  // present (if it's non-nullptr). singletonSet can go out of scope but
307  // its values, which are SingletonHolderBase pointers, are alive as long as
308  // SingletonVault is not being destroyed.
309  exe.add([=] {
310  // decrement counter and notify if requested, whether initialization
311  // was successful, was skipped (already initialized), or exception thrown.
312  SCOPE_EXIT {
313  if (--(*countdown) == 0) {
314  if (done != nullptr) {
315  done->post();
316  }
317  }
318  };
319  // if initialization is in progress in another thread, don't try to init
320  // here. Otherwise the current thread will block on 'createInstance'.
321  if (!single->creationStarted()) {
322  single->createInstance();
323  }
324  });
325  }
326 }
327 
329  auto stateW = state_.wlock();
330  if (stateW->state == detail::SingletonVaultState::Type::Quiescing) {
331  return;
332  }
334 
335  auto stateR = stateW.moveFromWriteToRead();
336  {
337  auto singletons = singletons_.rlock();
338  auto creationOrder = creationOrder_.rlock();
339 
340  CHECK_GE(singletons->size(), creationOrder->size());
341 
342  // Release all ReadMostlyMainPtrs at once
343  {
345  for (auto& singleton_type : *creationOrder) {
346  singletons->at(singleton_type)->preDestroyInstance(deleter);
347  }
348  }
349 
350  for (auto type_iter = creationOrder->rbegin();
351  type_iter != creationOrder->rend();
352  ++type_iter) {
353  singletons->at(*type_iter)->destroyInstance();
354  }
355 
356  for (auto& singleton_type : *creationOrder) {
357  auto instance = singletons->at(singleton_type);
358  if (!instance->hasLiveInstance()) {
359  continue;
360  }
361 
362  fatalHelper.leakedSingletons_.push_back(instance->type());
363  }
364  }
365 
366  {
367  auto creationOrder = creationOrder_.wlock();
368  creationOrder->clear();
369  }
370 }
371 
373  auto state = state_.wlock();
374 
376 
378 }
379 
381  // Add a dependency on folly::ThreadLocal to make sure all its static
382  // singletons are initalized first.
384  std::atexit([] { SingletonVault::singleton()->destroyInstances(); });
385 }
386 
387 // If we're using folly's Symbolizer, create a static initializer to setup
388 // Singltone's to use it to print stack traces. It's important that we keep
389 // this in the same compilation unit as the `SingletonVault` so that it's
390 // setup/used iff singleton's are used.
391 #if FOLLY_USE_SYMBOLIZER
392 namespace {
393 
394 std::string stackTraceGetter() {
395  // Get and symbolize stack trace
396  constexpr size_t kMaxStackTraceDepth = 100;
398 
399  if (!getStackTraceSafe(addresses)) {
400  return "";
401  } else {
402  constexpr size_t kDefaultCapacity = 500;
403  symbolizer::ElfCache elfCache(kDefaultCapacity);
404 
405  symbolizer::Symbolizer symbolizer(&elfCache);
406  symbolizer.symbolize(addresses);
407 
409  printer.println(addresses);
410  return printer.str();
411  }
412 }
413 
414 struct SetStackTraceGetter {
415  SetStackTraceGetter() {
416  SingletonVault::stackTraceGetter().store(stackTraceGetter);
417  }
418 };
419 
420 #ifdef __APPLE__
421 // OS X doesn't support constructor priorities.
422 SetStackTraceGetter setStackTraceGetter;
423 #else
424 SetStackTraceGetter __attribute__((__init_priority__(101))) setStackTraceGetter;
425 #endif
426 } // namespace
427 #endif
428 
429 } // namespace folly
void * ptr
void registerSingleton(detail::SingletonHolderBase *entry)
Definition: Singleton.cpp:225
void singletonThrowNullCreator(const std::type_info &type)
Definition: Singleton.cpp:174
static SingletonVault * singleton()
Definition: Singleton.h:495
static Singleton< ShutdownSocketSet, PrivateTag > singleton
ssize_t getStackTraceSafe(uintptr_t *addresses, size_t maxAddresses)
Definition: StackTrace.cpp:53
std::string sformat(StringPiece fmt, Args &&...args)
Definition: Format.h:280
PskType type
static void singleton_hs_init_weak(int *argc, char **argv[]) __attribute__((__weakref__("hs_init")))
void singletonWarnCreateUnregisteredAndAbort(const TypeDescriptor &type)
Definition: Singleton.cpp:133
static StaticMeta< Tag, AccessMode > & instance()
void singletonWarnCreateCircularDependencyAndAbort(const TypeDescriptor &type)
Definition: Singleton.cpp:128
virtual void add(Func)=0
#define SCOPE_EXIT
Definition: ScopeGuard.h:274
void singletonWarnLeakyInstantiatingNotRegisteredAndAbort(const TypeDescriptor &type)
Definition: Singleton.cpp:99
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void println(uintptr_t address, const SymbolizedFrame &frame)
Definition: Symbolizer.cpp:284
static std::atomic< StackTraceGetterPtr > & stackTraceGetter()
Definition: Singleton.h:510
char ** argv
void singletonThrowGetInvokedAfterDestruction(const TypeDescriptor &type)
Definition: Singleton.cpp:181
const int kMaxStackTraceDepth
Definition: gtest.h:147
void singletonWarnRegisterMockEarlyAndAbort(const TypeDescriptor &type)
Definition: Singleton.cpp:109
Type type_
Definition: JSONSchema.cpp:208
void singletonWarnDoubleRegistrationAndAbort(const TypeDescriptor &type)
Definition: Singleton.cpp:77
std::vector< detail::TypeDescriptor > leakedSingletons_
Definition: Singleton.cpp:209
void singletonWarnDestroyInstanceLeak(const TypeDescriptor &type, const void *ptr)
Definition: Singleton.cpp:115
std::basic_string< E, T, A > toStdString() const
Definition: FBString.h:1227
void singletonWarnLeakyDoubleRegistrationAndAbort(const TypeDescriptor &type)
Definition: Singleton.cpp:88
void post() noexcept
Definition: Baton.h:123
static void scheduleDestroyInstances()
Definition: Singleton.cpp:380
countdownsingle single
void doEagerInitVia(Executor &exe, folly::Baton<> *done=nullptr)
Definition: Singleton.cpp:291
std::string name() const
Definition: Singleton.cpp:67
const char * string
Definition: Conv.cpp:212
#define CHECK_THROW(cond, E)
Definition: Exception.h:135
void singletonWarnCreateBeforeRegistrationCompleteAndAbort(const TypeDescriptor &type)
Definition: Singleton.cpp:143
__attribute__((noinline, noclone)) VirtualBase *makeVirtual()
TypeDescriptor type() const
Definition: Singleton.h:285
InlineExecutor exe
Definition: Benchmark.cpp:337
void singletonPrintDestructionStackTrace(const TypeDescriptor &type)
Definition: Singleton.cpp:159
static Type defaultVaultType()
Definition: Singleton.cpp:51
#define UNLIKELY(x)
Definition: Likely.h:48
void symbolize(const uintptr_t *addresses, SymbolizedFrame *frames, size_t frameCount)
Definition: Symbolizer.cpp:94
fbstring demangle(const char *name)
Definition: Demangle.cpp:111
state
Definition: http_parser.c:272
void addEagerInitSingleton(detail::SingletonHolderBase *entry)
Definition: Singleton.cpp:238