Singleton-inl.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  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. namespace folly {
  17. namespace detail {
  18. template <typename T>
  19. template <typename Tag, typename VaultTag>
  20. SingletonHolder<T>& SingletonHolder<T>::singleton() {
  21. /* library-local */ static auto entry =
  22. createGlobal<SingletonHolder<T>, std::pair<Tag, VaultTag>>([]() {
  23. return new SingletonHolder<T>(
  24. {typeid(T), typeid(Tag)}, *SingletonVault::singleton<VaultTag>());
  25. });
  26. return *entry;
  27. }
  28. [[noreturn]] void singletonWarnDoubleRegistrationAndAbort(
  29. const TypeDescriptor& type);
  30. template <typename T>
  31. void SingletonHolder<T>::registerSingleton(CreateFunc c, TeardownFunc t) {
  32. std::lock_guard<std::mutex> entry_lock(mutex_);
  33. if (state_ != SingletonHolderState::NotRegistered) {
  34. /* Possible causes:
  35. *
  36. * You have two instances of the same
  37. * folly::Singleton<Class>. Probably because you define the
  38. * singleton in a header included in multiple places? In general,
  39. * folly::Singleton shouldn't be in the header, only off in some
  40. * anonymous namespace in a cpp file. Code needing the singleton
  41. * will find it when that code references folly::Singleton<Class>.
  42. *
  43. * Alternatively, you could have 2 singletons with the same type
  44. * defined with a different name in a .cpp (source) file. For
  45. * example:
  46. *
  47. * Singleton<int> a([] { return new int(3); });
  48. * Singleton<int> b([] { return new int(4); });
  49. *
  50. */
  51. singletonWarnDoubleRegistrationAndAbort(type());
  52. }
  53. create_ = std::move(c);
  54. teardown_ = std::move(t);
  55. state_ = SingletonHolderState::Dead;
  56. }
  57. template <typename T>
  58. void SingletonHolder<T>::registerSingletonMock(CreateFunc c, TeardownFunc t) {
  59. if (state_ == SingletonHolderState::NotRegistered) {
  60. detail::singletonWarnRegisterMockEarlyAndAbort(type());
  61. }
  62. if (state_ == SingletonHolderState::Living) {
  63. destroyInstance();
  64. }
  65. {
  66. auto creationOrder = vault_.creationOrder_.wlock();
  67. auto it = std::find(creationOrder->begin(), creationOrder->end(), type());
  68. if (it != creationOrder->end()) {
  69. creationOrder->erase(it);
  70. }
  71. }
  72. std::lock_guard<std::mutex> entry_lock(mutex_);
  73. create_ = std::move(c);
  74. teardown_ = std::move(t);
  75. }
  76. template <typename T>
  77. T* SingletonHolder<T>::get() {
  78. if (LIKELY(
  79. state_.load(std::memory_order_acquire) ==
  80. SingletonHolderState::Living)) {
  81. return instance_ptr_;
  82. }
  83. createInstance();
  84. if (instance_weak_.expired()) {
  85. detail::singletonThrowGetInvokedAfterDestruction(type());
  86. }
  87. return instance_ptr_;
  88. }
  89. template <typename T>
  90. std::weak_ptr<T> SingletonHolder<T>::get_weak() {
  91. if (UNLIKELY(
  92. state_.load(std::memory_order_acquire) !=
  93. SingletonHolderState::Living)) {
  94. createInstance();
  95. }
  96. return instance_weak_;
  97. }
  98. template <typename T>
  99. std::shared_ptr<T> SingletonHolder<T>::try_get() {
  100. if (UNLIKELY(
  101. state_.load(std::memory_order_acquire) !=
  102. SingletonHolderState::Living)) {
  103. createInstance();
  104. }
  105. return instance_weak_.lock();
  106. }
  107. template <typename T>
  108. folly::ReadMostlySharedPtr<T> SingletonHolder<T>::try_get_fast() {
  109. if (UNLIKELY(
  110. state_.load(std::memory_order_acquire) !=
  111. SingletonHolderState::Living)) {
  112. createInstance();
  113. }
  114. return instance_weak_fast_.lock();
  115. }
  116. template <typename T>
  117. void SingletonHolder<T>::vivify() {
  118. if (UNLIKELY(
  119. state_.load(std::memory_order_relaxed) !=
  120. SingletonHolderState::Living)) {
  121. createInstance();
  122. }
  123. }
  124. template <typename T>
  125. bool SingletonHolder<T>::hasLiveInstance() {
  126. return !instance_weak_.expired();
  127. }
  128. template <typename T>
  129. void SingletonHolder<T>::preDestroyInstance(
  130. ReadMostlyMainPtrDeleter<>& deleter) {
  131. instance_copy_ = instance_;
  132. deleter.add(std::move(instance_));
  133. }
  134. template <typename T>
  135. void SingletonHolder<T>::destroyInstance() {
  136. state_ = SingletonHolderState::Dead;
  137. instance_.reset();
  138. instance_copy_.reset();
  139. if (destroy_baton_) {
  140. constexpr std::chrono::seconds kDestroyWaitTime{5};
  141. auto last_reference_released =
  142. destroy_baton_->try_wait_for(kDestroyWaitTime);
  143. if (last_reference_released) {
  144. teardown_(instance_ptr_);
  145. } else {
  146. print_destructor_stack_trace_->store(true);
  147. detail::singletonWarnDestroyInstanceLeak(type(), instance_ptr_);
  148. }
  149. }
  150. }
  151. template <typename T>
  152. SingletonHolder<T>::SingletonHolder(
  153. TypeDescriptor typeDesc,
  154. SingletonVault& vault)
  155. : SingletonHolderBase(typeDesc), vault_(vault) {}
  156. template <typename T>
  157. bool SingletonHolder<T>::creationStarted() {
  158. // If alive, then creation was of course started.
  159. // This is flipped after creating_thread_ was set, and before it was reset.
  160. if (state_.load(std::memory_order_acquire) == SingletonHolderState::Living) {
  161. return true;
  162. }
  163. // Not yet built. Is it currently in progress?
  164. if (creating_thread_.load(std::memory_order_acquire) != std::thread::id()) {
  165. return true;
  166. }
  167. return false;
  168. }
  169. template <typename T>
  170. void SingletonHolder<T>::createInstance() {
  171. if (creating_thread_.load(std::memory_order_acquire) ==
  172. std::this_thread::get_id()) {
  173. detail::singletonWarnCreateCircularDependencyAndAbort(type());
  174. }
  175. std::lock_guard<std::mutex> entry_lock(mutex_);
  176. if (state_.load(std::memory_order_acquire) == SingletonHolderState::Living) {
  177. return;
  178. }
  179. if (state_.load(std::memory_order_acquire) ==
  180. SingletonHolderState::NotRegistered) {
  181. detail::singletonWarnCreateUnregisteredAndAbort(type());
  182. }
  183. if (state_.load(std::memory_order_acquire) == SingletonHolderState::Living) {
  184. return;
  185. }
  186. SCOPE_EXIT {
  187. // Clean up creator thread when complete, and also, in case of errors here,
  188. // so that subsequent attempts don't think this is still in the process of
  189. // being built.
  190. creating_thread_.store(std::thread::id(), std::memory_order_release);
  191. };
  192. creating_thread_.store(std::this_thread::get_id(), std::memory_order_release);
  193. auto state = vault_.state_.rlock();
  194. if (vault_.type_ != SingletonVault::Type::Relaxed &&
  195. !state->registrationComplete) {
  196. detail::singletonWarnCreateBeforeRegistrationCompleteAndAbort(type());
  197. }
  198. if (state->state == detail::SingletonVaultState::Type::Quiescing) {
  199. return;
  200. }
  201. auto destroy_baton = std::make_shared<folly::Baton<>>();
  202. auto print_destructor_stack_trace =
  203. std::make_shared<std::atomic<bool>>(false);
  204. // Can't use make_shared -- no support for a custom deleter, sadly.
  205. std::shared_ptr<T> instance(
  206. create_(),
  207. [destroy_baton, print_destructor_stack_trace, type = type()](T*) mutable {
  208. destroy_baton->post();
  209. if (print_destructor_stack_trace->load()) {
  210. detail::singletonPrintDestructionStackTrace(type);
  211. }
  212. });
  213. // We should schedule destroyInstances() only after the singleton was
  214. // created. This will ensure it will be destroyed before singletons,
  215. // not managed by folly::Singleton, which were initialized in its
  216. // constructor
  217. SingletonVault::scheduleDestroyInstances();
  218. instance_weak_ = instance;
  219. instance_ptr_ = instance.get();
  220. instance_.reset(std::move(instance));
  221. instance_weak_fast_ = instance_;
  222. destroy_baton_ = std::move(destroy_baton);
  223. print_destructor_stack_trace_ = std::move(print_destructor_stack_trace);
  224. // This has to be the last step, because once state is Living other threads
  225. // may access instance and instance_weak w/o synchronization.
  226. state_.store(SingletonHolderState::Living, std::memory_order_release);
  227. vault_.creationOrder_.wlock()->push_back(type());
  228. }
  229. } // namespace detail
  230. } // namespace folly