Schedule destroyInstances only when first singleton is created
authorAndrii Grynenko <andrii@fb.com>
Tue, 14 Oct 2014 03:08:15 +0000 (20:08 -0700)
committerdcsommer <dcsommer@fb.com>
Fri, 17 Oct 2014 18:43:57 +0000 (11:43 -0700)
Summary:
Right now destroyInstances is scheduled when SingletonVault is requested. This may change singleton destruction order (folly::Singleton-managed vs unmanaged singletons) when new singleton is registered with folly::Singleton (no matter if it is even used).
This diff changes it to be more stable.

Test Plan: servicerouter unittests

Reviewed By: chip@fb.com

Subscribers: njormrod, mshneer

FB internal diff: D1615213

Tasks: 5353022

folly/experimental/Singleton.cpp
folly/experimental/Singleton.h

index 27573fd2ecfaed1bd5e083dca61c1f2552f08638..5c1e650ebb665e7c5870148967e56f3ed9eea679 100644 (file)
@@ -73,16 +73,22 @@ void SingletonVault::reenableInstances() {
 
 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;
 }
 
 }
index 99b633f0fe55c56255d1de536462a3b71d2a73a2..eba1c57f9aee683f5496d64daa41564ef0693ab5 100644 (file)
@@ -329,6 +329,16 @@ class SingletonVault {
     SingletonEntry(SingletonEntry&&) = delete;
   };
 
+  // Initializes static object, which calls destroyInstances on destruction.
+  // Used to have better deletion ordering with singleton not managed by
+  // folly::Singleton. The desruction will happen in the following order:
+  // 1. Singletons, not managed by folly::Singleton, which were created after
+  //    any of the singletons managed by folly::Singleton was requested.
+  // 2. All singletons managed by folly::Singleton
+  // 3. Singletons, not managed by folly::Singleton, which were created before
+  //    any of the singletons managed by folly::Singleton was requested.
+  static void scheduleDestroyInstances();
+
   SingletonEntry* get_entry(detail::TypeDescriptor type) {
     RWSpinLock::ReadHolder rh(&mutex_);
 
@@ -375,6 +385,13 @@ class SingletonVault {
       entry_lock.unlock();
       // Can't use make_shared -- no support for a custom deleter, sadly.
       auto instance = std::shared_ptr<void>(entry->create(), entry->teardown);
+
+      // We should schedule destroyInstances() only after the singleton was
+      // created. This will ensure it will be destroyed before singletons,
+      // not managed by folly::Singleton, which were initialized in its
+      // constructor
+      scheduleDestroyInstances();
+
       entry_lock.lock();
 
       CHECK(entry->state == SingletonEntryState::BeingBorn);