#pragma once #include "util/config/ConfigDefinition.hpp" #include "util/log/Logger.hpp" #include #include #include #include #include #include #include #include #include #include namespace util { namespace impl { class SignalsHandlerStatic; } // namespace impl /** * @brief Class handling signals. * @note There could be only one instance of this class. */ class SignalsHandler { /** * @brief States of the signal handler state machine. */ enum class State { WaitingForSignal, GracefulShutdown, ForceExit, NormalExit }; std::chrono::steady_clock::duration gracefulPeriod_; std::function forceExitHandler_; boost::signals2::signal stopSignal_; std::atomic signalReceived_{false}; std::atomic state_{State::WaitingForSignal}; std::mutex mutex_; std::condition_variable cv_; std::thread workerThread_; friend class impl::SignalsHandlerStatic; public: /** * @brief Enum for stop priority. */ enum class Priority { StopFirst = 0, Normal = 1, StopLast = 2 }; /** * @brief Create SignalsHandler object. * * @param config The configuration. * @param forceExitHandler The handler for forced exit. */ SignalsHandler( util::config::ClioConfigDefinition const& config, std::function forceExitHandler = kDefaultForceExitHandler ); SignalsHandler(SignalsHandler const&) = delete; SignalsHandler(SignalsHandler&&) = delete; SignalsHandler& operator=(SignalsHandler const&) = delete; SignalsHandler& operator=(SignalsHandler&&) = delete; /** * @brief Destructor of SignalsHandler. */ ~SignalsHandler(); /** * @brief Subscribe to stop signal. * * @tparam SomeCallback The type of the callback. * @param callback The callback to call on stop signal. * @param priority The priority of the callback. Default is Normal. */ template void subscribeToStop(SomeCallback&& callback, Priority priority = Priority::Normal) { stopSignal_.connect(static_cast(priority), std::forward(callback)); } /** * @brief Notify the signal handler that graceful shutdown has completed. * This allows the handler to transition to NormalExit state. */ void notifyGracefulShutdownComplete(); static constexpr auto kHandledSignals = {SIGINT, SIGTERM}; private: /** * @brief Set signal handler for handled signals. * * @param handler The handler to set. Default is nullptr. */ static void setHandler(void (*handler)(int) = nullptr); /** * @brief Run the state machine loop in a worker thread. */ void runStateMachine(); static constexpr auto kDefaultForceExitHandler = []() { std::exit(EXIT_FAILURE); }; }; } // namespace util