Move Singleton out of folly/experimental into folly/
authorAndrii Grynenko <andrii@fb.com>
Wed, 22 Apr 2015 02:37:08 +0000 (19:37 -0700)
committerAndrii Grynenko <andrii@fb.com>
Wed, 29 Apr 2015 22:57:37 +0000 (15:57 -0700)
Test Plan: contbuild

Reviewed By: chip@fb.com

Subscribers: wormhole-diffs@, trunkagent, hphp-diffs@, jan, simpkins, configerator-diffs@, fbcode-common-diffs@, chaoyc, bill, search-fbcode-diffs@, agallagher, nli, marcelo, ckwalsh, mcduff, hitesh, mshneer, unicorn-diffs@, vighnesh, fugalh, andreib, bmatheny, tw-eng@, tanmoyc, zhuohuang, rvm4, antonl, acampi, alikhtarov, hdoshi, rsethi, panin, folly-diffs@, lins, kennyyu, hannesr, jsedgwick, dominik, yfeldblum, songhao, raghavpi, labrams, lyang, chalfant, #preselection, macsyz, nimishshah

FB internal diff: D2012267

Tasks: 5676394

Signature: t1:2012267:1430334667:eaad0262b35ffbfae86df5bdb45bf057ac62c51b

20 files changed:
folly/Makefile.am
folly/Singleton-inl.h [new file with mode: 0644]
folly/Singleton.cpp [new file with mode: 0644]
folly/Singleton.h [new file with mode: 0644]
folly/SingletonStackTrace.cpp [new file with mode: 0644]
folly/SingletonVault_c.cpp [new file with mode: 0644]
folly/SingletonVault_c.h [new file with mode: 0644]
folly/experimental/JSONSchema.cpp
folly/experimental/Singleton-inl.h [deleted file]
folly/experimental/Singleton.cpp [deleted file]
folly/experimental/Singleton.h [deleted file]
folly/experimental/SingletonStackTrace.cpp [deleted file]
folly/experimental/SingletonVault_c.cpp [deleted file]
folly/experimental/SingletonVault_c.h [deleted file]
folly/experimental/test/SingletonTest.cpp [deleted file]
folly/experimental/test/SingletonVaultCTest.cpp [deleted file]
folly/futures/detail/ThreadWheelTimekeeper.cpp
folly/test/SingletonTest.cpp [new file with mode: 0644]
folly/test/SingletonVaultCTest.cpp [new file with mode: 0644]
folly/wangle/concurrent/GlobalExecutor.cpp

index 245f4c8991444c288ac20f183b86330acb0243d7..442e070b31e1cbec4832c8957d9fad4bb4ef3086 100644 (file)
@@ -105,8 +105,6 @@ nobase_follyinclude_HEADERS = \
        experimental/JSONSchema.h \
        experimental/Select64.h \
        experimental/SharedMutex.h \
-       experimental/Singleton.h \
-       experimental/Singleton-inl.h \
        experimental/StringKeyedCommon.h \
        experimental/StringKeyedUnorderedMap.h \
        experimental/StringKeyedUnorderedSet.h \
@@ -227,6 +225,8 @@ nobase_follyinclude_HEADERS = \
        Range.h \
        RWSpinLock.h \
        ScopeGuard.h \
+       Singleton.h \
+       Singleton-inl.h \
        SmallLocks.h \
        small_vector.h \
        SocketAddress.h \
@@ -377,6 +377,7 @@ libfolly_la_SOURCES = \
        Random.cpp \
        SafeAssert.cpp \
        SocketAddress.cpp \
+       Singleton.cpp \
        SpookyHashV1.cpp \
        SpookyHashV2.cpp \
        stats/Instantiations.cpp \
@@ -395,7 +396,6 @@ libfolly_la_SOURCES = \
        experimental/JSONSchema.cpp \
        experimental/Select64.cpp \
        experimental/SharedMutex.cpp \
-       experimental/Singleton.cpp \
        experimental/TestUtil.cpp \
        wangle/acceptor/Acceptor.cpp \
        wangle/acceptor/ConnectionManager.cpp \
