Documentation Index
Fetch the complete documentation index at: https://docs.springtail.io/llms.txt
Use this file to discover all available pages before exploring further.
Singleton Template Class
Overview
TheSingleton template class provides a thread-safe singleton pattern implementation with optional threading support and lifecycle management. This class is part of the springtail namespace and is designed to ensure that only one instance of a derived class exists throughout the application’s lifetime.
Features
- Thread-safe initialization using
std::call_once - Optional threading support with automatic thread naming
- Service registration integration with centralized shutdown management through
ServiceRegistry - Protected lifecycle hooks for derived class customization
- Deleted copy/move semantics to prevent duplication
- Atomic shutdown flag for safe thread termination
Class Template
T should be the derived class that inherits from Singleton<T> (CRTP pattern).
Public Interface
Static Methods
get_instance()
T. Creates the instance on first call using thread-safe initialization.
Returns: Pointer to the singleton instance
Thread Safety: Yes
Example:
shutdown()
- Sets the shutdown flag
- Signals thread termination if a thread exists
- Joins the thread
- Calls internal cleanup
- Deletes the instance
Instance Methods
start_thread()
_internal_run() method. Thread name is automatically set based on the service ID or type name.
Example:
Protected Interface
Derived classes should override these methods to customize behavior:_internal_run()
start_thread() is used. Should periodically check _is_shutting_down() to enable graceful termination.
Example:
_internal_thread_shutdown()
_internal_shutdown()
_is_shutting_down()
true if shutting down, false otherwise
Constructor
service_id: Service identifier for registration (default:ServiceId::ServiceInvalidId)
Static Utility Methods
_assert_instance()
_has_instance()
true if instance exists, false otherwise
ServiceId Enum
ServiceId uniquely identifies a logical service within the Springtail system.
These identifiers are used for:
- Dependency ordering
- Thread naming
- Coordinated shutdown
- Service registration
ServiceId enum defines service identifiers for various components in the system:
ServiceInvalidId is reserved for non-registered or internal services.
Helper Functions
get_type_name<T>()
T
Service Registration
springtail_register_service()
Registers a service shutdown callback with the global service registry.
- Services are shut down in dependency order.
- Registration is idempotent and enforced per service ID.
- Typically invoked automatically by
Singleton.
springtail_shutdown().
springtail_get_service_name()
Returns a human-readable name for a given ServiceId.
Used for:
- Logging
- Thread naming
- Debug output
"Invalid" is returned.
Singleton Framework
TheSingleton<T> template provides a thread-safe, lifecycle-aware singleton implementation designed for long-lived system services.
Key Properties
- Lazy exactly-once initialization
- Exactly-once shutdown
- Optional background thread
- Dependency-aware cleanup
- Integrated with service registry
Singleton Lifecycle
Instance Creation
- The instance is created on first call to
get_instance(). - Creation is guarded by
std::call_once. - The derived class must have a default constructor.
Thread Management
Singletons may optionally run a dedicated thread. To enable threading:- Call
start_thread(). - Implement
_internal_run().
- Thread name is derived from
ServiceId. - If no valid
ServiceIdexists, the type name is used. - Names are truncated to 15 characters to satisfy pthread limits.
Shutdown Semantics
Shutdown is global and idempotent. Whenshutdown() is called:
_shutting_downis set to true._internal_thread_shutdown()is invoked.- The thread is joined (if started).
_internal_shutdown()is invoked.- The instance is destroyed.
Overrides in Derived Classes
Derived classes may need to implement overrides for the following hooks. Some of these functions are for running and shutting down the internal thread, while another is simply for internal shutdown._internal_run
Executed in the background thread.
Must be overridden if start_thread() is used.
_internal_thread_shutdown
Used to wake or unblock the background thread prior to joining.
Typical use cases:
- Notifying condition variables
- Closing file descriptors
- Signaling event loops
_internal_shutdown
Final cleanup hook.
Used for:
- Releasing resources
- Stopping dependent components
- Final state updates
Shutdown State Checking
_is_shutting_down
Returns true if shutdown has been initiated.
Intended for use inside _internal_run() loops to allow cooperative termination.
Constructor Behavior
TheSingleton constructor accepts an optional ServiceId.
If a valid ServiceId is provided:
- The service is automatically registered for shutdown.
- The shutdown order is dependency-aware and is a part of the initialization framework.
ServiceInvalidId. This value ensures that the service won’t be registered with initialization framework. It will be up to the user to figure out when and how to invoke shutdown() function.
Type Name Utility
get_type_name<T>
Returns a demangled type name extracted from __PRETTY_FUNCTION__.
Used internally for:
- Thread naming fallback
- Diagnostics
Typical Usage Pattern
- Define a service class inheriting from
Singleton<T>. - If you want this class to be a part of the global shutdown sequence, then you need to do the following:
- create a new service id in
ServiceIdenum - in the constructor pass this new service id to
Singletonconstructor - in
init.ccfile, setup dependencies for this service on the other existing services, for the very least it should depend onServiceRegisterIdbecause this is the id of the service that provides initialization and shutdown for Springtail base functionality - in
init.ccfile, add the name of the new service to service names mapdependencies_names
- Optionally start a background thread.
- Let the framework manage lifecycle and shutdown if the service id is assigned, otherwise manage it yourself.
springtail_shutdown().
Here is the usage example.
Thread Safety
- Instance creation is thread-safe via
std::call_once - Shutdown is thread-safe via
std::call_once - The
_shutting_downflag is atomic for safe cross-thread access - Derived classes are responsible for their own thread-safety
Design Considerations
- No double initialization
- No double shutdown
- Deterministic shutdown order
- Thread-safe lifecycle transitions
- No dependency cycles allowed
- Uses the Curiously Recurring Template Pattern (CRTP) for static polymorphism
- Derived classes should friend
Singleton<T>to allow private constructor access - All copy and move operations are explicitly deleted
- Instance is created on first
get_instance()call - Services can self-register for centralized shutdown
- Long-lived system services
- Daemons and infrastructure components
- Deterministic startup/shutdown