- // An actual instance of a singleton, tracking the instance itself,
- // its state as described above, and the create and teardown
- // functions.
- struct SingletonEntry {
- // mutex protects the entire entry
- std::mutex mutex;
-
- // state changes notify state_condvar
- SingletonEntryState state = SingletonEntryState::Dead;
- std::condition_variable state_condvar;
-
- // the thread creating the singleton
- std::thread::id creating_thread;
-
- // The singleton itself and related functions.
- std::shared_ptr<void> instance;
- void* instance_ptr = nullptr;
- CreateFunc create = nullptr;
- TeardownFunc teardown = nullptr;
-
- SingletonEntry() = default;
- SingletonEntry(const SingletonEntry&) = delete;
- SingletonEntry& operator=(const SingletonEntry&) = delete;
- SingletonEntry& operator=(SingletonEntry&&) = delete;
- SingletonEntry(SingletonEntry&&) = delete;
- };
-
- // Get a pointer to the living SingletonEntry for the specified
- // type. The singleton is created as part of this function, if
- // necessary.
- SingletonEntry* get_entry(detail::TypeDescriptor type,
- std::unique_lock<std::mutex>* lock) {
- // mutex must be held when calling this function
- stateCheck(
- SingletonVaultState::Running,
- "Attempt to load a singleton before "
- "SingletonVault::registrationComplete was called (hint: you probably "
- "didn't call initFacebook)");
-
- auto it = singletons_.find(type);
- if (it == singletons_.end()) {
- throw std::out_of_range(std::string("non-existent singleton: ") +
- type.name());
- }
-
- auto entry = it->second.get();
- std::unique_lock<std::mutex> entry_lock(entry->mutex);
-
- if (entry->state == SingletonEntryState::BeingBorn) {
- // If this thread is trying to give birth to the singleton, it's
- // a circular dependency and we must panic.
- if (entry->creating_thread == std::this_thread::get_id()) {
- throw std::out_of_range(std::string("circular singleton dependency: ") +
- type.name());
- }
-
- // Otherwise, another thread is constructing the singleton;
- // let's wait on a condvar to see it complete. We release and
- // reaquire lock while waiting on the entry to resolve its state.
- lock->unlock();
- entry->state_condvar.wait(entry_lock, [&entry]() {
- return entry->state != SingletonEntryState::BeingBorn;
- });
- lock->lock();
- }
-
- if (entry->instance == nullptr) {
- CHECK(entry->state == SingletonEntryState::Dead);
- entry->state = SingletonEntryState::BeingBorn;
- entry->creating_thread = std::this_thread::get_id();
-
- entry_lock.unlock();
- lock->unlock();
- // Can't use make_shared -- no support for a custom deleter, sadly.
- auto instance = std::shared_ptr<void>(entry->create(), entry->teardown);
- lock->lock();
- entry_lock.lock();
-
- CHECK(entry->state == SingletonEntryState::BeingBorn);
- entry->instance = instance;
- entry->instance_ptr = instance.get();
- entry->state = SingletonEntryState::Living;
- entry->state_condvar.notify_all();
-
- creation_order_.push_back(type);
- }
- CHECK(entry->state == SingletonEntryState::Living);
- return entry;
- }
-
- mutable std::mutex mutex_;
- typedef std::unique_ptr<SingletonEntry> SingletonEntryPtr;
- std::unordered_map<detail::TypeDescriptor,
- SingletonEntryPtr,
- detail::TypeDescriptorHasher> singletons_;
+ // 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_;