folly/folly/Singleton.h

/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * 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.
 */

//
// Docs: https://fburl.com/fbcref_singleton
//

// SingletonVault - a library to manage the creation and destruction
// of interdependent singletons.
//
// Recommended usage of this class: 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 {
//   // Caution - may return a null ptr during startup and shutdown.
//   static std::shared_ptr<MyExpensiveService> getInstance();
//   ....
// };
//
// In your .cpp file:
// namespace { struct PrivateTag {}; }
// static folly::Singleton<MyExpensiveService, PrivateTag> the_singleton;
// std::shared_ptr<MyExpensiveService> MyExpensiveService::getInstance() {
//   return the_singleton.try_get();
// }
//
// Code in other modules can access it via:
//
// auto instance = MyExpensiveService::getInstance();
//
// Advanced usage and notes:
//
// You can also access a singleton instance with
// `Singleton<ObjectType, TagType>::try_get()`. We recommend
// that you prefer the form `the_singleton.try_get()` because it ensures that
// `the_singleton` is used and cannot be garbage-collected during linking: this
// is necessary because the constructor of `the_singleton` is what registers it
// to the SingletonVault.
//
// 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 a default tag is
// used. We recommend that you use a tag from an anonymous namespace private to
// your implementation file, as this ensures that the singleton is only
// available via your interface and not also through Singleton<T>::try_get()
//
// 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.
//
// For example, if you need to pass arguments to your class's constructor:
//   class X {
//    public:
//      X(int a1, std::string a2);
//    // ...
//   }
// Make your singleton like this:
//   folly::Singleton<X> singleton_x([]() { return new X(42, "foo"); });
//
// The above examples detail a situation where an expensive singleton is loaded
// on-demand (thus only if needed).  However if there is an expensive singleton
// that will likely be needed, and initialization takes a potentially long time,
// e.g. while initializing, parsing some files, talking to remote services,
// making uses of other singletons, and so on, the initialization of those can
// be scheduled up front, or "eagerly".
//
// In that case the singleton can be declared this way:
//
// namespace {
// auto the_singleton =
//     folly::Singleton<MyExpensiveService>(/* optional create, destroy args */)
//     .shouldEagerInit();
// }
//
// This way the singleton's instance is built at program initialization,
// if the program opted-in to that feature by calling "doEagerInit" or
// "doEagerInitVia" during its startup.
//
// 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/CancellationToken.h>
#include <folly/Exception.h>
#include <folly/Executor.h>
#include <folly/Memory.h>
#include <folly/Synchronized.h>
#include <folly/concurrency/CoreCachedSharedPtr.h>
#include <folly/concurrency/memory/ReadMostlySharedPtr.h>
#include <folly/detail/Singleton.h>
#include <folly/detail/StaticSingletonManager.h>
#include <folly/hash/Hash.h>
#include <folly/lang/Exception.h>
#include <folly/memory/SanitizeLeak.h>
#include <folly/synchronization/Baton.h>

#include <algorithm>
#include <atomic>
#include <condition_variable>
#include <functional>
#include <list>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#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:
//      a) Strict: no singleton can be created in this stage.
//      b) Relaxed: singleton can be created (the default vault is Relaxed).
//   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 {

// A TypeDescriptor is the unique handle for a given singleton.  It is
// a combination of the type and of the optional name, and is used as
// a key in unordered_maps.
class TypeDescriptor {};

class TypeDescriptorHasher {};

[[noreturn]] void singletonWarnLeakyDoubleRegistrationAndAbort(
    const TypeDescriptor& type);

[[noreturn]] void singletonWarnLeakyInstantiatingNotRegisteredAndAbort(
    const TypeDescriptor& type);

[[noreturn]] void singletonWarnRegisterMockEarlyAndAbort(
    const TypeDescriptor& type);

void singletonWarnDestroyInstanceLeak(
    const TypeDescriptor& type, const void* ptr);

[[noreturn]] void singletonWarnCreateCircularDependencyAndAbort(
    const TypeDescriptor& type);

[[noreturn]] void singletonWarnCreateUnregisteredAndAbort(
    const TypeDescriptor& type);

[[noreturn]] void singletonWarnCreateBeforeRegistrationCompleteAndAbort(
    const TypeDescriptor& type);

void singletonPrintDestructionStackTrace(const TypeDescriptor& type);

[[noreturn]] void singletonThrowNullCreator(const std::type_info& type);

[[noreturn]] void singletonThrowGetInvokedAfterDestruction(
    const TypeDescriptor& type);

struct SingletonVaultState {};

// 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 {};

// 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 {};

} // namespace detail

class SingletonVault {};

/**
 * Singleton 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>::try_get().
 *
 * There are many supporting libraries and classes for Singleton; this is the
 * one that users typically interact with.
 */
template <
    typename T,
    typename Tag = detail::DefaultTag,
    typename VaultTag = detail::DefaultTag /* for testing */>
class Singleton {};

template <typename T, typename Tag = detail::DefaultTag>
class LeakySingleton {};
} // namespace folly

#include <folly/Singleton-inl.h>