diff --git a/score/launch_manager/src/daemon/BUILD b/score/launch_manager/src/daemon/BUILD index 2e957629f..435910f9c 100644 --- a/score/launch_manager/src/daemon/BUILD +++ b/score/launch_manager/src/daemon/BUILD @@ -32,10 +32,12 @@ cc_binary( "//score/launch_manager/src/daemon/src/process_group_manager:alive_monitor_thread", "//score/launch_manager/src/daemon/src/process_state_client:process_state_notifier", "//score/launch_manager/src/daemon/src/recovery_client", + "//score/launch_manager/src/daemon/src/watchdog:i_watchdog_if", "@score_baselibs//score/language/futurecpp", ] + select({ "//config:lm_use_new_configuration": [ "//score/launch_manager/src/daemon/src/configuration:flatbuffer_config_loader", + "//score/launch_manager/src/daemon/src/watchdog/details:watchdog_impl", ], "//conditions:default": [], }), diff --git a/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/AliveMonitorImpl.cpp b/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/AliveMonitorImpl.cpp index 455e219a9..fb706a051 100644 --- a/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/AliveMonitorImpl.cpp +++ b/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/AliveMonitorImpl.cpp @@ -18,7 +18,6 @@ #include #include "score/mw/launch_manager/alive_monitor/details/daemon/AliveMonitorImpl.hpp" -#include "score/mw/launch_manager/watchdog/details/WatchdogImpl.hpp" namespace score { @@ -31,21 +30,17 @@ namespace daemon #ifdef USE_NEW_CONFIGURATION AliveMonitorImpl::AliveMonitorImpl(SptrIRecoveryClient recovery_client, - UptrIWatchdogIf watchdog, UptrIProcessStateReceiver process_state_receiver, const Config& config) : m_recovery_client(recovery_client), - m_watchdog(std::move(watchdog)), m_process_state_receiver{std::move(process_state_receiver)}, m_config(config) { } #else AliveMonitorImpl::AliveMonitorImpl(SptrIRecoveryClient recovery_client, - UptrIWatchdogIf watchdog, UptrIProcessStateReceiver process_state_receiver) : m_recovery_client(recovery_client), - m_watchdog(std::move(watchdog)), m_process_state_receiver{std::move(process_state_receiver)} { } @@ -58,8 +53,7 @@ EInitCode AliveMonitorImpl::init() noexcept { m_osClock.startMeasurement(); - m_daemon = std::make_unique(m_osClock, std::move(m_watchdog), - std::move(m_process_state_receiver)); + m_daemon = std::make_unique(m_osClock, std::move(m_process_state_receiver)); #ifdef USE_NEW_CONFIGURATION initResult = m_daemon->init(m_recovery_client, m_config); #else diff --git a/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/AliveMonitorImpl.hpp b/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/AliveMonitorImpl.hpp index d3dd55fd4..f694198e7 100644 --- a/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/AliveMonitorImpl.hpp +++ b/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/AliveMonitorImpl.hpp @@ -26,16 +26,11 @@ namespace lcm { class IRecoveryClient; -namespace watchdog { -class IWatchdogIf; -} - namespace saf { namespace daemon { using SptrIRecoveryClient = std::shared_ptr; -using UptrIWatchdogIf = std::unique_ptr; using UptrIProcessStateReceiver = std::unique_ptr; using UptrPhmDaemon = std::unique_ptr; using OsClock = score::lcm::saf::timers::OsClockInterface; @@ -47,12 +42,10 @@ class AliveMonitorImpl : public IAliveMonitor { public: #ifdef USE_NEW_CONFIGURATION AliveMonitorImpl(SptrIRecoveryClient recovery_client, - UptrIWatchdogIf watchdog, UptrIProcessStateReceiver process_state_receiver, const Config& config); #else - AliveMonitorImpl(SptrIRecoveryClient recovery_client, - UptrIWatchdogIf watchdog, + AliveMonitorImpl(SptrIRecoveryClient recovery_client, UptrIProcessStateReceiver process_state_receiver); #endif @@ -62,7 +55,6 @@ class AliveMonitorImpl : public IAliveMonitor { private: SptrIRecoveryClient m_recovery_client{nullptr}; - UptrIWatchdogIf m_watchdog{nullptr}; UptrPhmDaemon m_daemon{nullptr}; OsClock m_osClock{}; UptrIProcessStateReceiver m_process_state_receiver; diff --git a/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/BUILD b/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/BUILD index d86aec34c..4e28edbda 100644 --- a/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/BUILD +++ b/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/BUILD @@ -74,7 +74,6 @@ cc_library( "//score/launch_manager/src/daemon/src/alive_monitor/details/timers:cycle_timer", "//score/launch_manager/src/daemon/src/alive_monitor/details/timers:timers_os_clock", "//score/launch_manager/src/daemon/src/common:log", - "//score/launch_manager/src/daemon/src/watchdog:i_watchdog_if", "//score/launch_manager/src/lifecycle_client", ] + select({ "//config:lm_use_new_configuration": [ @@ -106,7 +105,6 @@ cc_library( visibility = ["//score/launch_manager/src/daemon:__subpackages__"], deps = [ ":i_health_monitor", - "//score/launch_manager/src/daemon/src/watchdog/details:watchdog_impl", "@score_baselibs//score/language/futurecpp", ], ) diff --git a/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/PhmDaemon.cpp b/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/PhmDaemon.cpp index 5c213dede..8827a2669 100644 --- a/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/PhmDaemon.cpp +++ b/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/PhmDaemon.cpp @@ -31,22 +31,17 @@ namespace daemon true_no_defect) */ /* RULECHECKER_comment(0, 4, check_incomplete_data_member_construction, "Default constructor is used for\ processStateReader.", true_no_defect) */ -PhmDaemon::PhmDaemon(OsClock& f_osClock, - std::unique_ptr f_watchdog, - std::unique_ptr f_process_state_receiver) +PhmDaemon::PhmDaemon(OsClock& f_osClock, std::unique_ptr f_process_state_receiver) : osClock{f_osClock}, cycleTimer{&osClock}, swClusterHandlers{}, - processStateReader{std::move(f_process_state_receiver)}, - watchdog(std::move(f_watchdog)) + processStateReader{std::move(f_process_state_receiver)} { static_cast(f_osClock); } void PhmDaemon::performCyclicTriggers(void) { - bool isCriticalFailure{false}; - NanoSecondType syncTimestamp{timers::OsClock::getMonotonicSystemClock()}; if (syncTimestamp == 0U) { @@ -55,29 +50,13 @@ void PhmDaemon::performCyclicTriggers(void) syncTimestamp = UINT64_MAX; } - isCriticalFailure = (!processStateReader.distributeChanges(syncTimestamp)); - - if (!isCriticalFailure) + if (processStateReader.distributeChanges(syncTimestamp)) { for (auto& phmHandler : swClusterHandlers) { phmHandler.performCyclicTriggers(syncTimestamp); - isCriticalFailure = isCriticalFailure || phmHandler.hasAnyRecoveryEnqueueFailed(); } } - - // watchdog is fired iff: - // * isCriticalFailure is set (e.g. process state distribution error, recovery ring buffer full) - // else: - // * watchdog is serviced - if (!isCriticalFailure) - { - watchdog->serviceWatchdog(); - } - else - { - watchdog->fireWatchdogReaction(); - } } #ifdef USE_NEW_CONFIGURATION diff --git a/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/PhmDaemon.hpp b/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/PhmDaemon.hpp index dac9eb966..3d8ec97b0 100644 --- a/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/PhmDaemon.hpp +++ b/score/launch_manager/src/daemon/src/alive_monitor/details/daemon/PhmDaemon.hpp @@ -25,7 +25,6 @@ #include "score/mw/launch_manager/alive_monitor/details/ifexm/ProcessStateReader.hpp" #include "score/mw/launch_manager/alive_monitor/details/timers/CycleTimeValidator.hpp" #include "score/mw/launch_manager/alive_monitor/details/timers/CycleTimer.hpp" -#include "score/mw/launch_manager/watchdog/IWatchdogIf.hpp" #ifdef USE_NEW_CONFIGURATION #include "score/mw/launch_manager/configuration/config.hpp" #endif @@ -45,8 +44,6 @@ enum class EInitCode : std::int8_t kNotInitialized, ///< Init was not performed kCycleTimeInitFailed, ///< Cyclic Timer initialization failed kConstructFlatCfgFactoryFailed, ///< FlatCfgFactory failed loading SWCL configurations - kWatchdogInitFailed, ///< Watchdog Initialization failed - kWatchdogEnableFailed, ///< Enabling watchdog device failed kMachineConfigInitFailed, ///< MachineConfigFactory failed loading the machine configuration kSignalHandlerRegistrationFailed, ///< Failed to register signal handler for termination signals kGeneralError ///< General error @@ -60,7 +57,6 @@ class PhmDaemon { public: using OsClock = score::lcm::saf::timers::OsClockInterface; - using Watchdog = watchdog::IWatchdogIf; using ProcessStateReceiver = score::lcm::IProcessStateReceiver; using RecoveryClient = score::lcm::IRecoveryClient; using MachineConfigFactory = factory::MachineConfigFactory; @@ -77,12 +73,10 @@ class PhmDaemon as same as generated function", true_no_defect) */ /// @brief Set the OS clock interface /// @param[in] f_osClock Access to the system clock (dependency injection possible in tests) - /// @param[in] f_watchdog watchdog implementation (dependency injection possible in tests) /// @param[in] f_process_state_receiver process state receiver implementation (dependency injection possible in tests) /* RULECHECKER_comment(3,1, check_expensive_to_copy_in_parameter, "Move only types cannot be passed by const ref", true_no_defect) */ PhmDaemon(OsClock& f_osClock, - std::unique_ptr f_watchdog, std::unique_ptr f_process_state_receiver); /* RULECHECKER_comment(0, 4, check_min_instructions, "Default destructor is not provided\ @@ -150,18 +144,6 @@ class PhmDaemon return EInitCode::kCycleTimeInitFailed; } - if (!watchdog->init(cycleTimeModified, machineConfig)) - { - LM_LOG_ERROR() << "Phm Daemon: Initialization of watchdog failed!"; - return EInitCode::kWatchdogInitFailed; - } - - if (!watchdog->enable()) - { - LM_LOG_ERROR() << "Phm Daemon: Enabling of watchdog failed!"; - return EInitCode::kWatchdogEnableFailed; - } - return EInitCode::kNoError; } @@ -234,7 +216,6 @@ class PhmDaemon } LM_LOG_INFO() << "Phm Daemon: Received termination request - shutting down"; - watchdog->disable(); return true; } @@ -267,9 +248,6 @@ class PhmDaemon /// @brief Process State Reader for PHM daemon ProcessStateReader processStateReader; - - /// @brief Connection to watchdog devices - std::unique_ptr watchdog; }; } // namespace daemon diff --git a/score/launch_manager/src/daemon/src/alive_monitor/details/factory/BUILD b/score/launch_manager/src/daemon/src/alive_monitor/details/factory/BUILD index df83b0384..a19ba40c0 100644 --- a/score/launch_manager/src/daemon/src/alive_monitor/details/factory/BUILD +++ b/score/launch_manager/src/daemon/src/alive_monitor/details/factory/BUILD @@ -49,7 +49,7 @@ cc_library( }), include_prefix = "score/mw/launch_manager/alive_monitor/details/factory", strip_include_prefix = "/score/launch_manager/src/daemon/src/alive_monitor/details/factory", - visibility = ["//score/launch_manager/src/daemon/src/alive_monitor:__subpackages__"], + visibility = ["//score/launch_manager/src/daemon:__subpackages__"], deps = [ ":static_config", "//score/launch_manager/src/daemon/src/alive_monitor/config", diff --git a/score/launch_manager/src/daemon/src/common/constants.hpp b/score/launch_manager/src/daemon/src/common/constants.hpp index 22843d1c7..c0100d4c6 100644 --- a/score/launch_manager/src/daemon/src/common/constants.hpp +++ b/score/launch_manager/src/daemon/src/common/constants.hpp @@ -47,6 +47,9 @@ constexpr std::chrono::milliseconds kMaxRunningDelay{1000}; ///< report_running constexpr std::chrono::milliseconds kControlClientMaxIpcDelay{500}; ///< The maximum time to wait, when trying to communicate with LCM. When this time is exceeded kCommunicationError will be returned constexpr std::chrono::milliseconds kControlClientBgThreadSleepTime{100}; +constexpr std::int64_t kMainLoopCycleTimeMs{50}; ///< The period at which the main loop services the watchdog +constexpr std::int64_t kMainLoopCycleTimeNs{kMainLoopCycleTimeMs * 1'000'000LL}; + enum class ControlClientLimits : uint16_t { kControlClientMaxInstances = 256U, ///< Maximum number of ControlClient instances that should be created by state manager. If state manager create more instances than kMaxInstances, those instances will always return kCommunicationError when used diff --git a/score/launch_manager/src/daemon/src/configuration/config.hpp b/score/launch_manager/src/daemon/src/configuration/config.hpp index 49810d483..bc96ed7a3 100644 --- a/score/launch_manager/src/daemon/src/configuration/config.hpp +++ b/score/launch_manager/src/daemon/src/configuration/config.hpp @@ -13,11 +13,11 @@ #ifndef CONFIG_HPP #define CONFIG_HPP +#include #include #include #include #include -#include #include namespace score::mw::launch_manager::configuration @@ -291,4 +291,4 @@ class ConfigBuilder } // namespace score::mw::launch_manager::configuration -#endif // CONFIG_HPP +#endif // CONFIG_HPP diff --git a/score/launch_manager/src/daemon/src/main.cpp b/score/launch_manager/src/daemon/src/main.cpp index e2c8aece8..b12da8ea4 100644 --- a/score/launch_manager/src/daemon/src/main.cpp +++ b/score/launch_manager/src/daemon/src/main.cpp @@ -21,7 +21,7 @@ #include "score/mw/launch_manager/common/log.hpp" #include "score/mw/launch_manager/alive_monitor/details/daemon/AliveMonitorImpl.hpp" -#include "score/mw/launch_manager/watchdog/details/WatchdogImpl.hpp" +#include "score/mw/launch_manager/watchdog/IWatchdogIf.hpp" #include "score/mw/launch_manager/process_group_manager/alive_monitor_thread.hpp" #include "score/mw/launch_manager/process_group_manager/process_group_manager.hpp" #include "score/mw/launch_manager/process_state_client/process_state_notifier.hpp" @@ -205,12 +205,10 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char* argv[]) #endif LM_LOG_DEBUG() << "Launch Manager Started !!!!"; std::shared_ptr recoveryClient{std::make_shared()}; - std::unique_ptr watchdog{ - std::make_unique()}; auto process_state_notifier = std::make_unique(); std::unique_ptr healthMonitor{ std::make_unique( - recoveryClient, std::move(watchdog), process_state_notifier->constructReceiver() + recoveryClient, process_state_notifier->constructReceiver() #ifdef USE_NEW_CONFIGURATION , *config_result #endif @@ -218,8 +216,15 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] const char* argv[]) std::unique_ptr aliveMonitorThread{ std::make_unique(std::move(healthMonitor))}; - std::unique_ptr process_group_manager = std::make_unique( - std::move(aliveMonitorThread), recoveryClient, std::move(process_state_notifier)); +#ifdef USE_NEW_CONFIGURATION + auto watchdog = score::lcm::watchdog::createWatchdog(); + auto process_group_manager = std::make_unique( + std::move(aliveMonitorThread), recoveryClient, std::move(process_state_notifier), std::move(watchdog)); +#else + // Legacy configuration wires no watchdog; the watchdog usage in PGM is #ifdef-guarded off. + auto process_group_manager = std::make_unique( + std::move(aliveMonitorThread), recoveryClient, std::move(process_state_notifier), nullptr); +#endif #ifdef USE_NEW_CONFIGURATION if (process_group_manager->initialize(*config_result)) diff --git a/score/launch_manager/src/daemon/src/process_group_manager/BUILD b/score/launch_manager/src/daemon/src/process_group_manager/BUILD index 8fd583c3c..33ac2aafa 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/BUILD +++ b/score/launch_manager/src/daemon/src/process_group_manager/BUILD @@ -71,6 +71,7 @@ cc_library( "//score/launch_manager/src/daemon/src/process_group_manager/details:safe_process_map", "//score/launch_manager/src/daemon/src/process_state_client:iprocess_state_notifier", "//score/launch_manager/src/daemon/src/recovery_client", + "//score/launch_manager/src/daemon/src/watchdog:i_watchdog_if", "@score_baselibs//score/language/futurecpp", ] + select({ "//config:lm_use_new_configuration": [ diff --git a/score/launch_manager/src/daemon/src/process_group_manager/details/process_group_manager.cpp b/score/launch_manager/src/daemon/src/process_group_manager/details/process_group_manager.cpp index 40c94ba54..da654f66f 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/details/process_group_manager.cpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/details/process_group_manager.cpp @@ -39,7 +39,8 @@ void ProcessGroupManager::cancel() ProcessGroupManager::ProcessGroupManager(std::unique_ptr alive_monitor_thread, std::shared_ptr recovery_client, - std::unique_ptr process_state_notifier) + std::unique_ptr process_state_notifier, + std::unique_ptr watchdog) : configuration_(), process_interface_(), process_map_(nullptr), @@ -50,10 +51,8 @@ ProcessGroupManager::ProcessGroupManager(std::unique_ptr al process_groups_(), process_state_notifier_(std::move(process_state_notifier)), alive_monitor_thread_(std::move(alive_monitor_thread)), - recovery_client_(recovery_client) //, - // ucm_polling_thread_( -// [this](const Message::Action act, const Message::UpdateContext updateCtx, const lib::fun::string& swc) -> bool -// { return reloadConfiguration(act, updateCtx, IdentifierHash(swc.c_str())); }) + recovery_client_(recovery_client), + watchdog_(std::move(watchdog)) { } @@ -118,12 +117,35 @@ bool ProcessGroupManager::initialize() return false; } +#ifdef USE_NEW_CONFIGURATION + const auto watchdog_config = config.watchdog(); + + // Watchdog config may not be available if no watchdog is configured + if (watchdog_config.has_value()) + { + if (!watchdog_->init(watchdog_config.value(), score::lcm::internal::kMainLoopCycleTimeNs)) + { + LM_LOG_ERROR() << "Watchdog initialization failed"; + return false; + } + if (!watchdog_->enable()) + { + LM_LOG_ERROR() << "Watchdog enable failed"; + return false; + } + } + +#endif + return true; } void ProcessGroupManager::deinitialize() { // ucm_polling_thread_.stopPolling(); +#ifdef USE_NEW_CONFIGURATION + watchdog_->disable(); +#endif alive_monitor_thread_->stop(); configuration_.deinitialize(); process_groups_.clear(); @@ -166,7 +188,6 @@ inline bool ProcessGroupManager::initializeControlClientHandler() return false; } - if (osal::IpcCommsSync::control_client_handler_nudge_fd == fd2) { void* buf = mmap(NULL, sizeof(osal::Semaphore), PROT_WRITE, MAP_SHARED, fd2, 0); @@ -299,8 +320,10 @@ bool ProcessGroupManager::run() while (!em_cancelled.load()) { // Wait for something to happen... - const auto osal_result = - ControlClientChannel::nudgeControlClientHandler_->timedWait(std::chrono::milliseconds(100)); + // The wait is kept below the minimum watchdog timeout so that the wait plus per-iteration + // processing stays within budget for servicing the watchdog each cycle. + const auto osal_result = ControlClientChannel::nudgeControlClientHandler_->timedWait( + std::chrono::milliseconds(score::lcm::internal::kMainLoopCycleTimeMs)); SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE( osal_result == OsalReturnType::kSuccess || osal_result == OsalReturnType::kTimeout, @@ -312,6 +335,16 @@ bool ProcessGroupManager::run() processGroupHandler(*pg); } recoveryActionHandler(); + +#ifdef USE_NEW_CONFIGURATION + if (recovery_client_ && recovery_client_->hasOverflow()) + { + LM_LOG_ERROR() << "Recovery client overflow detected, firing watchdog"; + watchdog_->fireWatchdogReaction(); + } + + watchdog_->serviceWatchdog(); +#endif } allProcessGroupsOff(); diff --git a/score/launch_manager/src/daemon/src/process_group_manager/process_group_manager.hpp b/score/launch_manager/src/daemon/src/process_group_manager/process_group_manager.hpp index 9b2c57c68..df61a7dce 100644 --- a/score/launch_manager/src/daemon/src/process_group_manager/process_group_manager.hpp +++ b/score/launch_manager/src/daemon/src/process_group_manager/process_group_manager.hpp @@ -26,17 +26,18 @@ #else #include "score/mw/launch_manager/configuration/configuration_manager.hpp" #endif -#include "score/mw/launch_manager/process_group_manager/iprocess.hpp" -#include "score/mw/launch_manager/process_group_manager/details/graph.hpp" #include "score/mw/launch_manager/common/concurrency/mpmc_concurrent_queue.hpp" +#include "score/mw/launch_manager/common/concurrency/workerthread.hpp" +#include "score/mw/launch_manager/common/constants.hpp" +#include "score/mw/launch_manager/process_group_manager/details/graph.hpp" #include "score/mw/launch_manager/process_group_manager/details/os_handler.hpp" -#include "score/mw/launch_manager/process_state_client/iprocess_state_notifier.hpp" #include "score/mw/launch_manager/process_group_manager/details/process_info_node.hpp" #include "score/mw/launch_manager/process_group_manager/details/safe_process_map.hpp" -#include "score/mw/launch_manager/common/concurrency/workerthread.hpp" #include "score/mw/launch_manager/process_group_manager/ialive_monitor_thread.hpp" +#include "score/mw/launch_manager/process_group_manager/iprocess.hpp" +#include "score/mw/launch_manager/process_state_client/iprocess_state_notifier.hpp" #include "score/mw/launch_manager/recovery_client/recovery_client.hpp" -#include "score/mw/launch_manager/common/constants.hpp" +#include "score/mw/launch_manager/watchdog/IWatchdogIf.hpp" namespace score::lcm::internal { @@ -76,9 +77,12 @@ class ProcessGroupManager final /// @param recovery_client A shared pointer to an IRecoveryClient instance for handling recovery operations. /// @param process_state_notifier A unique pointer to an IProcessStateNotifier instance for notifying the Alive /// Monitor thread of process state changes. + /// @param watchdog A unique pointer to an IWatchdogIf instance serviced during the main loop. May be nullptr in + /// legacy configuration where no watchdog is wired. ProcessGroupManager(std::unique_ptr alive_monitor_thread, std::shared_ptr recovery_client, - std::unique_ptr process_state_notifier); + std::unique_ptr process_state_notifier, + std::unique_ptr watchdog); /// @brief Initializes the process group manager. /// Loads the flat configuration through ConfigurationManager. @@ -282,7 +286,6 @@ class ProcessGroupManager final inline bool initializeProcessGroups(); #endif - /// @brief Creates process component objects, including the job queue and worker threads. inline void createProcessComponentsObjects(); @@ -336,6 +339,9 @@ class ProcessGroupManager final std::unique_ptr alive_monitor_thread_; std::shared_ptr recovery_client_{}; + + /// @brief The watchdog serviced during the main loop. May be nullptr in legacy configuration. + std::unique_ptr watchdog_; }; } // namespace score::lcm::internal diff --git a/score/launch_manager/src/daemon/src/watchdog/BUILD b/score/launch_manager/src/daemon/src/watchdog/BUILD index 0f1c87d62..3b54e7b1e 100644 --- a/score/launch_manager/src/daemon/src/watchdog/BUILD +++ b/score/launch_manager/src/daemon/src/watchdog/BUILD @@ -26,5 +26,8 @@ cc_library( include_prefix = "score/mw/launch_manager/watchdog", strip_include_prefix = "/score/launch_manager/src/daemon/src/watchdog", visibility = ["//score:__subpackages__"], - deps = [":i_device_config_factory"], + deps = [ + ":i_device_config_factory", + "//score/launch_manager/src/daemon/src/common:constants", + ], ) diff --git a/score/launch_manager/src/daemon/src/watchdog/IWatchdogIf.hpp b/score/launch_manager/src/daemon/src/watchdog/IWatchdogIf.hpp index ebe092cb8..e957bd39e 100644 --- a/score/launch_manager/src/daemon/src/watchdog/IWatchdogIf.hpp +++ b/score/launch_manager/src/daemon/src/watchdog/IWatchdogIf.hpp @@ -15,9 +15,15 @@ #ifndef IWATCHDOGIF_HPP_INCLUDED #define IWATCHDOGIF_HPP_INCLUDED +#include "score/mw/launch_manager/common/constants.hpp" + #include +#include -#include "score/mw/launch_manager/watchdog/IDeviceConfigFactory.hpp" +namespace score::mw::launch_manager::configuration +{ +struct WatchdogConfig; +} namespace score { @@ -48,6 +54,11 @@ class IWatchdogIf /// @brief Maximum supported timeout value in ms static constexpr std::uint16_t kTimeoutMaxMillis{30U /*seconds*/ * 1000U /*millis per second*/}; + /// The main loop cycle time must be strictly less than the minimum watchdog timeout to ensure that + /// the watchdog timeout cannot expire during an unblocked run of the main loop. + static_assert(score::lcm::internal::kMainLoopCycleTimeMs < kTimeoutMinMillis, + "Main loop cycle time must be less than the minimum watchdog timeout"); + /// @brief Destructor. /* RULECHECKER_comment(0, 2, check_min_instructions, "Default destructor has no body", true_no_defect) */ virtual ~IWatchdogIf() noexcept = default; @@ -61,11 +72,13 @@ class IWatchdogIf /// @note Method is not reentrant safe. /// @note Only simple watchdogs are supported as of now, no windows watchdog (i.e. the min timeout value is always /// assumed 0). - /// @param[in] f_cycleTimeInNs The cycle time in nanoseconds in which serviceWatchdog() will be called - /// @param[in] f_configFactory The factory for retrieving the watchdog configuration(s) + /// @param[in] watchdog_config The configuration for the watchdog + /// @param[in] cycle_time_ns The period in nanoseconds at which serviceWatchdog() is called; used to validate + /// that the configured watchdog timeout is long enough to be serviced in time. /// @return Status of configuration. True all device configurations are valid and has been successfully taken over /// by the Watchdog Interface library, false otherwise. - virtual bool init(std::int64_t f_cycleTimeInNs, const IDeviceConfigFactory& f_configFactory) noexcept = 0; + virtual bool init(const score::mw::launch_manager::configuration::WatchdogConfig& watchdog_config, + std::int64_t cycle_time_ns) noexcept = 0; /// @brief Activate the watchdogs. /// @details Initialize and activate all watchdogs which are configured for use by the Watchdog Interface library. @@ -123,6 +136,10 @@ class IWatchdogIf }; }; +/// @brief Creates a concrete WatchdogImpl instance behind the IWatchdogIf interface. +/// @return An owning pointer to a new watchdog implementation. +std::unique_ptr createWatchdog(); + } // namespace watchdog } // namespace lcm } // namespace score diff --git a/score/launch_manager/src/daemon/src/watchdog/details/BUILD b/score/launch_manager/src/daemon/src/watchdog/details/BUILD index b8b8c3c4e..7f5dc12fa 100644 --- a/score/launch_manager/src/daemon/src/watchdog/details/BUILD +++ b/score/launch_manager/src/daemon/src/watchdog/details/BUILD @@ -42,6 +42,7 @@ cc_library( ":watchdog", "//score/launch_manager/src/daemon/src/alive_monitor/details/timers:os_clock_interface", "//score/launch_manager/src/daemon/src/common:log", + "//score/launch_manager/src/daemon/src/configuration:config", "//score/launch_manager/src/daemon/src/watchdog:i_device_config_factory", "//score/launch_manager/src/daemon/src/watchdog:i_watchdog_if", "@score_baselibs//score/language/futurecpp", diff --git a/score/launch_manager/src/daemon/src/watchdog/details/WatchdogImpl.cpp b/score/launch_manager/src/daemon/src/watchdog/details/WatchdogImpl.cpp index d2ca1d2e1..2c5428e64 100644 --- a/score/launch_manager/src/daemon/src/watchdog/details/WatchdogImpl.cpp +++ b/score/launch_manager/src/daemon/src/watchdog/details/WatchdogImpl.cpp @@ -20,6 +20,7 @@ #include #include "score/mw/launch_manager/alive_monitor/details/timers/OsClockInterface.hpp" +#include "score/mw/launch_manager/configuration/config.hpp" #include "score/mw/launch_manager/watchdog/details/DeviceIf.hpp" #include "score/mw/launch_manager/watchdog/details/Watchdog.hpp" @@ -55,31 +56,32 @@ T secToMs(const T f_timeout) /* RULECHECKER_comment(0:0,9:0, check_min_instructions, "Constructor with empty body is valid", true_no_defect) */ WatchdogImpl::WatchdogImpl() noexcept : IWatchdogIf(), watchdogDevices(), state(ELibState::idle) {} -bool WatchdogImpl::init(std::int64_t f_cycleTimeInNs, const IDeviceConfigFactory& f_configFactory) noexcept +bool WatchdogImpl::init(const score::mw::launch_manager::configuration::WatchdogConfig& watchdog_config, + std::int64_t cycle_time_ns) noexcept { bool isSuccess{true}; try { - const auto configurations{f_configFactory.getDeviceConfigurations()}; - if (!configurations) + if (watchdog_config.max_timeout_ms > std::numeric_limits::max()) { - LM_LOG_ERROR() << "Watchdog: Invalid watchdog device configuration. Watchdog initialization failed."; - isSuccess = false; + LM_LOG_ERROR() << "Watchdog: Invalid watchdog timeout value " << watchdog_config.max_timeout_ms + << "ms. Watchdog initialization failed."; + return false; } - if (isSuccess) - { - watchdogDevices.reserve(configurations->size()); + // Translate WatchdogConfig to DeviceConfig + DeviceConfig config{}; + config.fileName = watchdog_config.device_file_path; + config.timeoutMin = 0U; + config.timeoutMax = static_cast(watchdog_config.max_timeout_ms); + config.canBeDeactivated = watchdog_config.deactivate_on_shutdown; + config.needsMagicClose = watchdog_config.require_magic_close; - for (auto& config : *configurations) - { - if (!configureDevice(config, f_cycleTimeInNs)) - { - LM_LOG_ERROR() << "Watchdog: Error when configuring watchdog device" << config.fileName - << "- Watchdog initialization failed."; - isSuccess = false; - } - } + if (!configureDevice(config, cycle_time_ns)) + { + LM_LOG_ERROR() << "Watchdog: Error when configuring watchdog device " << config.fileName + << " - Watchdog initialization failed."; + isSuccess = false; } } catch (const std::exception& e) @@ -481,6 +483,12 @@ void WatchdogImpl::waitForever() const noexcept /* RULECHECKER_comment(1:0,1:0, check_pragma_usage, "External tooling requires pragma", true_no_defect) */ #pragma CTC ENDSKIP #endif + +std::unique_ptr createWatchdog() +{ + return std::make_unique(); +} + } // namespace watchdog } // namespace lcm } // namespace score diff --git a/score/launch_manager/src/daemon/src/watchdog/details/WatchdogImpl.hpp b/score/launch_manager/src/daemon/src/watchdog/details/WatchdogImpl.hpp index 7302ad867..0364f97f3 100644 --- a/score/launch_manager/src/daemon/src/watchdog/details/WatchdogImpl.hpp +++ b/score/launch_manager/src/daemon/src/watchdog/details/WatchdogImpl.hpp @@ -57,7 +57,8 @@ class WatchdogImpl : public IWatchdogIf ~WatchdogImpl() override = default; /// @copydoc IWatchdogIf::init() - bool init(std::int64_t f_cycleTimeInNs, const IDeviceConfigFactory& f_configFactory) noexcept override; + bool init(const score::mw::launch_manager::configuration::WatchdogConfig& watchdog_config, + std::int64_t cycle_time_ns) noexcept override; /// @copydoc IWatchdogIf::enable() bool enable() noexcept override;