diff --git a/folly/Singleton-inl.h b/folly/Singleton-inl.h
new file mode 100644 (file)
index 0000000..c853da6
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace folly {
+
+namespace detail {
+
+template <typename T>
+template <typename Tag, typename VaultTag>
+SingletonHolder<T>& SingletonHolder<T>::singleton() {
+  static auto entry = new SingletonHolder<T>(
+    {typeid(T), typeid(Tag)},
+    *SingletonVault::singleton<VaultTag>());
+  return *entry;
+}
+
+template <typename T>
+void SingletonHolder<T>::registerSingleton(CreateFunc c, TeardownFunc t) {
+  std::lock_guard<std::mutex> entry_lock(mutex_);
+
+  if (state_ != SingletonHolderState::NotRegistered) {
+    throw std::logic_error("Double registration");
+  }
+
+  create_ = std::move(c);
+  teardown_ = std::move(t);
+
+  state_ = SingletonHolderState::Dead;
+}
+
+template <typename T>
+void SingletonHolder<T>::registerSingletonMock(CreateFunc c, TeardownFunc t) {
+  if (state_ == SingletonHolderState::NotRegistered) {
+    throw std::logic_error("Registering mock before singleton was registered");
+  }
+  destroyInstance();
+
+  std::lock_guard<std::mutex> entry_lock(mutex_);
+
+  create_ = std::move(c);
+  teardown_ = std::move(t);
+}
+
+template <typename T>
+T* SingletonHolder<T>::get() {
+  if (LIKELY(state_ == SingletonHolderState::Living)) {
+    return instance_ptr_;
+  }
+  createInstance();
+
+  if (instance_weak_.expired()) {
+    throw std::runtime_error(
+      "Raw pointer to a singleton requested after its destruction.");
+  }
+
+  return instance_ptr_;
+}
+
+template <typename T>
+std::weak_ptr<T> SingletonHolder<T>::get_weak() {
+  if (UNLIKELY(state_ != SingletonHolderState::Living)) {
+    createInstance();
+  }
+
+  return instance_weak_;
+}
+
+template <typename T>
+TypeDescriptor SingletonHolder<T>::type() {
+  return type_;
+}
+
+template <typename T>
+bool SingletonHolder<T>::hasLiveInstance() {
+  return !instance_weak_.expired();
+}
+
+template <typename T>
+void SingletonHolder<T>::destroyInstance() {
+  state_ = SingletonHolderState::Dead;
+  instance_.reset();
+  if (destroy_baton_) {
+    auto wait_result = destroy_baton_->timed_wait(
+      std::chrono::steady_clock::now() + kDestroyWaitTime);
+    if (!wait_result) {
+      print_destructor_stack_trace_->store(true);
+      LOG(ERROR) << "Singleton of type " << type_.name() << " has a "
+                 << "living reference at destroyInstances time; beware! Raw "
+                 << "pointer is " << instance_ptr_ << ". It is very likely "
+                 << "that some other singleton is holding a shared_ptr to it. "
+                 << "Make sure dependencies between these singletons are "
+                 << "properly defined.";
+    }
+  }
+}
+
+template <typename T>
+SingletonHolder<T>::SingletonHolder(TypeDescriptor type__,
+                                    SingletonVault& vault) :
+    type_(type__), vault_(vault) {
+}
+
+template <typename T>
+void SingletonHolder<T>::createInstance() {
+  // There's no synchronization here, so we may not see the current value
+  // for creating_thread if it was set by other thread, but we only care about
+  // it if it was set by current thread anyways.
+  if (creating_thread_ == std::this_thread::get_id()) {
+    throw std::out_of_range(std::string("circular singleton dependency: ") +
+                            type_.name());
+  }
+
+  std::lock_guard<std::mutex> entry_lock(mutex_);
+  if (state_ == SingletonHolderState::Living) {
+    return;
+  }
+  if (state_ == SingletonHolderState::NotRegistered) {
+    throw std::out_of_range("Creating instance for unregistered singleton");
+  }
+
+  if (state_ == SingletonHolderState::Living) {
+    return;
+  }
+
+  creating_thread_ = std::this_thread::get_id();
+
+  RWSpinLock::ReadHolder rh(&vault_.stateMutex_);
+  if (vault_.state_ == SingletonVault::SingletonVaultState::Quiescing) {
+    creating_thread_ = std::thread::id();
+    return;
+  }
+
+  auto destroy_baton = std::make_shared<folly::Baton<>>();
+  auto print_destructor_stack_trace =
+    std::make_shared<std::atomic<bool>>(false);
+  auto teardown = teardown_;
+  auto type_name = type_.name();
+
+  // Can't use make_shared -- no support for a custom deleter, sadly.
+  instance_ = std::shared_ptr<T>(
+    create_(),
+    [destroy_baton, print_destructor_stack_trace, teardown, type_name]
+    (T* instance_ptr) mutable {
+      teardown(instance_ptr);
+      destroy_baton->post();
+      if (print_destructor_stack_trace->load()) {
+        std::string output = "Singleton " + type_name + " was destroyed.\n";
+
+        auto stack_trace_getter = SingletonVault::stackTraceGetter().load();
+        auto stack_trace = stack_trace_getter ? stack_trace_getter() : "";
+        if (stack_trace.empty()) {
+          output += "Failed to get destructor stack trace.";
+        } else {
+          output += "Destructor stack trace:\n";
+          output += stack_trace;
+        }
+
+        LOG(ERROR) << output;
+      }
+    });
+
+  // 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
+  SingletonVault::scheduleDestroyInstances();
+
+  instance_weak_ = instance_;
+  instance_ptr_ = instance_.get();
+  creating_thread_ = std::thread::id();
+  destroy_baton_ = std::move(destroy_baton);
+  print_destructor_stack_trace_ = std::move(print_destructor_stack_trace);
+
+  // This has to be the last step, because once state is Living other threads
+  // may access instance and instance_weak w/o synchronization.
+  state_.store(SingletonHolderState::Living);
+
+  {
+    RWSpinLock::WriteHolder wh(&vault_.mutex_);
+    vault_.creation_order_.push_back(type_);
+  }
+}
+
+}
+
+}
diff --git a/folly/Singleton.cpp b/folly/Singleton.cpp
new file mode 100644 (file)
index 0000000..bfd63e5
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/Singleton.h>
+
+#include <string>
+
+namespace folly {
+
+namespace detail {
+
+constexpr std::chrono::seconds SingletonHolderBase::kDestroyWaitTime;
+
+}
+
+namespace {
+
+struct FatalHelper {
+  ~FatalHelper() {
+    if (!leakedSingletons_.empty()) {
+      std::string leakedTypes;
+      for (const auto& singleton : leakedSingletons_) {
+        leakedTypes += "\t" + singleton.name() + "\n";
+      }
+      LOG(DFATAL) << "Singletons of the following types had living references "
+                  << "after destroyInstances was finished:\n" << leakedTypes
+                  << "beware! It is very likely that those singleton instances "
+                  << "are leaked.";
+    }
+  }
+
+  std::vector<detail::TypeDescriptor> leakedSingletons_;
+};
+
+FatalHelper __attribute__ ((__init_priority__ (101))) fatalHelper;
+
+}
+
+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_);
+
+    CHECK_GE(singletons_.size(), creation_order_.size());
+
+    for (auto type_iter = creation_order_.rbegin();
+         type_iter != creation_order_.rend();
+         ++type_iter) {
+      singletons_[*type_iter]->destroyInstance();
+    }
+
+    for (auto& singleton_type: creation_order_) {
+      auto singleton = singletons_[singleton_type];
+      if (!singleton->hasLiveInstance()) {
+        continue;
+      }
+
+      fatalHelper.leakedSingletons_.push_back(singleton->type());
+    }
+  }
+
+  {
+    RWSpinLock::WriteHolder wh(&mutex_);
+    creation_order_.clear();
+  }
+}
+
+void SingletonVault::reenableInstances() {
+  RWSpinLock::WriteHolder state_wh(&stateMutex_);
+
+  stateCheck(SingletonVaultState::Quiescing);
+
+  state_ = SingletonVaultState::Running;
+}
+
+void SingletonVault::scheduleDestroyInstances() {
+  RequestContext::getStaticContext();
+
+  class SingletonVaultDestructor {
+   public:
+    ~SingletonVaultDestructor() {
+      SingletonVault::singleton()->destroyInstances();
+    }
+  };
+
+  // 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;
+}
+
+}
diff --git a/folly/Singleton.h b/folly/Singleton.h
new file mode 100644 (file)
index 0000000..c9868d4
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// SingletonVault - a library to manage the creation and destruction
+// of interdependent singletons.
+//
+// Basic usage of this class is very simple; suppose you have a class
+// called MyExpensiveService, and you only want to construct one (ie,
+// it's a singleton), but you only want to construct it if it is used.
+//
+// In your .h file:
+// class MyExpensiveService { ... };
+//
+// In your .cpp file:
+// namespace { folly::Singleton<MyExpensiveService> the_singleton; }
+//
+// Code can access it via:
+//
+// MyExpensiveService* instance = Singleton<MyExpensiveService>::get();
+// or
+// std::weak_ptr<MyExpensiveService> instance =
+//     Singleton<MyExpensiveService>::get_weak();
+//
+// You also can directly access it by the variable defining the
+// singleton rather than via get(), and even treat that variable like
+// a smart pointer (dereferencing it or using the -> operator).
+//
+// Please note, however, that all non-weak_ptr interfaces are
+// inherently subject to races with destruction.  Use responsibly.
+//
+// The singleton will be created on demand.  If the constructor for
+// MyExpensiveService actually makes use of *another* Singleton, then
+// the right thing will happen -- that other singleton will complete
+// construction before get() returns.  However, in the event of a
+// circular dependency, a runtime error will occur.
+//
+// You can have multiple singletons of the same underlying type, but
+// each must be given a unique tag. If no tag is specified - default tag is used
+//
+// namespace {
+// struct Tag1 {};
+// struct Tag2 {};
+// folly::Singleton<MyExpensiveService> s_default();
+// folly::Singleton<MyExpensiveService, Tag1> s1();
+// folly::Singleton<MyExpensiveService, Tag2> s2();
+// }
+// ...
+// MyExpensiveService* svc_default = s_default.get();
+// MyExpensiveService* svc1 = s1.get();
+// MyExpensiveService* svc2 = s2.get();
+//
+// By default, the singleton instance is constructed via new and
+// deleted via delete, but this is configurable:
+//
+// namespace { folly::Singleton<MyExpensiveService> the_singleton(create,
+//                                                                destroy); }
+//
+// Where create and destroy are functions, Singleton<T>::CreateFunc
+// Singleton<T>::TeardownFunc.
+//
+// What if you need to destroy all of your singletons?  Say, some of
+// your singletons manage threads, but you need to fork?  Or your unit
+// test wants to clean up all global state?  Then you can call
+// SingletonVault::singleton()->destroyInstances(), which invokes the
+// TeardownFunc for each singleton, in the reverse order they were
+// created.  It is your responsibility to ensure your singletons can
+// handle cases where the singletons they depend on go away, however.
+// Singletons won't be recreated after destroyInstances call. If you
+// want to re-enable singleton creation (say after fork was called) you
+// should call reenableInstances.
+
+#pragma once
+#include <folly/Baton.h>
+#include <folly/Exception.h>
+#include <folly/Hash.h>
+#include <folly/Memory.h>
+#include <folly/RWSpinLock.h>
+#include <folly/Demangle.h>
+#include <folly/io/async/Request.h>
+
+#include <algorithm>
+#include <vector>
+#include <mutex>
+#include <thread>
+#include <condition_variable>
+#include <string>
+#include <unordered_map>
+#include <functional>
+#include <typeinfo>
+#include <typeindex>
+
+#include <glog/logging.h>
+
+namespace folly {
+
+// For actual usage, please see the Singleton<T> class at the bottom
+// of this file; that is what you will actually interact with.
+
+// SingletonVault is the class that manages singleton instances.  It
+// is unaware of the underlying types of singletons, and simply
+// manages lifecycles and invokes CreateFunc and TeardownFunc when
+// appropriate.  In general, you won't need to interact with the
+// SingletonVault itself.
+//
+// A vault goes through a few stages of life:
+//
+//   1. Registration phase; singletons can be registered, but no
+//      singleton can be created.
+//   2. registrationComplete() has been called; singletons can no
+//      longer be registered, but they can be created.
+//   3. A vault can return to stage 1 when destroyInstances is called.
+//
+// In general, you don't need to worry about any of the above; just
+// ensure registrationComplete() is called near the top of your main()
+// function, otherwise no singletons can be instantiated.
+
+class SingletonVault;
+
+namespace detail {
+
+struct DefaultTag {};
+
+// A TypeDescriptor is the unique handle for a given singleton.  It is
+// a combinaiton of the type and of the optional name, and is used as
+// a key in unordered_maps.
+class TypeDescriptor {
+ public:
+  TypeDescriptor(const std::type_info& ti,
+                 const std::type_info& tag_ti)
+      : ti_(ti), tag_ti_(tag_ti) {
+  }
+
+  TypeDescriptor(const TypeDescriptor& other)
+      : ti_(other.ti_), tag_ti_(other.tag_ti_) {
+  }
+
+  TypeDescriptor& operator=(const TypeDescriptor& other) {
+    if (this != &other) {
+      ti_ = other.ti_;
+      tag_ti_ = other.tag_ti_;
+    }
+
+    return *this;
+  }
+
+  std::string name() const {
+    auto ret = demangle(ti_.name());
+    if (tag_ti_ != std::type_index(typeid(DefaultTag))) {
+      ret += "/";
+      ret += demangle(tag_ti_.name());
+    }
+    return ret.toStdString();
+  }
+
+  friend class TypeDescriptorHasher;
+
+  bool operator==(const TypeDescriptor& other) const {
+    return ti_ == other.ti_ && tag_ti_ == other.tag_ti_;
+  }
+
+ private:
+  std::type_index ti_;
+  std::type_index tag_ti_;
+};
+
+class TypeDescriptorHasher {
+ public:
+  size_t operator()(const TypeDescriptor& ti) const {
+    return folly::hash::hash_combine(ti.ti_, ti.tag_ti_);
+  }
+};
+
+// This interface is used by SingletonVault to interact with SingletonHolders.
+// Having a non-template interface allows SingletonVault to keep a list of all
+// SingletonHolders.
+class SingletonHolderBase {
+ public:
+  virtual ~SingletonHolderBase() {}
+
+  virtual TypeDescriptor type() = 0;
+  virtual bool hasLiveInstance() = 0;
+  virtual void destroyInstance() = 0;
+
+ protected:
+  static constexpr std::chrono::seconds kDestroyWaitTime{5};
+};
+
+// An actual instance of a singleton, tracking the instance itself,
+// its state as described above, and the create and teardown
+// functions.
+template <typename T>
+struct SingletonHolder : public SingletonHolderBase {
+ public:
+  typedef std::function<void(T*)> TeardownFunc;
+  typedef std::function<T*(void)> CreateFunc;
+
+  template <typename Tag, typename VaultTag>
+  inline static SingletonHolder<T>& singleton();
+
+  inline T* get();
+  inline std::weak_ptr<T> get_weak();
+
+  void registerSingleton(CreateFunc c, TeardownFunc t);
+  void registerSingletonMock(CreateFunc c, TeardownFunc t);
+  virtual TypeDescriptor type();
+  virtual bool hasLiveInstance();
+  virtual void destroyInstance();
+
+ private:
+  SingletonHolder(TypeDescriptor type, SingletonVault& vault);
+
+  void createInstance();
+
+  enum class SingletonHolderState {
+    NotRegistered,
+    Dead,
+    Living,
+  };
+
+  TypeDescriptor type_;
+  SingletonVault& vault_;
+
+  // mutex protects the entire entry during construction/destruction
+  std::mutex mutex_;
+
+  // State of the singleton entry. If state is Living, instance_ptr and
+  // instance_weak can be safely accessed w/o synchronization.
+  std::atomic<SingletonHolderState> state_{SingletonHolderState::NotRegistered};
+
+  // the thread creating the singleton (only valid while creating an object)
+  std::thread::id creating_thread_;
+
+  // The singleton itself and related functions.
+
+  // holds a shared_ptr to singleton instance, set when state is changed from
+  // Dead to Living. Reset when state is changed from Living to Dead.
+  std::shared_ptr<T> instance_;
+  // weak_ptr to the singleton instance, set when state is changed from Dead
+  // to Living. We never write to this object after initialization, so it is
+  // safe to read it from different threads w/o synchronization if we know
+  // that state is set to Living
+  std::weak_ptr<T> instance_weak_;
+  // Time we wait on destroy_baton after releasing Singleton shared_ptr.
+  std::shared_ptr<folly::Baton<>> destroy_baton_;
+  T* instance_ptr_ = nullptr;
+  CreateFunc create_ = nullptr;
+  TeardownFunc teardown_ = nullptr;
+
+  std::shared_ptr<std::atomic<bool>> print_destructor_stack_trace_;
+
+  SingletonHolder(const SingletonHolder&) = delete;
+  SingletonHolder& operator=(const SingletonHolder&) = delete;
+  SingletonHolder& operator=(SingletonHolder&&) = delete;
+  SingletonHolder(SingletonHolder&&) = delete;
+};
+
+}
+
+class SingletonVault {
+ public:
+  enum class Type { Strict, Relaxed };
+
+  explicit SingletonVault(Type type = Type::Relaxed) : type_(type) {}
+
+  // Destructor is only called by unit tests to check destroyInstances.
+  ~SingletonVault();
+
+  typedef std::function<void(void*)> TeardownFunc;
+  typedef std::function<void*(void)> CreateFunc;
+
+  // Ensure that Singleton has not been registered previously and that
+  // registration is not complete. If validations succeeds,
+  // register a singleton of a given type with the create and teardown
+  // functions.
+  void registerSingleton(detail::SingletonHolderBase* entry) {
+    RWSpinLock::ReadHolder rh(&stateMutex_);
+
+    stateCheck(SingletonVaultState::Running);
+
+    if (UNLIKELY(registrationComplete_)) {
+      throw std::logic_error(
+        "Registering singleton after registrationComplete().");
+    }
+
+    RWSpinLock::ReadHolder rhMutex(&mutex_);
+    CHECK_THROW(singletons_.find(entry->type()) == singletons_.end(),
+                std::logic_error);
+
+    RWSpinLock::UpgradedHolder wh(&mutex_);
+    singletons_[entry->type()] = entry;
+  }
+
+  // Mark registration is complete; no more singletons can be
+  // registered at this point.
+  void registrationComplete() {
+    RequestContext::getStaticContext();
+    std::atexit([](){ SingletonVault::singleton()->destroyInstances(); });
+
+    RWSpinLock::WriteHolder wh(&stateMutex_);
+
+    stateCheck(SingletonVaultState::Running);
+
+    if (type_ == Type::Strict) {
+      for (const auto& p: singletons_) {
+        if (p.second->hasLiveInstance()) {
+          throw std::runtime_error(
+            "Singleton created before registration was complete.");
+        }
+      }
+    }
+
+    registrationComplete_ = true;
+  }
+
+  // Destroy all singletons; when complete, the vault can't create
+  // singletons once again until reenableInstances() is called.
+  void destroyInstances();
+
+  // Enable re-creating singletons after destroyInstances() was called.
+  void reenableInstances();
+
+  // For testing; how many registered and living singletons we have.
+  size_t registeredSingletonCount() const {
+    RWSpinLock::ReadHolder rh(&mutex_);
+
+    return singletons_.size();
+  }
+
+  size_t livingSingletonCount() const {
+    RWSpinLock::ReadHolder rh(&mutex_);
+
+    size_t ret = 0;
+    for (const auto& p : singletons_) {
+      if (p.second->hasLiveInstance()) {
+        ++ret;
+      }
+    }
+
+    return ret;
+  }
+
+  // A well-known vault; you can actually have others, but this is the
+  // default.
+  static SingletonVault* singleton() {
+    return singleton<>();
+  }
+
+  // Gets singleton vault for any Tag. Non-default tag should be used in unit
+  // tests only.
+  template <typename VaultTag = detail::DefaultTag>
+  static SingletonVault* singleton() {
+    static SingletonVault* vault = new SingletonVault();
+    return vault;
+  }
+
+  typedef std::string(*StackTraceGetterPtr)();
+
+  static std::atomic<StackTraceGetterPtr>& stackTraceGetter() {
+    static std::atomic<StackTraceGetterPtr> stackTraceGetterPtr;
+    return stackTraceGetterPtr;
+  }
+
+ private:
+  template <typename T>
+  friend class detail::SingletonHolder;
+
+  // The two stages of life for a vault, as mentioned in the class comment.
+  enum class SingletonVaultState {
+    Running,
+    Quiescing,
+  };
+
+  // Each singleton in the vault can be in two states: dead
+  // (registered but never created), living (CreateFunc returned an instance).
+
+  void stateCheck(SingletonVaultState expected,
+                  const char* msg="Unexpected singleton state change") {
+    if (expected != state_) {
+        throw std::logic_error(msg);
+    }
+  }
+
+  // This method only matters if registrationComplete() is never called.
+  // Otherwise destroyInstances is scheduled to be executed atexit.
+  //
+  // 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();
+
+  typedef std::unordered_map<detail::TypeDescriptor,
+                             detail::SingletonHolderBase*,
+                             detail::TypeDescriptorHasher> SingletonMap;
+
+  mutable folly::RWSpinLock mutex_;
+  SingletonMap singletons_;
+  std::vector<detail::TypeDescriptor> creation_order_;
+  SingletonVaultState state_{SingletonVaultState::Running};
+  bool registrationComplete_{false};
+  folly::RWSpinLock stateMutex_;
+  Type type_{Type::Relaxed};
+};
+
+// This is the wrapper class that most users actually interact with.
+// It allows for simple access to registering and instantiating
+// singletons.  Create instances of this class in the global scope of
+// type Singleton<T> to register your singleton for later access via
+// Singleton<T>::get().
+template <typename T,
+          typename Tag = detail::DefaultTag,
+          typename VaultTag = detail::DefaultTag /* for testing */>
+class Singleton {
+ public:
+  typedef std::function<T*(void)> CreateFunc;
+  typedef std::function<void(T*)> TeardownFunc;
+
+  // Generally your program life cycle should be fine with calling
+  // get() repeatedly rather than saving the reference, and then not
+  // call get() during process shutdown.
+  static T* get() {
+    return getEntry().get();
+  }
+
+  // If, however, you do need to hold a reference to the specific
+  // singleton, you can try to do so with a weak_ptr.  Avoid this when
+  // possible but the inability to lock the weak pointer can be a
+  // signal that the vault has been destroyed.
+  static std::weak_ptr<T> get_weak() {
+    return getEntry().get_weak();
+  }
+
+  // Allow the Singleton<t> instance to also retrieve the underlying
+  // singleton, if desired.
+  T& operator*() { return *get(); }
+  T* operator->() { return get(); }
+
+  explicit Singleton(std::nullptr_t _ = nullptr,
+                     Singleton::TeardownFunc t = nullptr) :
+      Singleton ([]() { return new T; }, std::move(t)) {
+  }
+
+  explicit Singleton(Singleton::CreateFunc c,
+                     Singleton::TeardownFunc t = nullptr) {
+    if (c == nullptr) {
+      throw std::logic_error(
+        "nullptr_t should be passed if you want T to be default constructed");
+    }
+
+    auto vault = SingletonVault::singleton<VaultTag>();
+    getEntry().registerSingleton(std::move(c), getTeardownFunc(std::move(t)));
+    vault->registerSingleton(&getEntry());
+  }
+
+  /**
+  * Construct and inject a mock singleton which should be used only from tests.
+  * Unlike regular singletons which are initialized once per process lifetime,
+  * mock singletons live for the duration of a test. This means that one process
+  * running multiple tests can initialize and register the same singleton
+  * multiple times. This functionality should be used only from tests
+  * since it relaxes validation and performance in order to be able to perform
+  * the injection. The returned mock singleton is functionality identical to
+  * regular singletons.
+  */
+  static void make_mock(std::nullptr_t c = nullptr,
+                        typename Singleton<T>::TeardownFunc t = nullptr) {
+    make_mock([]() { return new T; }, t);
+  }
+
+  static void make_mock(CreateFunc c,
+                        typename Singleton<T>::TeardownFunc t = nullptr) {
+    if (c == nullptr) {
+      throw std::logic_error(
+        "nullptr_t should be passed if you want T to be default constructed");
+    }
+
+    auto& entry = getEntry();
+
+    entry.registerSingletonMock(c, getTeardownFunc(t));
+  }
+
+ private:
+  inline static detail::SingletonHolder<T>& getEntry() {
+    return detail::SingletonHolder<T>::template singleton<Tag, VaultTag>();
+  }
+
+  // Construct TeardownFunc.
+  static typename detail::SingletonHolder<T>::TeardownFunc getTeardownFunc(
+      TeardownFunc t)  {
+    if (t == nullptr) {
+      return  [](T* v) { delete v; };
+    } else {
+      return t;
+    }
+  }
+};
+
+}
+
+#include <folly/Singleton-inl.h>
diff --git a/folly/SingletonStackTrace.cpp b/folly/SingletonStackTrace.cpp
new file mode 100644 (file)
index 0000000..3e1f87c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <folly/Singleton.h>
+#include <folly/experimental/symbolizer/Symbolizer.h>
+
+namespace folly {
+
+namespace {
+
+std::string stackTraceGetter() {
+  // Get and symbolize stack trace
+  constexpr size_t kMaxStackTraceDepth = 100;
+  symbolizer::FrameArray<kMaxStackTraceDepth> addresses;
+
+  if (!getStackTraceSafe(addresses)) {
+    return "";
+  } else {
+    constexpr size_t kDefaultCapacity = 500;
+    symbolizer::ElfCache elfCache(kDefaultCapacity);
+
+    symbolizer::Symbolizer symbolizer(&elfCache);
+    symbolizer.symbolize(addresses);
+
+    symbolizer::StringSymbolizePrinter printer;
+    printer.println(addresses);
+    return printer.str();
+  }
+}
+
+struct SetStackTraceGetter {
+  SetStackTraceGetter() {
+    SingletonVault::stackTraceGetter().store(stackTraceGetter);
+  }
+};
+
+SetStackTraceGetter setStackTraceGetter;
+
+}
+
+}
diff --git a/folly/SingletonVault_c.cpp b/folly/SingletonVault_c.cpp
new file mode 100644 (file)
index 0000000..5a6d6d4
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/SingletonVault_c.h>
+#include <folly/Singleton.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SingletonVault_t *SingletonVault_singleton() {
+  return folly::SingletonVault::singleton();
+}
+
+void SingletonVault_registrationComplete(SingletonVault_t *vault) {
+  ((folly::SingletonVault*) vault)->registrationComplete();
+}
+
+void SingletonVault_destroyInstances(SingletonVault_t *vault) {
+  ((folly::SingletonVault*) vault)->destroyInstances();
+}
+
+void SingletonVault_reenableInstances(SingletonVault_t *vault) {
+  ((folly::SingletonVault*) vault)->reenableInstances();
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/folly/SingletonVault_c.h b/folly/SingletonVault_c.h
new file mode 100644 (file)
index 0000000..da3f5af
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Plain C interface to SingletonVault. This facilitates combining programs
+// that cannot use C++ (e.g. programs written in C) with libraries that use
+// Singleton, by allowing the program to perform the required SingletonVault
+// lifecycle calls.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void SingletonVault_t;
+
+SingletonVault_t *SingletonVault_singleton();
+void SingletonVault_registrationComplete(SingletonVault_t *vault);
+void SingletonVault_destroyInstances(SingletonVault_t *vault);
+void SingletonVault_reenableInstances(SingletonVault_t *vault);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
index 6978cf696f9f6610711ff055ccedef9b7dcf781d..5413da3809989c4b4402fa0fdff5003ad3f90594 100644 (file)
@@ -22,7 +22,7 @@
 #include <folly/Memory.h>
 #include <folly/Optional.h>
 #include <folly/String.h>
-#include <folly/experimental/Singleton.h>
+#include <folly/Singleton.h>
 #include <folly/json.h>
 
 namespace folly {
diff --git a/folly/experimental/Singleton-inl.h b/folly/experimental/Singleton-inl.h
deleted file mode 100644 (file)
index c853da6..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-namespace folly {
-
-namespace detail {
-
-template <typename T>
-template <typename Tag, typename VaultTag>
-SingletonHolder<T>& SingletonHolder<T>::singleton() {
-  static auto entry = new SingletonHolder<T>(
-    {typeid(T), typeid(Tag)},
-    *SingletonVault::singleton<VaultTag>());
-  return *entry;
-}
-
-template <typename T>
-void SingletonHolder<T>::registerSingleton(CreateFunc c, TeardownFunc t) {
-  std::lock_guard<std::mutex> entry_lock(mutex_);
-
-  if (state_ != SingletonHolderState::NotRegistered) {
-    throw std::logic_error("Double registration");
-  }
-
-  create_ = std::move(c);
-  teardown_ = std::move(t);
-
-  state_ = SingletonHolderState::Dead;
-}
-
-template <typename T>
-void SingletonHolder<T>::registerSingletonMock(CreateFunc c, TeardownFunc t) {
-  if (state_ == SingletonHolderState::NotRegistered) {
-    throw std::logic_error("Registering mock before singleton was registered");
-  }
-  destroyInstance();
-
-  std::lock_guard<std::mutex> entry_lock(mutex_);
-
-  create_ = std::move(c);
-  teardown_ = std::move(t);
-}
-
-template <typename T>
-T* SingletonHolder<T>::get() {
-  if (LIKELY(state_ == SingletonHolderState::Living)) {
-    return instance_ptr_;
-  }
-  createInstance();
-
-  if (instance_weak_.expired()) {
-    throw std::runtime_error(
-      "Raw pointer to a singleton requested after its destruction.");
-  }
-
-  return instance_ptr_;
-}
-
-template <typename T>
-std::weak_ptr<T> SingletonHolder<T>::get_weak() {
-  if (UNLIKELY(state_ != SingletonHolderState::Living)) {
-    createInstance();
-  }
-
-  return instance_weak_;
-}
-
-template <typename T>
-TypeDescriptor SingletonHolder<T>::type() {
-  return type_;
-}
-
-template <typename T>
-bool SingletonHolder<T>::hasLiveInstance() {
-  return !instance_weak_.expired();
-}
-
-template <typename T>
-void SingletonHolder<T>::destroyInstance() {
-  state_ = SingletonHolderState::Dead;
-  instance_.reset();
-  if (destroy_baton_) {
-    auto wait_result = destroy_baton_->timed_wait(
-      std::chrono::steady_clock::now() + kDestroyWaitTime);
-    if (!wait_result) {
-      print_destructor_stack_trace_->store(true);
-      LOG(ERROR) << "Singleton of type " << type_.name() << " has a "
-                 << "living reference at destroyInstances time; beware! Raw "
-                 << "pointer is " << instance_ptr_ << ". It is very likely "
-                 << "that some other singleton is holding a shared_ptr to it. "
-                 << "Make sure dependencies between these singletons are "
-                 << "properly defined.";
-    }
-  }
-}
-
-template <typename T>
-SingletonHolder<T>::SingletonHolder(TypeDescriptor type__,
-                                    SingletonVault& vault) :
-    type_(type__), vault_(vault) {
-}
-
-template <typename T>
-void SingletonHolder<T>::createInstance() {
-  // There's no synchronization here, so we may not see the current value
-  // for creating_thread if it was set by other thread, but we only care about
-  // it if it was set by current thread anyways.
-  if (creating_thread_ == std::this_thread::get_id()) {
-    throw std::out_of_range(std::string("circular singleton dependency: ") +
-                            type_.name());
-  }
-
-  std::lock_guard<std::mutex> entry_lock(mutex_);
-  if (state_ == SingletonHolderState::Living) {
-    return;
-  }
-  if (state_ == SingletonHolderState::NotRegistered) {
-    throw std::out_of_range("Creating instance for unregistered singleton");
-  }
-
-  if (state_ == SingletonHolderState::Living) {
-    return;
-  }
-
-  creating_thread_ = std::this_thread::get_id();
-
-  RWSpinLock::ReadHolder rh(&vault_.stateMutex_);
-  if (vault_.state_ == SingletonVault::SingletonVaultState::Quiescing) {
-    creating_thread_ = std::thread::id();
-    return;
-  }
-
-  auto destroy_baton = std::make_shared<folly::Baton<>>();
-  auto print_destructor_stack_trace =
-    std::make_shared<std::atomic<bool>>(false);
-  auto teardown = teardown_;
-  auto type_name = type_.name();
-
-  // Can't use make_shared -- no support for a custom deleter, sadly.
-  instance_ = std::shared_ptr<T>(
-    create_(),
-    [destroy_baton, print_destructor_stack_trace, teardown, type_name]
-    (T* instance_ptr) mutable {
-      teardown(instance_ptr);
-      destroy_baton->post();
-      if (print_destructor_stack_trace->load()) {
-        std::string output = "Singleton " + type_name + " was destroyed.\n";
-
-        auto stack_trace_getter = SingletonVault::stackTraceGetter().load();
-        auto stack_trace = stack_trace_getter ? stack_trace_getter() : "";
-        if (stack_trace.empty()) {
-          output += "Failed to get destructor stack trace.";
-        } else {
-          output += "Destructor stack trace:\n";
-          output += stack_trace;
-        }
-
-        LOG(ERROR) << output;
-      }
-    });
-
-  // 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
-  SingletonVault::scheduleDestroyInstances();
-
-  instance_weak_ = instance_;
-  instance_ptr_ = instance_.get();
-  creating_thread_ = std::thread::id();
-  destroy_baton_ = std::move(destroy_baton);
-  print_destructor_stack_trace_ = std::move(print_destructor_stack_trace);
-
-  // This has to be the last step, because once state is Living other threads
-  // may access instance and instance_weak w/o synchronization.
-  state_.store(SingletonHolderState::Living);
-
-  {
-    RWSpinLock::WriteHolder wh(&vault_.mutex_);
-    vault_.creation_order_.push_back(type_);
-  }
-}
-
-}
-
-}
diff --git a/folly/experimental/Singleton.cpp b/folly/experimental/Singleton.cpp
deleted file mode 100644 (file)
index 1c39326..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <folly/experimental/Singleton.h>
-
-#include <string>
-
-namespace folly {
-
-namespace detail {
-
-constexpr std::chrono::seconds SingletonHolderBase::kDestroyWaitTime;
-
-}
-
-namespace {
-
-struct FatalHelper {
-  ~FatalHelper() {
-    if (!leakedSingletons_.empty()) {
-      std::string leakedTypes;
-      for (const auto& singleton : leakedSingletons_) {
-        leakedTypes += "\t" + singleton.name() + "\n";
-      }
-      LOG(DFATAL) << "Singletons of the following types had living references "
-                  << "after destroyInstances was finished:\n" << leakedTypes
-                  << "beware! It is very likely that those singleton instances "
-                  << "are leaked.";
-    }
-  }
-
-  std::vector<detail::TypeDescriptor> leakedSingletons_;
-};
-
-FatalHelper __attribute__ ((__init_priority__ (101))) fatalHelper;
-
-}
-
-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_);
-
-    CHECK_GE(singletons_.size(), creation_order_.size());
-
-    for (auto type_iter = creation_order_.rbegin();
-         type_iter != creation_order_.rend();
-         ++type_iter) {
-      singletons_[*type_iter]->destroyInstance();
-    }
-
-    for (auto& singleton_type: creation_order_) {
-      auto singleton = singletons_[singleton_type];
-      if (!singleton->hasLiveInstance()) {
-        continue;
-      }
-
-      fatalHelper.leakedSingletons_.push_back(singleton->type());
-    }
-  }
-
-  {
-    RWSpinLock::WriteHolder wh(&mutex_);
-    creation_order_.clear();
-  }
-}
-
-void SingletonVault::reenableInstances() {
-  RWSpinLock::WriteHolder state_wh(&stateMutex_);
-
-  stateCheck(SingletonVaultState::Quiescing);
-
-  state_ = SingletonVaultState::Running;
-}
-
-void SingletonVault::scheduleDestroyInstances() {
-  RequestContext::getStaticContext();
-
-  class SingletonVaultDestructor {
-   public:
-    ~SingletonVaultDestructor() {
-      SingletonVault::singleton()->destroyInstances();
-    }
-  };
-
-  // 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;
-}
-
-}
diff --git a/folly/experimental/Singleton.h b/folly/experimental/Singleton.h
deleted file mode 100644 (file)
index 7af1725..0000000
+++ /dev/null
@@ -1,517 +0,0 @@
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// SingletonVault - a library to manage the creation and destruction
-// of interdependent singletons.
-//
-// Basic usage of this class is very simple; suppose you have a class
-// called MyExpensiveService, and you only want to construct one (ie,
-// it's a singleton), but you only want to construct it if it is used.
-//
-// In your .h file:
-// class MyExpensiveService { ... };
-//
-// In your .cpp file:
-// namespace { folly::Singleton<MyExpensiveService> the_singleton; }
-//
-// Code can access it via:
-//
-// MyExpensiveService* instance = Singleton<MyExpensiveService>::get();
-// or
-// std::weak_ptr<MyExpensiveService> instance =
-//     Singleton<MyExpensiveService>::get_weak();
-//
-// You also can directly access it by the variable defining the
-// singleton rather than via get(), and even treat that variable like
-// a smart pointer (dereferencing it or using the -> operator).
-//
-// Please note, however, that all non-weak_ptr interfaces are
-// inherently subject to races with destruction.  Use responsibly.
-//
-// The singleton will be created on demand.  If the constructor for
-// MyExpensiveService actually makes use of *another* Singleton, then
-// the right thing will happen -- that other singleton will complete
-// construction before get() returns.  However, in the event of a
-// circular dependency, a runtime error will occur.
-//
-// You can have multiple singletons of the same underlying type, but
-// each must be given a unique tag. If no tag is specified - default tag is used
-//
-// namespace {
-// struct Tag1 {};
-// struct Tag2 {};
-// folly::Singleton<MyExpensiveService> s_default();
-// folly::Singleton<MyExpensiveService, Tag1> s1();
-// folly::Singleton<MyExpensiveService, Tag2> s2();
-// }
-// ...
-// MyExpensiveService* svc_default = s_default.get();
-// MyExpensiveService* svc1 = s1.get();
-// MyExpensiveService* svc2 = s2.get();
-//
-// By default, the singleton instance is constructed via new and
-// deleted via delete, but this is configurable:
-//
-// namespace { folly::Singleton<MyExpensiveService> the_singleton(create,
-//                                                                destroy); }
-//
-// Where create and destroy are functions, Singleton<T>::CreateFunc
-// Singleton<T>::TeardownFunc.
-//
-// What if you need to destroy all of your singletons?  Say, some of
-// your singletons manage threads, but you need to fork?  Or your unit
-// test wants to clean up all global state?  Then you can call
-// SingletonVault::singleton()->destroyInstances(), which invokes the
-// TeardownFunc for each singleton, in the reverse order they were
-// created.  It is your responsibility to ensure your singletons can
-// handle cases where the singletons they depend on go away, however.
-// Singletons won't be recreated after destroyInstances call. If you
-// want to re-enable singleton creation (say after fork was called) you
-// should call reenableInstances.
-
-#pragma once
-#include <folly/Baton.h>
-#include <folly/Exception.h>
-#include <folly/Hash.h>
-#include <folly/Memory.h>
-#include <folly/RWSpinLock.h>
-#include <folly/Demangle.h>
-#include <folly/io/async/Request.h>
-
-#include <algorithm>
-#include <vector>
-#include <mutex>
-#include <thread>
-#include <condition_variable>
-#include <string>
-#include <unordered_map>
-#include <functional>
-#include <typeinfo>
-#include <typeindex>
-
-#include <glog/logging.h>
-
-namespace folly {
-
-// For actual usage, please see the Singleton<T> class at the bottom
-// of this file; that is what you will actually interact with.
-
-// SingletonVault is the class that manages singleton instances.  It
-// is unaware of the underlying types of singletons, and simply
-// manages lifecycles and invokes CreateFunc and TeardownFunc when
-// appropriate.  In general, you won't need to interact with the
-// SingletonVault itself.
-//
-// A vault goes through a few stages of life:
-//
-//   1. Registration phase; singletons can be registered, but no
-//      singleton can be created.
-//   2. registrationComplete() has been called; singletons can no
-//      longer be registered, but they can be created.
-//   3. A vault can return to stage 1 when destroyInstances is called.
-//
-// In general, you don't need to worry about any of the above; just
-// ensure registrationComplete() is called near the top of your main()
-// function, otherwise no singletons can be instantiated.
-
-class SingletonVault;
-
-namespace detail {
-
-struct DefaultTag {};
-
-// A TypeDescriptor is the unique handle for a given singleton.  It is
-// a combinaiton of the type and of the optional name, and is used as
-// a key in unordered_maps.
-class TypeDescriptor {
- public:
-  TypeDescriptor(const std::type_info& ti,
-                 const std::type_info& tag_ti)
-      : ti_(ti), tag_ti_(tag_ti) {
-  }
-
-  TypeDescriptor(const TypeDescriptor& other)
-      : ti_(other.ti_), tag_ti_(other.tag_ti_) {
-  }
-
-  TypeDescriptor& operator=(const TypeDescriptor& other) {
-    if (this != &other) {
-      ti_ = other.ti_;
-      tag_ti_ = other.tag_ti_;
-    }
-
-    return *this;
-  }
-
-  std::string name() const {
-    auto ret = demangle(ti_.name());
-    if (tag_ti_ != std::type_index(typeid(DefaultTag))) {
-      ret += "/";
-      ret += demangle(tag_ti_.name());
-    }
-    return ret.toStdString();
-  }
-
-  friend class TypeDescriptorHasher;
-
-  bool operator==(const TypeDescriptor& other) const {
-    return ti_ == other.ti_ && tag_ti_ == other.tag_ti_;
-  }
-
- private:
-  std::type_index ti_;
-  std::type_index tag_ti_;
-};
-
-class TypeDescriptorHasher {
- public:
-  size_t operator()(const TypeDescriptor& ti) const {
-    return folly::hash::hash_combine(ti.ti_, ti.tag_ti_);
-  }
-};
-
-// This interface is used by SingletonVault to interact with SingletonHolders.
-// Having a non-template interface allows SingletonVault to keep a list of all
-// SingletonHolders.
-class SingletonHolderBase {
- public:
-  virtual ~SingletonHolderBase() {}
-
-  virtual TypeDescriptor type() = 0;
-  virtual bool hasLiveInstance() = 0;
-  virtual void destroyInstance() = 0;
-
- protected:
-  static constexpr std::chrono::seconds kDestroyWaitTime{5};
-};
-
-// An actual instance of a singleton, tracking the instance itself,
-// its state as described above, and the create and teardown
-// functions.
-template <typename T>
-struct SingletonHolder : public SingletonHolderBase {
- public:
-  typedef std::function<void(T*)> TeardownFunc;
-  typedef std::function<T*(void)> CreateFunc;
-
-  template <typename Tag, typename VaultTag>
-  inline static SingletonHolder<T>& singleton();
-
-  inline T* get();
-  inline std::weak_ptr<T> get_weak();
-
-  void registerSingleton(CreateFunc c, TeardownFunc t);
-  void registerSingletonMock(CreateFunc c, TeardownFunc t);
-  virtual TypeDescriptor type();
-  virtual bool hasLiveInstance();
-  virtual void destroyInstance();
-
- private:
-  SingletonHolder(TypeDescriptor type, SingletonVault& vault);
-
-  void createInstance();
-
-  enum class SingletonHolderState {
-    NotRegistered,
-    Dead,
-    Living,
-  };
-
-  TypeDescriptor type_;
-  SingletonVault& vault_;
-
-  // mutex protects the entire entry during construction/destruction
-  std::mutex mutex_;
-
-  // State of the singleton entry. If state is Living, instance_ptr and
-  // instance_weak can be safely accessed w/o synchronization.
-  std::atomic<SingletonHolderState> state_{SingletonHolderState::NotRegistered};
-
-  // the thread creating the singleton (only valid while creating an object)
-  std::thread::id creating_thread_;
-
-  // The singleton itself and related functions.
-
-  // holds a shared_ptr to singleton instance, set when state is changed from
-  // Dead to Living. Reset when state is changed from Living to Dead.
-  std::shared_ptr<T> instance_;
-  // weak_ptr to the singleton instance, set when state is changed from Dead
-  // to Living. We never write to this object after initialization, so it is
-  // safe to read it from different threads w/o synchronization if we know
-  // that state is set to Living
-  std::weak_ptr<T> instance_weak_;
-  // Time we wait on destroy_baton after releasing Singleton shared_ptr.
-  std::shared_ptr<folly::Baton<>> destroy_baton_;
-  T* instance_ptr_ = nullptr;
-  CreateFunc create_ = nullptr;
-  TeardownFunc teardown_ = nullptr;
-
-  std::shared_ptr<std::atomic<bool>> print_destructor_stack_trace_;
-
-  SingletonHolder(const SingletonHolder&) = delete;
-  SingletonHolder& operator=(const SingletonHolder&) = delete;
-  SingletonHolder& operator=(SingletonHolder&&) = delete;
-  SingletonHolder(SingletonHolder&&) = delete;
-};
-
-}
-
-class SingletonVault {
- public:
-  enum class Type { Strict, Relaxed };
-
-  explicit SingletonVault(Type type = Type::Relaxed) : type_(type) {}
-
-  // Destructor is only called by unit tests to check destroyInstances.
-  ~SingletonVault();
-
-  typedef std::function<void(void*)> TeardownFunc;
-  typedef std::function<void*(void)> CreateFunc;
-
-  // Ensure that Singleton has not been registered previously and that
-  // registration is not complete. If validations succeeds,
-  // register a singleton of a given type with the create and teardown
-  // functions.
-  void registerSingleton(detail::SingletonHolderBase* entry) {
-    RWSpinLock::ReadHolder rh(&stateMutex_);
-
-    stateCheck(SingletonVaultState::Running);
-
-    if (UNLIKELY(registrationComplete_)) {
-      throw std::logic_error(
-        "Registering singleton after registrationComplete().");
-    }
-
-    RWSpinLock::ReadHolder rhMutex(&mutex_);
-    CHECK_THROW(singletons_.find(entry->type()) == singletons_.end(),
-                std::logic_error);
-
-    RWSpinLock::UpgradedHolder wh(&mutex_);
-    singletons_[entry->type()] = entry;
-  }
-
-  // Mark registration is complete; no more singletons can be
-  // registered at this point.
-  void registrationComplete() {
-    RequestContext::getStaticContext();
-    std::atexit([](){ SingletonVault::singleton()->destroyInstances(); });
-
-    RWSpinLock::WriteHolder wh(&stateMutex_);
-
-    stateCheck(SingletonVaultState::Running);
-
-    if (type_ == Type::Strict) {
-      for (const auto& p: singletons_) {
-        if (p.second->hasLiveInstance()) {
-          throw std::runtime_error(
-            "Singleton created before registration was complete.");
-        }
-      }
-    }
-
-    registrationComplete_ = true;
-  }
-
-  // Destroy all singletons; when complete, the vault can't create
-  // singletons once again until reenableInstances() is called.
-  void destroyInstances();
-
-  // Enable re-creating singletons after destroyInstances() was called.
-  void reenableInstances();
-
-  // For testing; how many registered and living singletons we have.
-  size_t registeredSingletonCount() const {
-    RWSpinLock::ReadHolder rh(&mutex_);
-
-    return singletons_.size();
-  }
-
-  size_t livingSingletonCount() const {
-    RWSpinLock::ReadHolder rh(&mutex_);
-
-    size_t ret = 0;
-    for (const auto& p : singletons_) {
-      if (p.second->hasLiveInstance()) {
-        ++ret;
-      }
-    }
-
-    return ret;
-  }
-
-  // A well-known vault; you can actually have others, but this is the
-  // default.
-  static SingletonVault* singleton() {
-    return singleton<>();
-  }
-
-  // Gets singleton vault for any Tag. Non-default tag should be used in unit
-  // tests only.
-  template <typename VaultTag = detail::DefaultTag>
-  static SingletonVault* singleton() {
-    static SingletonVault* vault = new SingletonVault();
-    return vault;
-  }
-
-  typedef std::string(*StackTraceGetterPtr)();
-
-  static std::atomic<StackTraceGetterPtr>& stackTraceGetter() {
-    static std::atomic<StackTraceGetterPtr> stackTraceGetterPtr;
-    return stackTraceGetterPtr;
-  }
-
- private:
-  template <typename T>
-  friend class detail::SingletonHolder;
-
-  // The two stages of life for a vault, as mentioned in the class comment.
-  enum class SingletonVaultState {
-    Running,
-    Quiescing,
-  };
-
-  // Each singleton in the vault can be in two states: dead
-  // (registered but never created), living (CreateFunc returned an instance).
-
-  void stateCheck(SingletonVaultState expected,
-                  const char* msg="Unexpected singleton state change") {
-    if (expected != state_) {
-        throw std::logic_error(msg);
-    }
-  }
-
-  // This method only matters if registrationComplete() is never called.
-  // Otherwise destroyInstances is scheduled to be executed atexit.
-  //
-  // 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();
-
-  typedef std::unordered_map<detail::TypeDescriptor,
-                             detail::SingletonHolderBase*,
-                             detail::TypeDescriptorHasher> SingletonMap;
-
-  mutable folly::RWSpinLock mutex_;
-  SingletonMap singletons_;
-  std::vector<detail::TypeDescriptor> creation_order_;
-  SingletonVaultState state_{SingletonVaultState::Running};
-  bool registrationComplete_{false};
-  folly::RWSpinLock stateMutex_;
-  Type type_{Type::Relaxed};
-};
-
-// This is the wrapper class that most users actually interact with.
-// It allows for simple access to registering and instantiating
-// singletons.  Create instances of this class in the global scope of
-// type Singleton<T> to register your singleton for later access via
-// Singleton<T>::get().
-template <typename T,
-          typename Tag = detail::DefaultTag,
-          typename VaultTag = detail::DefaultTag /* for testing */>
-class Singleton {
- public:
-  typedef std::function<T*(void)> CreateFunc;
-  typedef std::function<void(T*)> TeardownFunc;
-
-  // Generally your program life cycle should be fine with calling
-  // get() repeatedly rather than saving the reference, and then not
-  // call get() during process shutdown.
-  static T* get() {
-    return getEntry().get();
-  }
-
-  // If, however, you do need to hold a reference to the specific
-  // singleton, you can try to do so with a weak_ptr.  Avoid this when
-  // possible but the inability to lock the weak pointer can be a
-  // signal that the vault has been destroyed.
-  static std::weak_ptr<T> get_weak() {
-    return getEntry().get_weak();
-  }
-
-  // Allow the Singleton<t> instance to also retrieve the underlying
-  // singleton, if desired.
-  T& operator*() { return *get(); }
-  T* operator->() { return get(); }
-
-  explicit Singleton(std::nullptr_t _ = nullptr,
-                     Singleton::TeardownFunc t = nullptr) :
-      Singleton ([]() { return new T; }, std::move(t)) {
-  }
-
-  explicit Singleton(Singleton::CreateFunc c,
-                     Singleton::TeardownFunc t = nullptr) {
-    if (c == nullptr) {
-      throw std::logic_error(
-        "nullptr_t should be passed if you want T to be default constructed");
-    }
-
-    auto vault = SingletonVault::singleton<VaultTag>();
-    getEntry().registerSingleton(std::move(c), getTeardownFunc(std::move(t)));
-    vault->registerSingleton(&getEntry());
-  }
-
-  /**
-  * Construct and inject a mock singleton which should be used only from tests.
-  * Unlike regular singletons which are initialized once per process lifetime,
-  * mock singletons live for the duration of a test. This means that one process
-  * running multiple tests can initialize and register the same singleton
-  * multiple times. This functionality should be used only from tests
-  * since it relaxes validation and performance in order to be able to perform
-  * the injection. The returned mock singleton is functionality identical to
-  * regular singletons.
-  */
-  static void make_mock(std::nullptr_t c = nullptr,
-                        typename Singleton<T>::TeardownFunc t = nullptr) {
-    make_mock([]() { return new T; }, t);
-  }
-
-  static void make_mock(CreateFunc c,
-                        typename Singleton<T>::TeardownFunc t = nullptr) {
-    if (c == nullptr) {
-      throw std::logic_error(
-        "nullptr_t should be passed if you want T to be default constructed");
-    }
-
-    auto& entry = getEntry();
-
-    entry.registerSingletonMock(c, getTeardownFunc(t));
-  }
-
- private:
-  inline static detail::SingletonHolder<T>& getEntry() {
-    return detail::SingletonHolder<T>::template singleton<Tag, VaultTag>();
-  }
-
-  // Construct TeardownFunc.
-  static typename detail::SingletonHolder<T>::TeardownFunc getTeardownFunc(
-      TeardownFunc t)  {
-    if (t == nullptr) {
-      return  [](T* v) { delete v; };
-    } else {
-      return t;
-    }
-  }
-};
-
-}
-
-#include <folly/experimental/Singleton-inl.h>
diff --git a/folly/experimental/SingletonStackTrace.cpp b/folly/experimental/SingletonStackTrace.cpp
deleted file mode 100644 (file)
index da53574..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <folly/experimental/Singleton.h>
-#include <folly/experimental/symbolizer/Symbolizer.h>
-
-namespace folly {
-
-namespace {
-
-std::string stackTraceGetter() {
-  // Get and symbolize stack trace
-  constexpr size_t kMaxStackTraceDepth = 100;
-  symbolizer::FrameArray<kMaxStackTraceDepth> addresses;
-
-  if (!getStackTraceSafe(addresses)) {
-    return "";
-  } else {
-    constexpr size_t kDefaultCapacity = 500;
-    symbolizer::ElfCache elfCache(kDefaultCapacity);
-
-    symbolizer::Symbolizer symbolizer(&elfCache);
-    symbolizer.symbolize(addresses);
-
-    symbolizer::StringSymbolizePrinter printer;
-    printer.println(addresses);
-    return printer.str();
-  }
-}
-
-struct SetStackTraceGetter {
-  SetStackTraceGetter() {
-    SingletonVault::stackTraceGetter().store(stackTraceGetter);
-  }
-};
-
-SetStackTraceGetter setStackTraceGetter;
-
-}
-
-}
diff --git a/folly/experimental/SingletonVault_c.cpp b/folly/experimental/SingletonVault_c.cpp
deleted file mode 100644 (file)
index 92ac83f..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <folly/experimental/SingletonVault_c.h>
-#include <folly/experimental/Singleton.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-SingletonVault_t *SingletonVault_singleton() {
-  return folly::SingletonVault::singleton();
-}
-
-void SingletonVault_registrationComplete(SingletonVault_t *vault) {
-  ((folly::SingletonVault*) vault)->registrationComplete();
-}
-
-void SingletonVault_destroyInstances(SingletonVault_t *vault) {
-  ((folly::SingletonVault*) vault)->destroyInstances();
-}
-
-void SingletonVault_reenableInstances(SingletonVault_t *vault) {
-  ((folly::SingletonVault*) vault)->reenableInstances();
-}
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
diff --git a/folly/experimental/SingletonVault_c.h b/folly/experimental/SingletonVault_c.h
deleted file mode 100644 (file)
index da3f5af..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Plain C interface to SingletonVault. This facilitates combining programs
-// that cannot use C++ (e.g. programs written in C) with libraries that use
-// Singleton, by allowing the program to perform the required SingletonVault
-// lifecycle calls.
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void SingletonVault_t;
-
-SingletonVault_t *SingletonVault_singleton();
-void SingletonVault_registrationComplete(SingletonVault_t *vault);
-void SingletonVault_destroyInstances(SingletonVault_t *vault);
-void SingletonVault_reenableInstances(SingletonVault_t *vault);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
diff --git a/folly/experimental/test/SingletonTest.cpp b/folly/experimental/test/SingletonTest.cpp
deleted file mode 100644 (file)
index f29db47..0000000
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <thread>
-
-#include <folly/experimental/Singleton.h>
-
-#include <folly/Benchmark.h>
-
-#include <glog/logging.h>
-#include <gtest/gtest.h>
-
-using namespace folly;
-
-// A simple class that tracks how often instances of the class and
-// subclasses are created, and the ordering.  Also tracks a global
-// unique counter for each object.
-std::atomic<size_t> global_counter(19770326);
-struct Watchdog {
-  static std::vector<Watchdog*> creation_order;
-  Watchdog() : serial_number(++global_counter) {
-    creation_order.push_back(this);
-  }
-
-  ~Watchdog() {
-    if (creation_order.back() != this) {
-      throw std::out_of_range("Watchdog destruction order mismatch");
-    }
-    creation_order.pop_back();
-  }
-
-  const size_t serial_number;
-  size_t livingWatchdogCount() const { return creation_order.size(); }
-
-  Watchdog(const Watchdog&) = delete;
-  Watchdog& operator=(const Watchdog&) = delete;
-  Watchdog(Watchdog&&) noexcept = default;
-};
-
-std::vector<Watchdog*> Watchdog::creation_order;
-
-// Some basic types we use for tracking.
-struct ChildWatchdog : public Watchdog {};
-struct GlobalWatchdog : public Watchdog {};
-struct UnregisteredWatchdog : public Watchdog {};
-
-namespace {
-Singleton<GlobalWatchdog> global_watchdog;
-}
-
-// Test basic global usage (the default way singletons will generally
-// be used).
-TEST(Singleton, BasicGlobalUsage) {
-  EXPECT_EQ(Watchdog::creation_order.size(), 0);
-  EXPECT_EQ(SingletonVault::singleton()->registeredSingletonCount(), 1);
-  EXPECT_EQ(SingletonVault::singleton()->livingSingletonCount(), 0);
-  auto wd1 = Singleton<GlobalWatchdog>::get();
-  EXPECT_NE(wd1, nullptr);
-  EXPECT_EQ(Watchdog::creation_order.size(), 1);
-  auto wd2 = Singleton<GlobalWatchdog>::get();
-  EXPECT_NE(wd2, nullptr);
-  EXPECT_EQ(wd1, wd2);
-  EXPECT_EQ(Watchdog::creation_order.size(), 1);
-  SingletonVault::singleton()->destroyInstances();
-  EXPECT_EQ(Watchdog::creation_order.size(), 0);
-}
-
-TEST(Singleton, MissingSingleton) {
-  EXPECT_THROW([]() { auto u = Singleton<UnregisteredWatchdog>::get(); }(),
-               std::out_of_range);
-}
-
-struct BasicUsageTag {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonBasicUsage = Singleton <T, Tag, BasicUsageTag>;
-
-// Exercise some basic codepaths ensuring registration order and
-// destruction order happen as expected, that instances are created
-// when expected, etc etc.
-TEST(Singleton, BasicUsage) {
-  auto& vault = *SingletonVault::singleton<BasicUsageTag>();
-
-  EXPECT_EQ(vault.registeredSingletonCount(), 0);
-  SingletonBasicUsage<Watchdog> watchdog_singleton;
-  EXPECT_EQ(vault.registeredSingletonCount(), 1);
-
-  SingletonBasicUsage<ChildWatchdog> child_watchdog_singleton;
-  EXPECT_EQ(vault.registeredSingletonCount(), 2);
-
-  vault.registrationComplete();
-
-  Watchdog* s1 = SingletonBasicUsage<Watchdog>::get();
-  EXPECT_NE(s1, nullptr);
-
-  Watchdog* s2 = SingletonBasicUsage<Watchdog>::get();
-  EXPECT_NE(s2, nullptr);
-
-  EXPECT_EQ(s1, s2);
-
-  auto s3 = SingletonBasicUsage<ChildWatchdog>::get();
-  EXPECT_NE(s3, nullptr);
-  EXPECT_NE(s2, s3);
-
-  EXPECT_EQ(vault.registeredSingletonCount(), 2);
-  EXPECT_EQ(vault.livingSingletonCount(), 2);
-
-  vault.destroyInstances();
-  EXPECT_EQ(vault.registeredSingletonCount(), 2);
-  EXPECT_EQ(vault.livingSingletonCount(), 0);
-}
-
-struct DirectUsageTag {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonDirectUsage = Singleton <T, Tag, DirectUsageTag>;
-
-TEST(Singleton, DirectUsage) {
-  auto& vault = *SingletonVault::singleton<DirectUsageTag>();
-
-  EXPECT_EQ(vault.registeredSingletonCount(), 0);
-
-  // Verify we can get to the underlying singletons via directly using
-  // the singleton definition.
-  SingletonDirectUsage<Watchdog> watchdog;
-  struct TestTag {};
-  SingletonDirectUsage<Watchdog, TestTag> named_watchdog;
-  EXPECT_EQ(vault.registeredSingletonCount(), 2);
-  vault.registrationComplete();
-
-  EXPECT_NE(watchdog.get(), nullptr);
-  EXPECT_EQ(watchdog.get(), SingletonDirectUsage<Watchdog>::get());
-  EXPECT_NE(watchdog.get(), named_watchdog.get());
-  EXPECT_EQ(watchdog->livingWatchdogCount(), 2);
-  EXPECT_EQ((*watchdog).livingWatchdogCount(), 2);
-
-  vault.destroyInstances();
-}
-
-struct NamedUsageTag {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonNamedUsage = Singleton <T, Tag, NamedUsageTag>;
-
-TEST(Singleton, NamedUsage) {
-  auto& vault = *SingletonVault::singleton<NamedUsageTag>();
-
-  EXPECT_EQ(vault.registeredSingletonCount(), 0);
-
-  // Define two named Watchdog singletons and one unnamed singleton.
-  struct Watchdog1 {};
-  struct Watchdog2 {};
-  typedef detail::DefaultTag Watchdog3;
-  SingletonNamedUsage<Watchdog, Watchdog1> watchdog1_singleton;
-  EXPECT_EQ(vault.registeredSingletonCount(), 1);
-  SingletonNamedUsage<Watchdog, Watchdog2> watchdog2_singleton;
-  EXPECT_EQ(vault.registeredSingletonCount(), 2);
-  SingletonNamedUsage<Watchdog, Watchdog3> watchdog3_singleton;
-  EXPECT_EQ(vault.registeredSingletonCount(), 3);
-
-  vault.registrationComplete();
-
-  // Verify our three singletons are distinct and non-nullptr.
-  Watchdog* s1 = SingletonNamedUsage<Watchdog, Watchdog1>::get();
-  EXPECT_EQ(s1, watchdog1_singleton.get());
-  Watchdog* s2 = SingletonNamedUsage<Watchdog, Watchdog2>::get();
-  EXPECT_EQ(s2, watchdog2_singleton.get());
-  EXPECT_NE(s1, s2);
-  Watchdog* s3 = SingletonNamedUsage<Watchdog, Watchdog3>::get();
-  EXPECT_EQ(s3, watchdog3_singleton.get());
-  EXPECT_NE(s3, s1);
-  EXPECT_NE(s3, s2);
-
-  // Verify the "default" singleton is the same as the DefaultTag-tagged
-  // singleton.
-  Watchdog* s4 = SingletonNamedUsage<Watchdog>::get();
-  EXPECT_EQ(s4, watchdog3_singleton.get());
-
-  vault.destroyInstances();
-}
-
-struct NaughtyUsageTag {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonNaughtyUsage = Singleton <T, Tag, NaughtyUsageTag>;
-struct NaughtyUsageTag2 {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonNaughtyUsage2 = Singleton <T, Tag, NaughtyUsageTag2>;
-
-// Some pathological cases such as getting unregistered singletons,
-// double registration, etc.
-TEST(Singleton, NaughtyUsage) {
-  auto& vault = *SingletonVault::singleton<NaughtyUsageTag>();
-
-  vault.registrationComplete();
-
-  // Unregistered.
-  EXPECT_THROW(Singleton<Watchdog>::get(), std::out_of_range);
-  EXPECT_THROW(SingletonNaughtyUsage<Watchdog>::get(), std::out_of_range);
-
-  vault.destroyInstances();
-
-  auto& vault2 = *SingletonVault::singleton<NaughtyUsageTag2>();
-
-  EXPECT_THROW(SingletonNaughtyUsage2<Watchdog>::get(), std::logic_error);
-  SingletonNaughtyUsage2<Watchdog> watchdog_singleton;
-  // double registration
-  EXPECT_THROW([]() {
-      SingletonNaughtyUsage2<Watchdog> watchdog_singleton;
-    }(),
-    std::logic_error);
-  vault2.destroyInstances();
-  // double registration after destroy
-  EXPECT_THROW([]() {
-      SingletonNaughtyUsage2<Watchdog> watchdog_singleton;
-    }(),
-    std::logic_error);
-}
-
-struct SharedPtrUsageTag {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonSharedPtrUsage = Singleton <T, Tag, SharedPtrUsageTag>;
-
-TEST(Singleton, SharedPtrUsage) {
-  struct WatchdogHolder {
-    ~WatchdogHolder() {
-      if (watchdog) {
-        LOG(ERROR) << "The following log message with stack trace is expected";
-      }
-    }
-
-    std::shared_ptr<Watchdog> watchdog;
-  };
-
-  auto& vault = *SingletonVault::singleton<SharedPtrUsageTag>();
-
-  EXPECT_EQ(vault.registeredSingletonCount(), 0);
-  SingletonSharedPtrUsage<Watchdog> watchdog_singleton;
-  EXPECT_EQ(vault.registeredSingletonCount(), 1);
-
-  SingletonSharedPtrUsage<ChildWatchdog> child_watchdog_singleton;
-  EXPECT_EQ(vault.registeredSingletonCount(), 2);
-
-  struct ATag {};
-  SingletonSharedPtrUsage<Watchdog, ATag> named_watchdog_singleton;
-
-  SingletonSharedPtrUsage<WatchdogHolder> watchdog_holder_singleton;
-
-  vault.registrationComplete();
-
-  // Initilize holder singleton first, so that it's the last one to be
-  // destroyed.
-  watchdog_holder_singleton.get();
-
-  Watchdog* s1 = SingletonSharedPtrUsage<Watchdog>::get();
-  EXPECT_NE(s1, nullptr);
-
-  Watchdog* s2 = SingletonSharedPtrUsage<Watchdog>::get();
-  EXPECT_NE(s2, nullptr);
-
-  EXPECT_EQ(s1, s2);
-
-  auto weak_s1 = SingletonSharedPtrUsage<Watchdog>::get_weak();
-
-  auto shared_s1 = weak_s1.lock();
-  EXPECT_EQ(shared_s1.get(), s1);
-  EXPECT_EQ(shared_s1.use_count(), 2);
-
-  auto old_serial = shared_s1->serial_number;
-
-  {
-    auto named_weak_s1 =
-      SingletonSharedPtrUsage<Watchdog, ATag>::get_weak();
-    auto locked = named_weak_s1.lock();
-    EXPECT_NE(locked.get(), shared_s1.get());
-  }
-
-  // We should release externally locked shared_ptr, otherwise it will be
-  // considered a leak
-  watchdog_holder_singleton->watchdog = std::move(shared_s1);
-
-  LOG(ERROR) << "The following log message regarding shared_ptr is expected";
-  {
-    auto start_time = std::chrono::steady_clock::now();
-    vault.destroyInstances();
-    auto duration = std::chrono::steady_clock::now() - start_time;
-    EXPECT_TRUE(duration > std::chrono::seconds{4} &&
-                duration < std::chrono::seconds{6});
-  }
-  EXPECT_EQ(vault.registeredSingletonCount(), 4);
-  EXPECT_EQ(vault.livingSingletonCount(), 0);
-
-  EXPECT_TRUE(weak_s1.expired());
-
-  auto empty_s1 = SingletonSharedPtrUsage<Watchdog>::get_weak();
-  EXPECT_FALSE(empty_s1.lock());
-
-  vault.reenableInstances();
-
-  // Singleton should be re-created only after reenableInstances() was called.
-  Watchdog* new_s1 = SingletonSharedPtrUsage<Watchdog>::get();
-  // Track serial number rather than pointer since the memory could be
-  // re-used when we create new_s1.
-  EXPECT_NE(new_s1->serial_number, old_serial);
-
-  auto new_s1_weak = SingletonSharedPtrUsage<Watchdog>::get_weak();
-  auto new_s1_shared = new_s1_weak.lock();
-  std::thread t([new_s1_shared]() mutable {
-      std::this_thread::sleep_for(std::chrono::seconds{2});
-      new_s1_shared.reset();
-    });
-  new_s1_shared.reset();
-  {
-    auto start_time = std::chrono::steady_clock::now();
-    vault.destroyInstances();
-    auto duration = std::chrono::steady_clock::now() - start_time;
-    EXPECT_TRUE(duration > std::chrono::seconds{1} &&
-                duration < std::chrono::seconds{3});
-  }
-  EXPECT_TRUE(new_s1_weak.expired());
-  t.join();
-}
-
-// Some classes to test singleton dependencies.  NeedySingleton has a
-// dependency on NeededSingleton, which happens during its
-// construction.
-struct NeedyTag {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonNeedy = Singleton <T, Tag, NeedyTag>;
-
-struct NeededSingleton {};
-struct NeedySingleton {
-  NeedySingleton() {
-    auto unused = SingletonNeedy<NeededSingleton>::get();
-    EXPECT_NE(unused, nullptr);
-  }
-};
-
-// Ensure circular dependencies fail -- a singleton that needs itself, whoops.
-struct SelfNeedyTag {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonSelfNeedy = Singleton <T, Tag, SelfNeedyTag>;
-
-struct SelfNeedySingleton {
-  SelfNeedySingleton() {
-    auto unused = SingletonSelfNeedy<SelfNeedySingleton>::get();
-    EXPECT_NE(unused, nullptr);
-  }
-};
-
-TEST(Singleton, SingletonDependencies) {
-  SingletonNeedy<NeededSingleton> needed_singleton;
-  SingletonNeedy<NeedySingleton> needy_singleton;
-  auto& needy_vault = *SingletonVault::singleton<NeedyTag>();
-
-  needy_vault.registrationComplete();
-
-  EXPECT_EQ(needy_vault.registeredSingletonCount(), 2);
-  EXPECT_EQ(needy_vault.livingSingletonCount(), 0);
-
-  auto needy = SingletonNeedy<NeedySingleton>::get();
-  EXPECT_EQ(needy_vault.livingSingletonCount(), 2);
-
-  SingletonSelfNeedy<SelfNeedySingleton> self_needy_singleton;
-  auto& self_needy_vault = *SingletonVault::singleton<SelfNeedyTag>();
-
-  self_needy_vault.registrationComplete();
-  EXPECT_THROW([]() {
-      SingletonSelfNeedy<SelfNeedySingleton>::get();
-    }(),
-    std::out_of_range);
-}
-
-// A test to ensure multiple threads contending on singleton creation
-// properly wait for creation rather than thinking it is a circular
-// dependency.
-class Slowpoke : public Watchdog {
- public:
-  Slowpoke() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); }
-};
-
-struct ConcurrencyTag {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonConcurrency = Singleton <T, Tag, ConcurrencyTag>;
-
-TEST(Singleton, SingletonConcurrency) {
-  auto& vault = *SingletonVault::singleton<ConcurrencyTag>();
-  SingletonConcurrency<Slowpoke> slowpoke_singleton;
-  vault.registrationComplete();
-
-  std::mutex gatekeeper;
-  gatekeeper.lock();
-  auto func = [&gatekeeper]() {
-    gatekeeper.lock();
-    gatekeeper.unlock();
-    auto unused = SingletonConcurrency<Slowpoke>::get();
-  };
-
-  EXPECT_EQ(vault.livingSingletonCount(), 0);
-  std::vector<std::thread> threads;
-  for (int i = 0; i < 100; ++i) {
-    threads.emplace_back(func);
-  }
-  // If circular dependency checks fail, the unlock would trigger a
-  // crash.  Instead, it succeeds, and we have exactly one living
-  // singleton.
-  gatekeeper.unlock();
-  for (auto& t : threads) {
-    t.join();
-  }
-  EXPECT_EQ(vault.livingSingletonCount(), 1);
-}
-
-struct ConcurrencyStressTag {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonConcurrencyStress = Singleton <T, Tag, ConcurrencyStressTag>;
-
-TEST(Singleton, SingletonConcurrencyStress) {
-  auto& vault = *SingletonVault::singleton<ConcurrencyStressTag>();
-  SingletonConcurrencyStress<Slowpoke> slowpoke_singleton;
-
-  std::vector<std::thread> ts;
-  for (size_t i = 0; i < 100; ++i) {
-    ts.emplace_back([&]() {
-        slowpoke_singleton.get_weak().lock();
-      });
-  }
-
-  for (size_t i = 0; i < 100; ++i) {
-    std::chrono::milliseconds d(20);
-
-    std::this_thread::sleep_for(d);
-    vault.destroyInstances();
-    std::this_thread::sleep_for(d);
-    vault.destroyInstances();
-  }
-
-  for (auto& t : ts) {
-    t.join();
-  }
-}
-
-// Benchmarking a normal singleton vs a Meyers singleton vs a Folly
-// singleton.  Meyers are insanely fast, but (hopefully) Folly
-// singletons are fast "enough."
-int* getMeyersSingleton() {
-  static auto ret = new int(0);
-  return ret;
-}
-
-int normal_singleton_value = 0;
-int* getNormalSingleton() {
-  doNotOptimizeAway(&normal_singleton_value);
-  return &normal_singleton_value;
-}
-
-struct MockTag {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonMock = Singleton <T, Tag, MockTag>;
-
-// Verify that existing Singleton's can be overridden
-// using the make_mock functionality.
-TEST(Singleton, MockTest) {
-  auto& vault = *SingletonVault::singleton<MockTag>();
-
-  SingletonMock<Watchdog> watchdog_singleton;
-  vault.registrationComplete();
-
-  // Registring singletons after registrationComplete called works
-  // with make_mock (but not with Singleton ctor).
-  EXPECT_EQ(vault.registeredSingletonCount(), 1);
-  int serial_count_first = SingletonMock<Watchdog>::get()->serial_number;
-
-  // Override existing mock using make_mock.
-  SingletonMock<Watchdog>::make_mock();
-
-  EXPECT_EQ(vault.registeredSingletonCount(), 1);
-  int serial_count_mock = SingletonMock<Watchdog>::get()->serial_number;
-
-  // If serial_count value is the same, then singleton was not replaced.
-  EXPECT_NE(serial_count_first, serial_count_mock);
-}
-
-struct BenchmarkSingleton {
-  int val = 0;
-};
-
-BENCHMARK(NormalSingleton, n) {
-  for (size_t i = 0; i < n; ++i) {
-    doNotOptimizeAway(getNormalSingleton());
-  }
-}
-
-BENCHMARK_RELATIVE(MeyersSingleton, n) {
-  for (size_t i = 0; i < n; ++i) {
-    doNotOptimizeAway(getMeyersSingleton());
-  }
-}
-
-struct BenchmarkTag {};
-template <typename T, typename Tag = detail::DefaultTag>
-using SingletonBenchmark = Singleton <T, Tag, BenchmarkTag>;
-
-struct GetTag{};
-struct GetWeakTag{};
-
-SingletonBenchmark<BenchmarkSingleton, GetTag> benchmark_singleton_get;
-SingletonBenchmark<BenchmarkSingleton, GetWeakTag> benchmark_singleton_get_weak;
-
-BENCHMARK_RELATIVE(FollySingleton, n) {
-  for (size_t i = 0; i < n; ++i) {
-    doNotOptimizeAway(SingletonBenchmark<BenchmarkSingleton, GetTag>::get());
-  }
-}
-
-BENCHMARK_RELATIVE(FollySingletonWeak, n) {
-  for (size_t i = 0; i < n; ++i) {
-    SingletonBenchmark<BenchmarkSingleton, GetWeakTag>::get_weak();
-  }
-}
-
-int main(int argc, char* argv[]) {
-  testing::InitGoogleTest(&argc, argv);
-  google::InitGoogleLogging(argv[0]);
-  google::ParseCommandLineFlags(&argc, &argv, true);
-
-  SingletonVault::singleton()->registrationComplete();
-
-  auto ret = RUN_ALL_TESTS();
-  if (!ret) {
-    folly::runBenchmarksOnFlag();
-  }
-  return ret;
-}
diff --git a/folly/experimental/test/SingletonVaultCTest.cpp b/folly/experimental/test/SingletonVaultCTest.cpp
deleted file mode 100644 (file)
index 4fcc1ea..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2015 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <folly/experimental/Singleton.h>
-#include <folly/experimental/SingletonVault_c.h>
-
-#include <gtest/gtest.h>
-
-#include <thread>
-
-__thread long instance_counter_instances = 0;
-
-class InstanceCounter {
- public:
-  InstanceCounter() {
-    instance_counter_instances++;
-  }
-
-  ~InstanceCounter() {
-    instance_counter_instances--;
-  }
-};
-
-TEST(SingletonVault, singletonReturnsSingletonInstance) {
-  SingletonVault_t *c = SingletonVault_singleton();
-  auto *cpp = folly::SingletonVault::singleton();
-  EXPECT_EQ(c, cpp);
-}
-
-struct TestTag {};
-template <typename T, typename Tag = folly::detail::DefaultTag>
-using SingletonTest = folly::Singleton <T, Tag, TestTag>;
-
-TEST(SingletonVault, singletonsAreCreatedAndDestroyed) {
-  auto vault = folly::SingletonVault::singleton<TestTag>();
-  SingletonTest<InstanceCounter> counter_singleton;
-  SingletonVault_registrationComplete((SingletonVault_t*) vault);
-  InstanceCounter *counter = SingletonTest<InstanceCounter>::get();
-  EXPECT_EQ(instance_counter_instances, 1);
-  SingletonVault_destroyInstances((SingletonVault_t*) vault);
-  EXPECT_EQ(instance_counter_instances, 0);
-}
index 51965d10283c18fcc611e911743dd25bf8984f4c..f861af23aa649c329e04441fd073d3c1a2da06e2 100644 (file)
@@ -15,7 +15,7 @@
  */
 #include "ThreadWheelTimekeeper.h"
 
-#include <folly/experimental/Singleton.h>
+#include <folly/Singleton.h>
 #include <folly/futures/Future.h>
 #include <future>
 
diff --git a/folly/test/SingletonTest.cpp b/folly/test/SingletonTest.cpp
new file mode 100644 (file)
index 0000000..19baebb
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <thread>
+
+#include <folly/Singleton.h>
+
+#include <folly/Benchmark.h>
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+using namespace folly;
+
+// A simple class that tracks how often instances of the class and
+// subclasses are created, and the ordering.  Also tracks a global
+// unique counter for each object.
+std::atomic<size_t> global_counter(19770326);
+struct Watchdog {
+  static std::vector<Watchdog*> creation_order;
+  Watchdog() : serial_number(++global_counter) {
+    creation_order.push_back(this);
+  }
+
+  ~Watchdog() {
+    if (creation_order.back() != this) {
+      throw std::out_of_range("Watchdog destruction order mismatch");
+    }
+    creation_order.pop_back();
+  }
+
+  const size_t serial_number;
+  size_t livingWatchdogCount() const { return creation_order.size(); }
+
+  Watchdog(const Watchdog&) = delete;
+  Watchdog& operator=(const Watchdog&) = delete;
+  Watchdog(Watchdog&&) noexcept = default;
+};
+
+std::vector<Watchdog*> Watchdog::creation_order;
+
+// Some basic types we use for tracking.
+struct ChildWatchdog : public Watchdog {};
+struct GlobalWatchdog : public Watchdog {};
+struct UnregisteredWatchdog : public Watchdog {};
+
+namespace {
+Singleton<GlobalWatchdog> global_watchdog;
+}
+
+// Test basic global usage (the default way singletons will generally
+// be used).
+TEST(Singleton, BasicGlobalUsage) {
+  EXPECT_EQ(Watchdog::creation_order.size(), 0);
+  EXPECT_EQ(SingletonVault::singleton()->registeredSingletonCount(), 1);
+  EXPECT_EQ(SingletonVault::singleton()->livingSingletonCount(), 0);
+  auto wd1 = Singleton<GlobalWatchdog>::get();
+  EXPECT_NE(wd1, nullptr);
+  EXPECT_EQ(Watchdog::creation_order.size(), 1);
+  auto wd2 = Singleton<GlobalWatchdog>::get();
+  EXPECT_NE(wd2, nullptr);
+  EXPECT_EQ(wd1, wd2);
+  EXPECT_EQ(Watchdog::creation_order.size(), 1);
+  SingletonVault::singleton()->destroyInstances();
+  EXPECT_EQ(Watchdog::creation_order.size(), 0);
+}
+
+TEST(Singleton, MissingSingleton) {
+  EXPECT_THROW([]() { auto u = Singleton<UnregisteredWatchdog>::get(); }(),
+               std::out_of_range);
+}
+
+struct BasicUsageTag {};
+template <typename T, typename Tag = detail::DefaultTag>
+using SingletonBasicUsage = Singleton <T, Tag, BasicUsageTag>;
+
+// Exercise some basic codepaths ensuring registration order and
+// destruction order happen as expected, that instances are created
+// when expected, etc etc.
+TEST(Singleton, BasicUsage) {
+  auto& vault = *SingletonVault::singleton<BasicUsageTag>();
+
+  EXPECT_EQ(vault.registeredSingletonCount(), 0);
+  SingletonBasicUsage<Watchdog> watchdog_singleton;
+  EXPECT_EQ(vault.registeredSingletonCount(), 1);
+
+  SingletonBasicUsage<ChildWatchdog> child_watchdog_singleton;
+  EXPECT_EQ(vault.registeredSingletonCount(), 2);
+
+  vault.registrationComplete();
+
+  Watchdog* s1 = SingletonBasicUsage<Watchdog>::get();
+  EXPECT_NE(s1, nullptr);
+
+  Watchdog* s2 = SingletonBasicUsage<Watchdog>::get();
+  EXPECT_NE(s2, nullptr);
+
+  EXPECT_EQ(s1, s2);
+
+  auto s3 = SingletonBasicUsage<ChildWatchdog>::get();
+  EXPECT_NE(s3, nullptr);
+  EXPECT_NE(s2, s3);
+
+  EXPECT_EQ(vault.registeredSingletonCount(), 2);
+  EXPECT_EQ(vault.livingSingletonCount(), 2);
+
+  vault.destroyInstances();
+  EXPECT_EQ(vault.registeredSingletonCount(), 2);
+  EXPECT_EQ(vault.livingSingletonCount(), 0);
+}
+
+struct DirectUsageTag {};
+template <typename T, typename Tag = detail::DefaultTag>
+using SingletonDirectUsage = Singleton <T, Tag, DirectUsageTag>;
+
+TEST(Singleton, DirectUsage) {
+  auto& vault = *SingletonVault::singleton<DirectUsageTag>();
+
+  EXPECT_EQ(vault.registeredSingletonCount(), 0);
+
+  // Verify we can get to the underlying singletons via directly using
+  // the singleton definition.
+  SingletonDirectUsage<Watchdog> watchdog;
+  struct TestTag {};
+  SingletonDirectUsage<Watchdog, TestTag> named_watchdog;
+  EXPECT_EQ(vault.registeredSingletonCount(), 2);
+  vault.registrationComplete();
+
+  EXPECT_NE(watchdog.get(), nullptr);
+  EXPECT_EQ(watchdog.get(), SingletonDirectUsage<Watchdog>::get());
+  EXPECT_NE(watchdog.get(), named_watchdog.get());
+  EXPECT_EQ(watchdog->livingWatchdogCount(), 2);
+  EXPECT_EQ((*watchdog).livingWatchdogCount(), 2);
+
+  vault.destroyInstances();
+}
+
+struct NamedUsageTag {};
+template <typename T, typename Tag = detail::DefaultTag>
+using SingletonNamedUsage = Singleton <T, Tag, NamedUsageTag>;
+
+TEST(Singleton, NamedUsage) {
+  auto& vault = *SingletonVault::singleton<NamedUsageTag>();
+
+  EXPECT_EQ(vault.registeredSingletonCount(), 0);
+
+  // Define two named Watchdog singletons and one unnamed singleton.
+  struct Watchdog1 {};
+  struct Watchdog2 {};
+  typedef detail::DefaultTag Watchdog3;
+  SingletonNamedUsage<Watchdog, Watchdog1> watchdog1_singleton;
+  EXPECT_EQ(vault.registeredSingletonCount(), 1);
+  SingletonNamedUsage<Watchdog, Watchdog2> watchdog2_singleton;
+  EXPECT_EQ(vault.registeredSingletonCount(), 2);
+  SingletonNamedUsage<Watchdog, Watchdog3> watchdog3_singleton;
+  EXPECT_EQ(vault.registeredSingletonCount(), 3);
+
+  vault.registrationComplete();
+
+  // Verify our three singletons are distinct and non-nullptr.
+  Watchdog* s1 = SingletonNamedUsage<Watchdog, Watchdog1>::get();
+  EXPECT_EQ(s1, watchdog1_singleton.get());
+  Watchdog* s2 = SingletonNamedUsage<Watchdog, Watchdog2>::get();
+  EXPECT_EQ(s2, watchdog2_singleton.get());
+  EXPECT_NE(s1, s2);
+  Watchdog* s3 = SingletonNamedUsage<Watchdog, Watchdog3>::get();
+  EXPECT_EQ(s3, watchdog3_singleton.get());
+  EXPECT_NE(s3, s1);
+  EXPECT_NE(s3, s2);
+
+  // Verify the "default" singleton is the same as the DefaultTag-tagged
+  // singleton.
+  Watchdog* s4 = SingletonNamedUsage<Watchdog>::get();
+  EXPECT_EQ(s4, watchdog3_singleton.get());
+
+  vault.destroyInstances();
+}
+
+struct NaughtyUsageTag {};
+template <typename T, typename Tag = detail::DefaultTag>
+using SingletonNaughtyUsage = Singleton <T, Tag, NaughtyUsageTag>;
+struct NaughtyUsageTag2 {};
+template <typename T, typename Tag = detail::DefaultTag>
+using SingletonNaughtyUsage2 = Singleton <T, Tag, NaughtyUsageTag2>;
+
+// Some pathological cases such as getting unregistered singletons,
+// double registration, etc.
+TEST(Singleton, NaughtyUsage) {
+  auto& vault = *SingletonVault::singleton<NaughtyUsageTag>();
+
+  vault.registrationComplete();
+
+  // Unregistered.
+  EXPECT_THROW(Singleton<Watchdog>::get(), std::out_of_range);
+  EXPECT_THROW(SingletonNaughtyUsage<Watchdog>::get(), std::out_of_range);
+
+  vault.destroyInstances();
+
+  auto& vault2 = *SingletonVault::singleton<NaughtyUsageTag2>();
+
+  EXPECT_THROW(SingletonNaughtyUsage2<Watchdog>::get(), std::logic_error);
+  SingletonNaughtyUsage2<Watchdog> watchdog_singleton;
+  // double registration
+  EXPECT_THROW([]() {
+      SingletonNaughtyUsage2<Watchdog> watchdog_singleton;
+    }(),
+    std::logic_error);
+  vault2.destroyInstances();
+  // double registration after destroy
+  EXPECT_THROW([]() {
+      SingletonNaughtyUsage2<Watchdog> watchdog_singleton;
+    }(),
+    std::logic_error);
+}
+
+struct SharedPtrUsageTag {};
+template <typename T, typename Tag = detail::DefaultTag>
+using SingletonSharedPtrUsage = Singleton <T, Tag, SharedPtrUsageTag>;
+
+TEST(Singleton, SharedPtrUsage) {
+  struct WatchdogHolder {
+    ~WatchdogHolder() {
+      if (watchdog) {
+        LOG(ERROR) << "The following log message with stack trace is expected";
+      }
+    }
+
+    std::shared_ptr<Watchdog> watchdog;
+  };
+
+  auto& vault = *SingletonVault::singleton<SharedPtrUsageTag>();
+
+  EXPECT_EQ(vault.registeredSingletonCount(), 0);
+  SingletonSharedPtrUsage<Watchdog> watchdog_singleton;
+  EXPECT_EQ(vault.registeredSingletonCount(), 1);
+
+  SingletonSharedPtrUsage<ChildWatchdog> child_watchdog_singleton;
+  EXPECT_EQ(vault.registeredSingletonCount(), 2);
+
+  struct ATag {};
+  SingletonSharedPtrUsage<Watchdog, ATag> named_watchdog_singleton;
+
+  SingletonSharedPtrUsage<WatchdogHolder> watchdog_holder_singleton;
+
+  vault.registrationComplete();
+
+  // Initilize holder singleton first, so that it's the last one to be
+  // destroyed.
+  watchdog_holder_singleton.get();
+
+  Watchdog* s1 = SingletonSharedPtrUsage<Watchdog>::get();
+  EXPECT_NE(s1, nullptr);
+
+  Watchdog* s2 = SingletonSharedPtrUsage<Watchdog>::get();
+  EXPECT_NE(s2, nullptr);
+
+  EXPECT_EQ(s1, s2);
+
+  auto weak_s1 = SingletonSharedPtrUsage<Watchdog>::get_weak();
+
+  auto shared_s1 = weak_s1.lock();
+  EXPECT_EQ(shared_s1.get(), s1);
+  EXPECT_EQ(shared_s1.use_count(), 2);
+
+  auto old_serial = shared_s1->serial_number;
+
+  {
+    auto named_weak_s1 =
+      SingletonSharedPtrUsage<Watchdog, ATag>::get_weak();
+    auto locked = named_weak_s1.lock();
+    EXPECT_NE(locked.get(), shared_s1.get());
+  }
+
+  // We should release externally locked shared_ptr, otherwise it will be
+  // considered a leak
+  watchdog_holder_singleton->watchdog = std::move(shared_s1);
+
+  LOG(ERROR) << "The following log message regarding shared_ptr is expected";
+  {
+    auto start_time = std::chrono::steady_clock::now();
+    vault.destroyInstances();
+    auto duration = std::chrono::steady_clock::now() - start_time;
+    EXPECT_TRUE(duration > std::chrono::seconds{4} &&
+                duration < std::chrono::seconds{6});
+  }
+  EXPECT_EQ(vault.registeredSingletonCount(), 4);
+  EXPECT_EQ(vault.livingSingletonCount(), 0);
+
+  EXPECT_TRUE(weak_s1.expired());
+
+  auto empty_s1 = SingletonSharedPtrUsage<Watchdog>::get_weak();
+  EXPECT_FALSE(empty_s1.lock());
+
+  vault.reenableInstances();
+
+  // Singleton should be re-created only after reenableInstances() was called.
+  Watchdog* new_s1 = SingletonSharedPtrUsage<Watchdog>::get();
+  // Track serial number rather than pointer since the memory could be
+  // re-used when we create new_s1.
+  EXPECT_NE(new_s1->serial_number, old_serial);
+
+  auto new_s1_weak = SingletonSharedPtrUsage<Watchdog>::get_weak();
+  auto new_s1_shared = new_s1_weak.lock();
+  std::thread t([new_s1_shared]() mutable {
+      std::this_thread::sleep_for(std::chrono::seconds{2});
+      new_s1_shared.reset();
+    });
+  new_s1_shared.reset();
+  {
+    auto start_time = std::chrono::steady_clock::now();
+    vault.destroyInstances();
+    auto duration = std::chrono::steady_clock::now() - start_time;
+    EXPECT_TRUE(duration > std::chrono::seconds{1} &&
+                duration < std::chrono::seconds{3});
+  }
+  EXPECT_TRUE(new_s1_weak.expired());
+  t.join();
+}
+
+// Some classes to test singleton dependencies.  NeedySingleton has a
+// dependency on NeededSingleton, which happens during its
+// construction.
+struct NeedyTag {};
+template <typename T, typename Tag = detail::DefaultTag>
+using SingletonNeedy = Singleton <T, Tag, NeedyTag>;
+
+struct NeededSingleton {};
+struct NeedySingleton {
+  NeedySingleton() {
+    auto unused = SingletonNeedy<NeededSingleton>::get();
+    EXPECT_NE(unused, nullptr);
+  }
+};
+
+// Ensure circular dependencies fail -- a singleton that needs itself, whoops.
+struct SelfNeedyTag {};
+template <typename T, typename Tag = detail::DefaultTag>
+using SingletonSelfNeedy = Singleton <T, Tag, SelfNeedyTag>;
+
+struct SelfNeedySingleton {
+  SelfNeedySingleton() {
+    auto unused = SingletonSelfNeedy<SelfNeedySingleton>::get();
+    EXPECT_NE(unused, nullptr);
+  }
+};
+
+TEST(Singleton, SingletonDependencies) {
+  SingletonNeedy<NeededSingleton> needed_singleton;
+  SingletonNeedy<NeedySingleton> needy_singleton;
+  auto& needy_vault = *SingletonVault::singleton<NeedyTag>();
+
+  needy_vault.registrationComplete();
+
+  EXPECT_EQ(needy_vault.registeredSingletonCount(), 2);
+  EXPECT_EQ(needy_vault.livingSingletonCount(), 0);
+
+  auto needy = SingletonNeedy<NeedySingleton>::get();
+  EXPECT_EQ(needy_vault.livingSingletonCount(), 2);
+
+  SingletonSelfNeedy<SelfNeedySingleton> self_needy_singleton;
+  auto& self_needy_vault = *SingletonVault::singleton<SelfNeedyTag>();
+
+  self_needy_vault.registrationComplete();
+  EXPECT_THROW([]() {
+      SingletonSelfNeedy<SelfNeedySingleton>::get();
+    }(),
+    std::out_of_range);
+}
+
+// A test to ensure multiple threads contending on singleton creation
+// properly wait for creation rather than thinking it is a circular
+// dependency.
+class Slowpoke : public Watchdog {
+ public:
+  Slowpoke() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); }
+};
+
+struct ConcurrencyTag {};
+template <typename T, typename Tag = detail::DefaultTag>
+using SingletonConcurrency = Singleton <T, Tag, ConcurrencyTag>;
+
+TEST(Singleton, SingletonConcurrency) {
+  auto& vault = *SingletonVault::singleton<ConcurrencyTag>();
+  SingletonConcurrency<Slowpoke> slowpoke_singleton;
+  vault.registrationComplete();
+
+  std::mutex gatekeeper;
+  gatekeeper.lock();
+  auto func = [&gatekeeper]() {
+    gatekeeper.lock();
+    gatekeeper.unlock();
+    auto unused = SingletonConcurrency<Slowpoke>::get();
+  };
+
+  EXPECT_EQ(vault.livingSingletonCount(), 0);
+  std::vector<std::thread> threads;
+  for (int i = 0; i < 100; ++i) {
+    threads.emplace_back(func);
+  }
+  // If circular dependency checks fail, the unlock would trigger a
+  // crash.  Instead, it succeeds, and we have exactly one living
+  // singleton.
+  gatekeeper.unlock();
+  for (auto& t : threads) {
+    t.join();
+  }
+  EXPECT_EQ(vault.livingSingletonCount(), 1);
+}
+
+struct ConcurrencyStressTag {};
+template <typename T, typename Tag = detail::DefaultTag>
+using SingletonConcurrencyStress = Singleton <T, Tag, ConcurrencyStressTag>;
+
+TEST(Singleton, SingletonConcurrencyStress) {
+  auto& vault = *SingletonVault::singleton<ConcurrencyStressTag>();
+  SingletonConcurrencyStress<Slowpoke> slowpoke_singleton;
+
+  std::vector<std::thread> ts;
+  for (size_t i = 0; i < 100; ++i) {
+    ts.emplace_back([&]() {
+        slowpoke_singleton.get_weak().lock();
+      });
+  }
+
+  for (size_t i = 0; i < 100; ++i) {
+    std::chrono::milliseconds d(20);
+
+    std::this_thread::sleep_for(d);
+    vault.destroyInstances();
+    std::this_thread::sleep_for(d);
+    vault.destroyInstances();
+  }
+
+  for (auto& t : ts) {
+    t.join();
+  }
+}
+
+// Benchmarking a normal singleton vs a Meyers singleton vs a Folly
+// singleton.  Meyers are insanely fast, but (hopefully) Folly
+// singletons are fast "enough."
+int* getMeyersSingleton() {
+  static auto ret = new int(0);
+  return ret;
+}
+
+int normal_singleton_value = 0;
+int* getNormalSingleton() {
+  doNotOptimizeAway(&normal_singleton_value);
+  return &normal_singleton_value;
+}
+
+struct MockTag {};
+template <typename T, typename Tag = detail::DefaultTag>
+using SingletonMock = Singleton <T, Tag, MockTag>;
+
+// Verify that existing Singleton's can be overridden
+// using the make_mock functionality.
+TEST(Singleton, MockTest) {
+  auto& vault = *SingletonVault::singleton<MockTag>();
+
+  SingletonMock<Watchdog> watchdog_singleton;
+  vault.registrationComplete();
+
+  // Registring singletons after registrationComplete called works
+  // with make_mock (but not with Singleton ctor).
+  EXPECT_EQ(vault.registeredSingletonCount(), 1);
+  int serial_count_first = SingletonMock<Watchdog>::get()->serial_number;
+
+  // Override existing mock using make_mock.
+  SingletonMock<Watchdog>::make_mock();
+
+  EXPECT_EQ(vault.registeredSingletonCount(), 1);
+  int serial_count_mock = SingletonMock<Watchdog>::get()->serial_number;
+
+  // If serial_count value is the same, then singleton was not replaced.
+  EXPECT_NE(serial_count_first, serial_count_mock);
+}
+
+struct BenchmarkSingleton {
+  int val = 0;
+};
+
+BENCHMARK(NormalSingleton, n) {
+  for (size_t i = 0; i < n; ++i) {
+    doNotOptimizeAway(getNormalSingleton());
+  }
+}
+
+BENCHMARK_RELATIVE(MeyersSingleton, n) {
+  for (size_t i = 0; i < n; ++i) {
+    doNotOptimizeAway(getMeyersSingleton());
+  }
+}
+
+struct BenchmarkTag {};
+template <typename T, typename Tag = detail::DefaultTag>
+using SingletonBenchmark = Singleton <T, Tag, BenchmarkTag>;
+
+struct GetTag{};
+struct GetWeakTag{};
+
+SingletonBenchmark<BenchmarkSingleton, GetTag> benchmark_singleton_get;
+SingletonBenchmark<BenchmarkSingleton, GetWeakTag> benchmark_singleton_get_weak;
+
+BENCHMARK_RELATIVE(FollySingleton, n) {
+  for (size_t i = 0; i < n; ++i) {
+    doNotOptimizeAway(SingletonBenchmark<BenchmarkSingleton, GetTag>::get());
+  }
+}
+
+BENCHMARK_RELATIVE(FollySingletonWeak, n) {
+  for (size_t i = 0; i < n; ++i) {
+    SingletonBenchmark<BenchmarkSingleton, GetWeakTag>::get_weak();
+  }
+}
+
+int main(int argc, char* argv[]) {
+  testing::InitGoogleTest(&argc, argv);
+  google::InitGoogleLogging(argv[0]);
+  google::ParseCommandLineFlags(&argc, &argv, true);
+
+  SingletonVault::singleton()->registrationComplete();
+
+  auto ret = RUN_ALL_TESTS();
+  if (!ret) {
+    folly::runBenchmarksOnFlag();
+  }
+  return ret;
+}
diff --git a/folly/test/SingletonVaultCTest.cpp b/folly/test/SingletonVaultCTest.cpp
new file mode 100644 (file)
index 0000000..1182278
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2015 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <folly/Singleton.h>
+#include <folly/SingletonVault_c.h>
+
+#include <gtest/gtest.h>
+
+#include <thread>
+
+__thread long instance_counter_instances = 0;
+
+class InstanceCounter {
+ public:
+  InstanceCounter() {
+    instance_counter_instances++;
+  }
+
+  ~InstanceCounter() {
+    instance_counter_instances--;
+  }
+};
+
+TEST(SingletonVault, singletonReturnsSingletonInstance) {
+  SingletonVault_t *c = SingletonVault_singleton();
+  auto *cpp = folly::SingletonVault::singleton();
+  EXPECT_EQ(c, cpp);
+}
+
+struct TestTag {};
+template <typename T, typename Tag = folly::detail::DefaultTag>
+using SingletonTest = folly::Singleton <T, Tag, TestTag>;
+
+TEST(SingletonVault, singletonsAreCreatedAndDestroyed) {
+  auto vault = folly::SingletonVault::singleton<TestTag>();
+  SingletonTest<InstanceCounter> counter_singleton;
+  SingletonVault_registrationComplete((SingletonVault_t*) vault);
+  InstanceCounter *counter = SingletonTest<InstanceCounter>::get();
+  EXPECT_EQ(instance_counter_instances, 1);
+  SingletonVault_destroyInstances((SingletonVault_t*) vault);
+  EXPECT_EQ(instance_counter_instances, 0);
+}
index ac7b9bac00339eb69b36abb4a2d825aee8a3fd6d..36a82155ee1252a29111d05b8cd5f1464692c307 100644 (file)
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <folly/experimental/Singleton.h>
+#include <folly/Singleton.h>
 #include <folly/wangle/concurrent/IOExecutor.h>
 #include <folly/wangle/concurrent/IOThreadPoolExecutor.h>
 #include <folly/futures/InlineExecutor.h>