get_fast/get_weak_fast API for folly::Singleton
[folly.git] / folly / experimental / Singleton.cpp
index 4cfacd5a473be3b2a54a3d86cbb8017293852051..68f531a6b778b91fc8bdc44a21a14b8d661d016e 100644 (file)
@@ -23,6 +23,15 @@ namespace folly {
 SingletonVault::~SingletonVault() { destroyInstances(); }
 
 void SingletonVault::destroyInstances() {
+  RWSpinLock::WriteHolder state_wh(&stateMutex_);
+
+  if (state_ == SingletonVaultState::Quiescing) {
+    return;
+  }
+  state_ = SingletonVaultState::Quiescing;
+
+  RWSpinLock::ReadHolder state_rh(std::move(state_wh));
+
   {
     RWSpinLock::ReadHolder rh(&mutex_);
 
@@ -31,20 +40,7 @@ void SingletonVault::destroyInstances() {
     for (auto type_iter = creation_order_.rbegin();
          type_iter != creation_order_.rend();
          ++type_iter) {
-      auto type = *type_iter;
-      auto it = singletons_.find(type);
-      CHECK(it != singletons_.end());
-      auto& entry = it->second;
-      std::lock_guard<std::mutex> entry_guard(entry->mutex);
-      if (entry->instance.use_count() > 1) {
-        LOG(ERROR) << "Singleton of type " << type.name() << " has a living "
-                   << "reference at destroyInstances time; beware! Raw pointer "
-                   << "is " << entry->instance.get() << " with use_count of "
-                   << entry->instance.use_count();
-      }
-      entry->instance.reset();
-      entry->state = SingletonEntryState::Dead;
-      entry->state_condvar.notify_all();
+      destroyInstance(singletons_.find(*type_iter));
     }
   }
 
@@ -54,18 +50,49 @@ void SingletonVault::destroyInstances() {
   }
 }
 
+/* Destroy and clean-up one singleton. Must be invoked while holding
+ * a read lock on mutex_.
+ * @param typeDescriptor - the type key for the removed singleton.
+ */
+void SingletonVault::destroyInstance(SingletonMap::iterator entry_it) {
+  const auto& type = entry_it->first;
+  auto& entry = *(entry_it->second);
+  if (entry.instance.use_count() > 1) {
+    LOG(ERROR) << "Singleton of type " << type.name() << " has a living "
+               << "reference at destroyInstances time; beware! Raw pointer "
+               << "is " << entry.instance.get() << " with use_count of "
+               << entry.instance.use_count();
+  }
+  entry.state = detail::SingletonEntryState::Dead;
+  entry.instance.reset();
+}
+
+void SingletonVault::reenableInstances() {
+  RWSpinLock::WriteHolder state_wh(&stateMutex_);
+
+  stateCheck(SingletonVaultState::Quiescing);
+
+  state_ = SingletonVaultState::Running;
+}
+
 SingletonVault* SingletonVault::singleton() {
   static SingletonVault* vault = new SingletonVault();
+  return vault;
+}
 
+void SingletonVault::scheduleDestroyInstances() {
   class SingletonVaultDestructor {
    public:
     ~SingletonVaultDestructor() {
       SingletonVault::singleton()->destroyInstances();
     }
   };
-  static SingletonVaultDestructor singletonVaultDestructor;
 
-  return vault;
+  // Here we intialize a singleton, which calls destroyInstances in its
+  // destructor. Because of singleton destruction order - it will be destroyed
+  // before all the singletons, which were initialized before it and after all
+  // the singletons initialized after it.
+  static SingletonVaultDestructor singletonVaultDestructor;
 }
 
 }