3848ab449145d56db1633c1c9e50aa2d7dd3a3eb
[folly.git] / folly / Singleton-inl.h
1 /*
2  * Copyright 2015 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>
23 SingletonHolder<T>& SingletonHolder<T>::singleton() {
24   static auto entry = new SingletonHolder<T>(
25     {typeid(T), typeid(Tag)},
26     *SingletonVault::singleton<VaultTag>());
27   return *entry;
28 }
29
30 template <typename T>
31 void SingletonHolder<T>::registerSingleton(CreateFunc c, TeardownFunc t) {
32   std::lock_guard<std::mutex> entry_lock(mutex_);
33
34   if (state_ != SingletonHolderState::NotRegistered) {
35     LOG(FATAL) << "Double registration of singleton: " << type_.name();
36   }
37
38   create_ = std::move(c);
39   teardown_ = std::move(t);
40
41   state_ = SingletonHolderState::Dead;
42 }
43
44 template <typename T>
45 void SingletonHolder<T>::registerSingletonMock(CreateFunc c, TeardownFunc t) {
46   if (state_ == SingletonHolderState::NotRegistered) {
47     LOG(FATAL)
48         << "Registering mock before singleton was registered: " << type_.name();
49   }
50   destroyInstance();
51
52   std::lock_guard<std::mutex> entry_lock(mutex_);
53
54   create_ = std::move(c);
55   teardown_ = std::move(t);
56 }
57
58 template <typename T>
59 T* SingletonHolder<T>::get() {
60   if (LIKELY(state_ == SingletonHolderState::Living)) {
61     return instance_ptr_;
62   }
63   createInstance();
64
65   if (instance_weak_.expired()) {
66     throw std::runtime_error(
67         "Raw pointer to a singleton requested after its destruction."
68         " Singleton type is: " +
69         type_.name());
70   }
71
72   return instance_ptr_;
73 }
74
75 template <typename T>
76 std::weak_ptr<T> SingletonHolder<T>::get_weak() {
77   if (UNLIKELY(state_ != SingletonHolderState::Living)) {
78     createInstance();
79   }
80
81   return instance_weak_;
82 }
83
84 template <typename T>
85 TypeDescriptor SingletonHolder<T>::type() {
86   return type_;
87 }
88
89 template <typename T>
90 bool SingletonHolder<T>::hasLiveInstance() {
91   return !instance_weak_.expired();
92 }
93
94 template <typename T>
95 void SingletonHolder<T>::destroyInstance() {
96   state_ = SingletonHolderState::Dead;
97   instance_.reset();
98   if (destroy_baton_) {
99     auto wait_result = destroy_baton_->timed_wait(
100       std::chrono::steady_clock::now() + kDestroyWaitTime);
101     if (!wait_result) {
102       print_destructor_stack_trace_->store(true);
103       LOG(ERROR) << "Singleton of type " << type_.name() << " has a "
104                  << "living reference at destroyInstances time; beware! Raw "
105                  << "pointer is " << instance_ptr_ << ". It is very likely "
106                  << "that some other singleton is holding a shared_ptr to it. "
107                  << "Make sure dependencies between these singletons are "
108                  << "properly defined.";
109     }
110   }
111 }
112
113 template <typename T>
114 SingletonHolder<T>::SingletonHolder(TypeDescriptor type__,
115                                     SingletonVault& vault) :
116     type_(type__), vault_(vault) {
117 }
118
119 template <typename T>
120 void SingletonHolder<T>::createInstance() {
121   // There's no synchronization here, so we may not see the current value
122   // for creating_thread if it was set by other thread, but we only care about
123   // it if it was set by current thread anyways.
124   if (creating_thread_ == std::this_thread::get_id()) {
125     LOG(FATAL) << "circular singleton dependency: " << type_.name();
126   }
127
128   std::lock_guard<std::mutex> entry_lock(mutex_);
129   if (state_ == SingletonHolderState::Living) {
130     return;
131   }
132   if (state_ == SingletonHolderState::NotRegistered) {
133     auto ptr = SingletonVault::stackTraceGetter().load();
134     LOG(FATAL) << "Creating instance for unregistered singleton: "
135                << type_.name() << "\n"
136                << "Stacktrace:"
137                << "\n" << (ptr ? (*ptr)() : "(not available)");
138   }
139
140   if (state_ == SingletonHolderState::Living) {
141     return;
142   }
143
144   SCOPE_EXIT {
145     // Clean up creator thread when complete, and also, in case of errors here,
146     // so that subsequent attempts don't think this is still in the process of
147     // being built.
148     creating_thread_ = std::thread::id();
149   };
150
151   creating_thread_ = std::this_thread::get_id();
152
153   RWSpinLock::ReadHolder rh(&vault_.stateMutex_);
154   if (vault_.state_ == SingletonVault::SingletonVaultState::Quiescing) {
155     return;
156   }
157
158   auto destroy_baton = std::make_shared<folly::Baton<>>();
159   auto print_destructor_stack_trace =
160     std::make_shared<std::atomic<bool>>(false);
161   auto teardown = teardown_;
162   auto type_name = type_.name();
163
164   // Can't use make_shared -- no support for a custom deleter, sadly.
165   instance_ = std::shared_ptr<T>(
166     create_(),
167     [destroy_baton, print_destructor_stack_trace, teardown, type_name]
168     (T* instance_ptr) mutable {
169       teardown(instance_ptr);
170       destroy_baton->post();
171       if (print_destructor_stack_trace->load()) {
172         std::string output = "Singleton " + type_name + " was destroyed.\n";
173
174         auto stack_trace_getter = SingletonVault::stackTraceGetter().load();
175         auto stack_trace = stack_trace_getter ? stack_trace_getter() : "";
176         if (stack_trace.empty()) {
177           output += "Failed to get destructor stack trace.";
178         } else {
179           output += "Destructor stack trace:\n";
180           output += stack_trace;
181         }
182
183         LOG(ERROR) << output;
184       }
185     });
186
187   // We should schedule destroyInstances() only after the singleton was
188   // created. This will ensure it will be destroyed before singletons,
189   // not managed by folly::Singleton, which were initialized in its
190   // constructor
191   SingletonVault::scheduleDestroyInstances();
192
193   instance_weak_ = instance_;
194   instance_ptr_ = instance_.get();
195   destroy_baton_ = std::move(destroy_baton);
196   print_destructor_stack_trace_ = std::move(print_destructor_stack_trace);
197
198   // This has to be the last step, because once state is Living other threads
199   // may access instance and instance_weak w/o synchronization.
200   state_.store(SingletonHolderState::Living);
201
202   {
203     RWSpinLock::WriteHolder wh(&vault_.mutex_);
204     vault_.creation_order_.push_back(type_);
205   }
206 }
207
208 }
209
210 }