Simplify some checks by using __CLANG_PREREQ
[folly.git] / folly / Singleton.cpp
index 52f3957f03719fd6a6fc38c6f7fbd92670cd0d06..c2a8afdef314714f4fd4d33236048291503e2447 100644 (file)
 
 #include <folly/Singleton.h>
 
+#include <atomic>
 #include <string>
 
+#include <folly/ScopeGuard.h>
+
 namespace folly {
 
 namespace detail {
@@ -128,7 +131,7 @@ void SingletonVault::doEagerInit() {
   }
 }
 
-void SingletonVault::doEagerInitVia(Executor* exe) {
+void SingletonVault::doEagerInitVia(Executor& exe, folly::Baton<>* done) {
   std::unordered_set<detail::SingletonHolderBase*> singletonSet;
   {
     RWSpinLock::ReadHolder rh(&stateMutex_);
@@ -139,8 +142,25 @@ void SingletonVault::doEagerInitVia(Executor* exe) {
     singletonSet = eagerInitSingletons_; // copy set of pointers
   }
 
+  auto countdown = std::make_shared<std::atomic<size_t>>(singletonSet.size());
   for (auto* single : singletonSet) {
-    exe->add([single] {
+    // countdown is retained by shared_ptr, and will be alive until last lambda
+    // is done.  notifyBaton is provided by the caller, and expected to remain
+    // present (if it's non-nullptr).  singletonSet can go out of scope but
+    // its values, which are SingletonHolderBase pointers, are alive as long as
+    // SingletonVault is not being destroyed.
+    exe.add([=] {
+      // decrement counter and notify if requested, whether initialization
+      // was successful, was skipped (already initialized), or exception thrown.
+      SCOPE_EXIT {
+        if (--(*countdown) == 0) {
+          if (done != nullptr) {
+            done->post();
+          }
+        }
+      };
+      // if initialization is in progress in another thread, don't try to init
+      // here.  Otherwise the current thread will block on 'createInstance'.
       if (!single->creationStarted()) {
         single->createInstance();
       }