proxygen
Singleton-inl.h
Go to the documentation of this file.
1 /*
2  * Copyright 2015-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 namespace folly {
18 
19 namespace detail {
20 
21 template <typename T>
22 template <typename Tag, typename VaultTag>
24  /* library-local */ static auto entry =
25  createGlobal<SingletonHolder<T>, std::pair<Tag, VaultTag>>([]() {
26  return new SingletonHolder<T>(
27  {typeid(T), typeid(Tag)}, *SingletonVault::singleton<VaultTag>());
28  });
29  return *entry;
30 }
31 
33  const TypeDescriptor& type);
34 
35 template <typename T>
37  std::lock_guard<std::mutex> entry_lock(mutex_);
38 
39  if (state_ != SingletonHolderState::NotRegistered) {
40  /* Possible causes:
41  *
42  * You have two instances of the same
43  * folly::Singleton<Class>. Probably because you define the
44  * singleton in a header included in multiple places? In general,
45  * folly::Singleton shouldn't be in the header, only off in some
46  * anonymous namespace in a cpp file. Code needing the singleton
47  * will find it when that code references folly::Singleton<Class>.
48  *
49  * Alternatively, you could have 2 singletons with the same type
50  * defined with a different name in a .cpp (source) file. For
51  * example:
52  *
53  * Singleton<int> a([] { return new int(3); });
54  * Singleton<int> b([] { return new int(4); });
55  *
56  * Adding tags should fix this (see documentation in the header).
57  *
58  */
60  }
61 
62  create_ = std::move(c);
63  teardown_ = std::move(t);
64 
65  state_ = SingletonHolderState::Dead;
66 }
67 
68 template <typename T>
70  if (state_ == SingletonHolderState::NotRegistered) {
72  }
73  if (state_ == SingletonHolderState::Living) {
74  destroyInstance();
75  }
76 
77  {
78  auto creationOrder = vault_.creationOrder_.wlock();
79 
80  auto it = std::find(creationOrder->begin(), creationOrder->end(), type());
81  if (it != creationOrder->end()) {
82  creationOrder->erase(it);
83  }
84  }
85 
86  std::lock_guard<std::mutex> entry_lock(mutex_);
87 
88  create_ = std::move(c);
89  teardown_ = std::move(t);
90 }
91 
92 template <typename T>
94  if (LIKELY(
95  state_.load(std::memory_order_acquire) ==
96  SingletonHolderState::Living)) {
97  return instance_ptr_;
98  }
99  createInstance();
100 
101  if (instance_weak_.expired()) {
103  }
104 
105  return instance_ptr_;
106 }
107 
108 template <typename T>
109 std::weak_ptr<T> SingletonHolder<T>::get_weak() {
110  if (UNLIKELY(
111  state_.load(std::memory_order_acquire) !=
112  SingletonHolderState::Living)) {
113  createInstance();
114  }
115 
116  return instance_weak_;
117 }
118 
119 template <typename T>
120 std::shared_ptr<T> SingletonHolder<T>::try_get() {
121  if (UNLIKELY(
122  state_.load(std::memory_order_acquire) !=
123  SingletonHolderState::Living)) {
124  createInstance();
125  }
126 
127  return instance_weak_.lock();
128 }
129 
130 template <typename T>
132  if (UNLIKELY(
133  state_.load(std::memory_order_acquire) !=
134  SingletonHolderState::Living)) {
135  createInstance();
136  }
137 
138  return instance_weak_fast_.lock();
139 }
140 
141 template <typename T>
143  if (UNLIKELY(
144  state_.load(std::memory_order_relaxed) !=
145  SingletonHolderState::Living)) {
146  createInstance();
147  }
148 }
149 
150 template <typename T>
152  return !instance_weak_.expired();
153 }
154 
155 template <typename T>
157  ReadMostlyMainPtrDeleter<>& deleter) {
158  instance_copy_ = instance_;
159  deleter.add(std::move(instance_));
160 }
161 
162 template <typename T>
164  state_ = SingletonHolderState::Dead;
165  instance_.reset();
166  instance_copy_.reset();
167  if (destroy_baton_) {
168  constexpr std::chrono::seconds kDestroyWaitTime{5};
169  auto last_reference_released =
170  destroy_baton_->try_wait_for(kDestroyWaitTime);
171  if (last_reference_released) {
172  teardown_(instance_ptr_);
173  } else {
174  print_destructor_stack_trace_->store(true);
176  }
177  }
178 }
179 
180 template <typename T>
182  TypeDescriptor typeDesc,
183  SingletonVault& vault)
184  : SingletonHolderBase(typeDesc), vault_(vault) {}
185 
186 template <typename T>
188  // If alive, then creation was of course started.
189  // This is flipped after creating_thread_ was set, and before it was reset.
190  if (state_.load(std::memory_order_acquire) == SingletonHolderState::Living) {
191  return true;
192  }
193 
194  // Not yet built. Is it currently in progress?
195  if (creating_thread_.load(std::memory_order_acquire) != std::thread::id()) {
196  return true;
197  }
198 
199  return false;
200 }
201 
202 template <typename T>
204  if (creating_thread_.load(std::memory_order_acquire) ==
205  std::this_thread::get_id()) {
207  }
208 
209  std::lock_guard<std::mutex> entry_lock(mutex_);
210  if (state_.load(std::memory_order_acquire) == SingletonHolderState::Living) {
211  return;
212  }
213  if (state_.load(std::memory_order_acquire) ==
216  }
217 
218  if (state_.load(std::memory_order_acquire) == SingletonHolderState::Living) {
219  return;
220  }
221 
222  SCOPE_EXIT {
223  // Clean up creator thread when complete, and also, in case of errors here,
224  // so that subsequent attempts don't think this is still in the process of
225  // being built.
226  creating_thread_.store(std::thread::id(), std::memory_order_release);
227  };
228 
229  creating_thread_.store(std::this_thread::get_id(), std::memory_order_release);
230 
231  auto state = vault_.state_.rlock();
233  !state->registrationComplete) {
235  }
237  return;
238  }
239 
240  auto destroy_baton = std::make_shared<folly::Baton<>>();
241  auto print_destructor_stack_trace =
242  std::make_shared<std::atomic<bool>>(false);
243 
244  // Can't use make_shared -- no support for a custom deleter, sadly.
245  std::shared_ptr<T> instance(
246  create_(),
247  [destroy_baton, print_destructor_stack_trace, type = type()](T*) mutable {
248  destroy_baton->post();
249  if (print_destructor_stack_trace->load()) {
251  }
252  });
253 
254  // We should schedule destroyInstances() only after the singleton was
255  // created. This will ensure it will be destroyed before singletons,
256  // not managed by folly::Singleton, which were initialized in its
257  // constructor
259 
260  instance_weak_ = instance;
261  instance_ptr_ = instance.get();
262  instance_.reset(std::move(instance));
264 
265  destroy_baton_ = std::move(destroy_baton);
266  print_destructor_stack_trace_ = std::move(print_destructor_stack_trace);
267 
268  // This has to be the last step, because once state is Living other threads
269  // may access instance and instance_weak w/o synchronization.
270  state_.store(SingletonHolderState::Living, std::memory_order_release);
271 
272  vault_.creationOrder_.wlock()->push_back(type());
273 }
274 
275 } // namespace detail
276 
277 } // namespace folly
folly::ReadMostlySharedPtr< T > try_get_fast()
PskType type
void preDestroyInstance(ReadMostlyMainPtrDeleter<> &) override
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
void singletonWarnCreateUnregisteredAndAbort(const TypeDescriptor &type)
Definition: Singleton.cpp:133
#define LIKELY(x)
Definition: Likely.h:47
void singletonWarnCreateCircularDependencyAndAbort(const TypeDescriptor &type)
Definition: Singleton.cpp:128
#define SCOPE_EXIT
Definition: ScopeGuard.h:274
folly::std T
std::function< T *(void)> CreateFunc
Definition: Singleton.h:305
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void registerSingleton(CreateFunc c, TeardownFunc t)
Definition: Singleton-inl.h:36
static SingletonHolder< T > & singleton()
Definition: Singleton-inl.h:23
std::mutex mutex_
std::shared_ptr< T > try_get()
folly::ReadMostlyMainPtr< T > instance_
Definition: Singleton.h:349
std::weak_ptr< T > get_weak()
void singletonThrowGetInvokedAfterDestruction(const TypeDescriptor &type)
Definition: Singleton.cpp:181
void registerSingletonMock(CreateFunc c, TeardownFunc t)
Definition: Singleton-inl.h:69
void singletonWarnRegisterMockEarlyAndAbort(const TypeDescriptor &type)
Definition: Singleton.cpp:109
void singletonWarnDoubleRegistrationAndAbort(const TypeDescriptor &type)
Definition: Singleton.cpp:77
std::shared_ptr< folly::Baton<> > destroy_baton_
Definition: Singleton.h:360
void singletonWarnDestroyInstanceLeak(const TypeDescriptor &type, const void *ptr)
Definition: Singleton.cpp:115
folly::ReadMostlyWeakPtr< T > instance_weak_fast_
Definition: Singleton.h:358
std::atomic< std::thread::id > creating_thread_
Definition: Singleton.h:343
void add(ReadMostlyMainPtr< T, RefCount > ptr) noexcept
static void scheduleDestroyInstances()
Definition: Singleton.cpp:380
std::weak_ptr< T > instance_weak_
Definition: Singleton.h:356
void singletonWarnCreateBeforeRegistrationCompleteAndAbort(const TypeDescriptor &type)
Definition: Singleton.cpp:143
std::atomic< SingletonHolderState > state_
Definition: Singleton.h:340
TypeDescriptor type() const
Definition: Singleton.h:285
void singletonPrintDestructionStackTrace(const TypeDescriptor &type)
Definition: Singleton.cpp:159
std::shared_ptr< std::atomic< bool > > print_destructor_stack_trace_
Definition: Singleton.h:365
#define UNLIKELY(x)
Definition: Likely.h:48
SingletonHolder(TypeDescriptor type, SingletonVault &vault)
char c
std::function< void(T *)> TeardownFunc
Definition: Singleton.h:304
Synchronized< std::vector< detail::TypeDescriptor >, SharedMutexSuppressTSAN > creationOrder_
Definition: Singleton.h:552
state
Definition: http_parser.c:272
Synchronized< detail::SingletonVaultState, SharedMutexReadPriority > state_
Definition: Singleton.h:557