From 7ef1239dcea48abb4a059c6f4545ebeead89785d Mon Sep 17 00:00:00 2001 From: WilliamRoebuck <244554584+WilliamRoebuck@users.noreply.github.com> Date: Mon, 1 Jun 2026 10:24:36 +0100 Subject: [PATCH 1/6] Removed local supervision, global supervision and recovery notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Removed local, global and recovery notification * Pass process identifier instead of pg identifier * Remove deadline and logical leftovers * Collapse checkpoint supervision into alive supervision --------- Co-authored-by: Nicolas Fußberger --- .../daemon/src/alive_monitor/Monitor.h | 43 -- .../src/alive_monitor/MonitorImplWrapper.h | 3 - .../src/alive_monitor/config/hm_flatcfg.fbs | 40 +- .../config/hm_flatcfg_generated.h | 504 +--------------- .../alive_monitor/config/hmcore_flatcfg.fbs | 2 - .../config/hmcore_flatcfg_generated.h | 24 +- .../src/alive_monitor/details/daemon/BUILD | 5 - .../details/daemon/PhmDaemon.cpp | 24 +- .../details/daemon/SwClusterHandler.cpp | 88 +-- .../details/daemon/SwClusterHandler.hpp | 38 +- .../src/alive_monitor/details/factory/BUILD | 3 - .../details/factory/FlatCfgFactory.cpp | 322 ++-------- .../details/factory/FlatCfgFactory.hpp | 27 +- .../details/factory/IPhmFactory.hpp | 39 +- .../details/factory/MachineConfigFactory.cpp | 4 - .../details/factory/MachineConfigFactory.hpp | 4 - .../details/factory/StaticConfig.hpp | 4 - .../src/alive_monitor/details/recovery/BUILD | 36 -- .../details/recovery/Notification.cpp | 132 ---- .../details/recovery/Notification.hpp | 200 ------- .../details/recovery/Notification_UT.cpp | 146 ----- .../details/supervision/Alive.cpp | 206 +++++-- .../details/supervision/Alive.hpp | 159 ++++- .../details/supervision/Alive_UT.cpp | 249 ++++++++ .../alive_monitor/details/supervision/BUILD | 62 +- .../details/supervision/Global.cpp | 565 ------------------ .../details/supervision/Global.hpp | 282 --------- .../supervision/ICheckpointSupervision.cpp | 128 ---- .../supervision/ICheckpointSupervision.hpp | 203 ------- .../details/supervision/ISupervision.hpp | 2 +- .../details/supervision/Local.cpp | 365 ----------- .../details/supervision/Local.hpp | 235 -------- .../details/supervision/SupervisionCfg.hpp | 157 +---- .../details/process_group_manager.cpp | 26 +- .../process_group_manager.hpp | 5 + .../src/recovery_client/irecovery_client.h | 15 +- .../src/recovery_client/recovery_client.cpp | 9 +- .../src/recovery_client/recovery_client.hpp | 6 +- .../recovery_client/recovery_client_UT.cpp | 32 +- scripts/config_mapping/lifecycle_config.py | 39 +- .../basic_test/expected_output/hm_demo.json | 78 +-- .../expected_output/hmproc_someip-daemon.json | 2 +- .../expected_output/hmproc_state_manager.json | 2 +- .../expected_output/hmproc_test_app1.json | 2 +- .../expected_output/hm_demo.json | 7 +- .../expected_output/hm_demo.json | 5 +- .../expected_output/hm_demo.json | 78 +-- ...hmproc_reporting_supervised_component.json | 2 +- ...sed_component_with_no_max_indications.json | 2 +- .../expected_output/hmproc_state_manager.json | 2 +- .../expected_output/hm_demo.json | 91 --- 51 files changed, 736 insertions(+), 3968 deletions(-) delete mode 100644 score/launch_manager/daemon/src/alive_monitor/details/recovery/BUILD delete mode 100644 score/launch_manager/daemon/src/alive_monitor/details/recovery/Notification.cpp delete mode 100644 score/launch_manager/daemon/src/alive_monitor/details/recovery/Notification.hpp delete mode 100644 score/launch_manager/daemon/src/alive_monitor/details/recovery/Notification_UT.cpp create mode 100644 score/launch_manager/daemon/src/alive_monitor/details/supervision/Alive_UT.cpp delete mode 100644 score/launch_manager/daemon/src/alive_monitor/details/supervision/Global.cpp delete mode 100644 score/launch_manager/daemon/src/alive_monitor/details/supervision/Global.hpp delete mode 100644 score/launch_manager/daemon/src/alive_monitor/details/supervision/ICheckpointSupervision.cpp delete mode 100644 score/launch_manager/daemon/src/alive_monitor/details/supervision/ICheckpointSupervision.hpp delete mode 100644 score/launch_manager/daemon/src/alive_monitor/details/supervision/Local.cpp delete mode 100644 score/launch_manager/daemon/src/alive_monitor/details/supervision/Local.hpp diff --git a/score/launch_manager/daemon/src/alive_monitor/Monitor.h b/score/launch_manager/daemon/src/alive_monitor/Monitor.h index ea85a73f5..a007ad784 100644 --- a/score/launch_manager/daemon/src/alive_monitor/Monitor.h +++ b/score/launch_manager/daemon/src/alive_monitor/Monitor.h @@ -24,49 +24,6 @@ namespace score::mw::lifecycle { -/// @brief Enumeration of elementary supervision status -enum class ElementarySupervisionStatus : std::uint32_t -{ - /// @brief Supervision is active and no failure is present. - kOK = 0U, - /// @brief A failure was detected but still within tolerance/debouncing. - kFailed = 1U, - /// @brief A failure was detected and qualified. - kExpired = 2U, - /// @brief Supervision is not active. - kDeactivated = 4U -}; - -/// @brief Enumeration of local supervision status -enum class LocalSupervisionStatus : std::uint32_t -{ - /// @brief Supervision is active and no failure is present. - kOK = 0U, - /// @brief A failure was detected but still within tolerance/debouncing. - kFailed = 1U, - /// @brief A failure was detected and qualified. - kExpired = 2U, - /// @brief Supervision is not active. - kDeactivated = 4U -}; - -/// @brief Enumeration of global supervision status -enum class GlobalSupervisionStatus : std::uint32_t -{ - /// @brief All relevant local supervisions are in status KOK or KDeactivated. - kOK = 0U, - /// @brief At least one local supervision is in status kFailed but none in status KExpired. - kFailed = 1U, - /// @brief At least one local supervision is in status kExpired but the number of - /// Supervision Cycles since reaching kExpired has not exceeded the tolerance. - kExpired = 2U, - /// @brief At least one local supervision is in status kExpired and the number of - /// Supervision Cycles since reaching kExpired has exceeded the tolerance. - kStopped = 3U, - /// @brief Supervision is not active. - kDeactivated = 4U -}; - /// @brief Monitor Class template class Monitor diff --git a/score/launch_manager/daemon/src/alive_monitor/MonitorImplWrapper.h b/score/launch_manager/daemon/src/alive_monitor/MonitorImplWrapper.h index c936d6d13..95c92422d 100644 --- a/score/launch_manager/daemon/src/alive_monitor/MonitorImplWrapper.h +++ b/score/launch_manager/daemon/src/alive_monitor/MonitorImplWrapper.h @@ -27,9 +27,6 @@ using Checkpoint = std::uint32_t; /// @brief Forward Declaration for them Implementation class for Monitor class MonitorImpl; -/// @brief Forward declaration of enumeration of local supervision status -enum class LocalSupervisionStatus : std::uint32_t; - /// @brief Wrapper of implementation class for score::mw::lifecycle::Monitor class /// This class is just a wrapper and forwards the calls from score::mw::lifecycle::Monitor class /// to the actual implementation class, i.e., score::mw::lifecycle::MonitorImpl diff --git a/score/launch_manager/daemon/src/alive_monitor/config/hm_flatcfg.fbs b/score/launch_manager/daemon/src/alive_monitor/config/hm_flatcfg.fbs index ea32ba7a9..df8ce1102 100644 --- a/score/launch_manager/daemon/src/alive_monitor/config/hm_flatcfg.fbs +++ b/score/launch_manager/daemon/src/alive_monitor/config/hm_flatcfg.fbs @@ -1,6 +1,6 @@ namespace HMFlatBuffer; -// HM version 8.0 +// HM version 8.1 file_identifier "BHMT"; file_extension "bin"; @@ -18,9 +18,6 @@ table HMEcuCfg { hmMonitorInterface: [HmMonitorInterface] (id:3); hmSupervisionCheckpoint: [HmSupervisionCheckpoint] (id:4); hmAliveSupervision: [HmAliveSupervision] (id:5); - hmLocalSupervision: [HmLocalSupervision] (id:6); - hmGlobalSupervision: [HmGlobalSupervision] (id:7); - hmRecoveryNotification: [RecoveryNotification] (id:8); } table Process { @@ -79,39 +76,4 @@ table HmAliveSupervision { refProcessGroupStates: [HmRefProcessGroupStates] (id:9); } -table HmLocalSupervision { - ruleContextKey: string (id:0); - infoRefInterfacePath: string (id:1); - hmRefAliveSupervision: [HmRefAliveSupervision] (id:2); -} - -table HmRefAliveSupervision { - ruleContextKey: int (id:0); - refAliveSupervisionIdx: uint32 (id:1); -} - -table HmGlobalSupervision { - ruleContextKey: string (id:0); - isSeverityCritical: bool (id:1); - localSupervision: [HmGlobalSupervisionLocalRef] (id:2); - refProcesses: [HmRefProcess] (id:3); - refProcessGroupStates: [HmRefProcessGroupStatesGlobal] (id:4); -} - -table HmGlobalSupervisionLocalRef { - refLocalSupervisionIndex: uint32 (id:0); -} - -table HmRefProcessGroupStatesGlobal { - identifier: string (id:0); - expiredSupervisionTolerance: double (id:1); -} - -table RecoveryNotification { - shortName: string (id:0, required); - processGroupMetaModelIdentifier: string (id:1); - refGlobalSupervisionIndex: uint32 (id:2); - shouldFireWatchdog: bool (id:3); -} - root_type HMEcuCfg; diff --git a/score/launch_manager/daemon/src/alive_monitor/config/hm_flatcfg_generated.h b/score/launch_manager/daemon/src/alive_monitor/config/hm_flatcfg_generated.h index fab01f69b..f1ff7e507 100644 --- a/score/launch_manager/daemon/src/alive_monitor/config/hm_flatcfg_generated.h +++ b/score/launch_manager/daemon/src/alive_monitor/config/hm_flatcfg_generated.h @@ -54,24 +54,6 @@ struct HmCheckpointTransitionBuilder; struct HmAliveSupervision; struct HmAliveSupervisionBuilder; -struct HmLocalSupervision; -struct HmLocalSupervisionBuilder; - -struct HmRefAliveSupervision; -struct HmRefAliveSupervisionBuilder; - -struct HmGlobalSupervision; -struct HmGlobalSupervisionBuilder; - -struct HmGlobalSupervisionLocalRef; -struct HmGlobalSupervisionLocalRefBuilder; - -struct HmRefProcessGroupStatesGlobal; -struct HmRefProcessGroupStatesGlobalBuilder; - -struct RecoveryNotification; -struct RecoveryNotificationBuilder; - enum ProcessType : int8_t { ProcessType_REGULAR_PROCESS = 0, ProcessType_LM_PROCESS = 1, @@ -113,10 +95,7 @@ struct HMEcuCfg FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { VT_PROCESS = 8, VT_HMMONITORINTERFACE = 10, VT_HMSUPERVISIONCHECKPOINT = 12, - VT_HMALIVESUPERVISION = 14, - VT_HMLOCALSUPERVISION = 16, - VT_HMGLOBALSUPERVISION = 18, - VT_HMRECOVERYNOTIFICATION = 20 + VT_HMALIVESUPERVISION = 14 }; int32_t versionMajor() const { return GetField(VT_VERSIONMAJOR, 0); @@ -136,15 +115,6 @@ struct HMEcuCfg FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { const ::flatbuffers::Vector<::flatbuffers::Offset> *hmAliveSupervision() const { return GetPointer> *>(VT_HMALIVESUPERVISION); } - const ::flatbuffers::Vector<::flatbuffers::Offset> *hmLocalSupervision() const { - return GetPointer> *>(VT_HMLOCALSUPERVISION); - } - const ::flatbuffers::Vector<::flatbuffers::Offset> *hmGlobalSupervision() const { - return GetPointer> *>(VT_HMGLOBALSUPERVISION); - } - const ::flatbuffers::Vector<::flatbuffers::Offset> *hmRecoveryNotification() const { - return GetPointer> *>(VT_HMRECOVERYNOTIFICATION); - } bool Verify(::flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, VT_VERSIONMAJOR, 4) && @@ -161,15 +131,6 @@ struct HMEcuCfg FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { VerifyOffset(verifier, VT_HMALIVESUPERVISION) && verifier.VerifyVector(hmAliveSupervision()) && verifier.VerifyVectorOfTables(hmAliveSupervision()) && - VerifyOffset(verifier, VT_HMLOCALSUPERVISION) && - verifier.VerifyVector(hmLocalSupervision()) && - verifier.VerifyVectorOfTables(hmLocalSupervision()) && - VerifyOffset(verifier, VT_HMGLOBALSUPERVISION) && - verifier.VerifyVector(hmGlobalSupervision()) && - verifier.VerifyVectorOfTables(hmGlobalSupervision()) && - VerifyOffset(verifier, VT_HMRECOVERYNOTIFICATION) && - verifier.VerifyVector(hmRecoveryNotification()) && - verifier.VerifyVectorOfTables(hmRecoveryNotification()) && verifier.EndTable(); } }; @@ -196,15 +157,6 @@ struct HMEcuCfgBuilder { void add_hmAliveSupervision(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> hmAliveSupervision) { fbb_.AddOffset(HMEcuCfg::VT_HMALIVESUPERVISION, hmAliveSupervision); } - void add_hmLocalSupervision(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> hmLocalSupervision) { - fbb_.AddOffset(HMEcuCfg::VT_HMLOCALSUPERVISION, hmLocalSupervision); - } - void add_hmGlobalSupervision(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> hmGlobalSupervision) { - fbb_.AddOffset(HMEcuCfg::VT_HMGLOBALSUPERVISION, hmGlobalSupervision); - } - void add_hmRecoveryNotification(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> hmRecoveryNotification) { - fbb_.AddOffset(HMEcuCfg::VT_HMRECOVERYNOTIFICATION, hmRecoveryNotification); - } explicit HMEcuCfgBuilder(::flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -223,14 +175,8 @@ inline ::flatbuffers::Offset CreateHMEcuCfg( ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> process = 0, ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> hmMonitorInterface = 0, ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> hmSupervisionCheckpoint = 0, - ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> hmAliveSupervision = 0, - ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> hmLocalSupervision = 0, - ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> hmGlobalSupervision = 0, - ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> hmRecoveryNotification = 0) { + ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> hmAliveSupervision = 0) { HMEcuCfgBuilder builder_(_fbb); - builder_.add_hmRecoveryNotification(hmRecoveryNotification); - builder_.add_hmGlobalSupervision(hmGlobalSupervision); - builder_.add_hmLocalSupervision(hmLocalSupervision); builder_.add_hmAliveSupervision(hmAliveSupervision); builder_.add_hmSupervisionCheckpoint(hmSupervisionCheckpoint); builder_.add_hmMonitorInterface(hmMonitorInterface); @@ -247,17 +193,11 @@ inline ::flatbuffers::Offset CreateHMEcuCfgDirect( const std::vector<::flatbuffers::Offset> *process = nullptr, const std::vector<::flatbuffers::Offset> *hmMonitorInterface = nullptr, const std::vector<::flatbuffers::Offset> *hmSupervisionCheckpoint = nullptr, - const std::vector<::flatbuffers::Offset> *hmAliveSupervision = nullptr, - const std::vector<::flatbuffers::Offset> *hmLocalSupervision = nullptr, - const std::vector<::flatbuffers::Offset> *hmGlobalSupervision = nullptr, - const std::vector<::flatbuffers::Offset> *hmRecoveryNotification = nullptr) { + const std::vector<::flatbuffers::Offset> *hmAliveSupervision = nullptr) { auto process__ = process ? _fbb.CreateVector<::flatbuffers::Offset>(*process) : 0; auto hmMonitorInterface__ = hmMonitorInterface ? _fbb.CreateVector<::flatbuffers::Offset>(*hmMonitorInterface) : 0; auto hmSupervisionCheckpoint__ = hmSupervisionCheckpoint ? _fbb.CreateVector<::flatbuffers::Offset>(*hmSupervisionCheckpoint) : 0; auto hmAliveSupervision__ = hmAliveSupervision ? _fbb.CreateVector<::flatbuffers::Offset>(*hmAliveSupervision) : 0; - auto hmLocalSupervision__ = hmLocalSupervision ? _fbb.CreateVector<::flatbuffers::Offset>(*hmLocalSupervision) : 0; - auto hmGlobalSupervision__ = hmGlobalSupervision ? _fbb.CreateVector<::flatbuffers::Offset>(*hmGlobalSupervision) : 0; - auto hmRecoveryNotification__ = hmRecoveryNotification ? _fbb.CreateVector<::flatbuffers::Offset>(*hmRecoveryNotification) : 0; return HMFlatBuffer::CreateHMEcuCfg( _fbb, versionMajor, @@ -265,10 +205,7 @@ inline ::flatbuffers::Offset CreateHMEcuCfgDirect( process__, hmMonitorInterface__, hmSupervisionCheckpoint__, - hmAliveSupervision__, - hmLocalSupervision__, - hmGlobalSupervision__, - hmRecoveryNotification__); + hmAliveSupervision__); } struct Process FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { @@ -950,439 +887,6 @@ inline ::flatbuffers::Offset CreateHmAliveSupervisionDirect( refProcessGroupStates__); } -struct HmLocalSupervision FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { - typedef HmLocalSupervisionBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_RULECONTEXTKEY = 4, - VT_INFOREFINTERFACEPATH = 6, - VT_HMREFALIVESUPERVISION = 8 - }; - const ::flatbuffers::String *ruleContextKey() const { - return GetPointer(VT_RULECONTEXTKEY); - } - const ::flatbuffers::String *infoRefInterfacePath() const { - return GetPointer(VT_INFOREFINTERFACEPATH); - } - const ::flatbuffers::Vector<::flatbuffers::Offset> *hmRefAliveSupervision() const { - return GetPointer> *>(VT_HMREFALIVESUPERVISION); - } - bool Verify(::flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyOffset(verifier, VT_RULECONTEXTKEY) && - verifier.VerifyString(ruleContextKey()) && - VerifyOffset(verifier, VT_INFOREFINTERFACEPATH) && - verifier.VerifyString(infoRefInterfacePath()) && - VerifyOffset(verifier, VT_HMREFALIVESUPERVISION) && - verifier.VerifyVector(hmRefAliveSupervision()) && - verifier.VerifyVectorOfTables(hmRefAliveSupervision()) && - verifier.EndTable(); - } -}; - -struct HmLocalSupervisionBuilder { - typedef HmLocalSupervision Table; - ::flatbuffers::FlatBufferBuilder &fbb_; - ::flatbuffers::uoffset_t start_; - void add_ruleContextKey(::flatbuffers::Offset<::flatbuffers::String> ruleContextKey) { - fbb_.AddOffset(HmLocalSupervision::VT_RULECONTEXTKEY, ruleContextKey); - } - void add_infoRefInterfacePath(::flatbuffers::Offset<::flatbuffers::String> infoRefInterfacePath) { - fbb_.AddOffset(HmLocalSupervision::VT_INFOREFINTERFACEPATH, infoRefInterfacePath); - } - void add_hmRefAliveSupervision(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> hmRefAliveSupervision) { - fbb_.AddOffset(HmLocalSupervision::VT_HMREFALIVESUPERVISION, hmRefAliveSupervision); - } - explicit HmLocalSupervisionBuilder(::flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - ::flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_); - auto o = ::flatbuffers::Offset(end); - return o; - } -}; - -inline ::flatbuffers::Offset CreateHmLocalSupervision( - ::flatbuffers::FlatBufferBuilder &_fbb, - ::flatbuffers::Offset<::flatbuffers::String> ruleContextKey = 0, - ::flatbuffers::Offset<::flatbuffers::String> infoRefInterfacePath = 0, - ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> hmRefAliveSupervision = 0) { - HmLocalSupervisionBuilder builder_(_fbb); - builder_.add_hmRefAliveSupervision(hmRefAliveSupervision); - builder_.add_infoRefInterfacePath(infoRefInterfacePath); - builder_.add_ruleContextKey(ruleContextKey); - return builder_.Finish(); -} - -inline ::flatbuffers::Offset CreateHmLocalSupervisionDirect( - ::flatbuffers::FlatBufferBuilder &_fbb, - const char *ruleContextKey = nullptr, - const char *infoRefInterfacePath = nullptr, - const std::vector<::flatbuffers::Offset> *hmRefAliveSupervision = nullptr) { - auto ruleContextKey__ = ruleContextKey ? _fbb.CreateString(ruleContextKey) : 0; - auto infoRefInterfacePath__ = infoRefInterfacePath ? _fbb.CreateString(infoRefInterfacePath) : 0; - auto hmRefAliveSupervision__ = hmRefAliveSupervision ? _fbb.CreateVector<::flatbuffers::Offset>(*hmRefAliveSupervision) : 0; - return HMFlatBuffer::CreateHmLocalSupervision( - _fbb, - ruleContextKey__, - infoRefInterfacePath__, - hmRefAliveSupervision__); -} - -struct HmRefAliveSupervision FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { - typedef HmRefAliveSupervisionBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_RULECONTEXTKEY = 4, - VT_REFALIVESUPERVISIONIDX = 6 - }; - int32_t ruleContextKey() const { - return GetField(VT_RULECONTEXTKEY, 0); - } - uint32_t refAliveSupervisionIdx() const { - return GetField(VT_REFALIVESUPERVISIONIDX, 0); - } - bool Verify(::flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField(verifier, VT_RULECONTEXTKEY, 4) && - VerifyField(verifier, VT_REFALIVESUPERVISIONIDX, 4) && - verifier.EndTable(); - } -}; - -struct HmRefAliveSupervisionBuilder { - typedef HmRefAliveSupervision Table; - ::flatbuffers::FlatBufferBuilder &fbb_; - ::flatbuffers::uoffset_t start_; - void add_ruleContextKey(int32_t ruleContextKey) { - fbb_.AddElement(HmRefAliveSupervision::VT_RULECONTEXTKEY, ruleContextKey, 0); - } - void add_refAliveSupervisionIdx(uint32_t refAliveSupervisionIdx) { - fbb_.AddElement(HmRefAliveSupervision::VT_REFALIVESUPERVISIONIDX, refAliveSupervisionIdx, 0); - } - explicit HmRefAliveSupervisionBuilder(::flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - ::flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_); - auto o = ::flatbuffers::Offset(end); - return o; - } -}; - -inline ::flatbuffers::Offset CreateHmRefAliveSupervision( - ::flatbuffers::FlatBufferBuilder &_fbb, - int32_t ruleContextKey = 0, - uint32_t refAliveSupervisionIdx = 0) { - HmRefAliveSupervisionBuilder builder_(_fbb); - builder_.add_refAliveSupervisionIdx(refAliveSupervisionIdx); - builder_.add_ruleContextKey(ruleContextKey); - return builder_.Finish(); -} - -struct HmGlobalSupervision FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { - typedef HmGlobalSupervisionBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_RULECONTEXTKEY = 4, - VT_ISSEVERITYCRITICAL = 6, - VT_LOCALSUPERVISION = 8, - VT_REFPROCESSES = 10, - VT_REFPROCESSGROUPSTATES = 12 - }; - const ::flatbuffers::String *ruleContextKey() const { - return GetPointer(VT_RULECONTEXTKEY); - } - bool isSeverityCritical() const { - return GetField(VT_ISSEVERITYCRITICAL, 0) != 0; - } - const ::flatbuffers::Vector<::flatbuffers::Offset> *localSupervision() const { - return GetPointer> *>(VT_LOCALSUPERVISION); - } - const ::flatbuffers::Vector<::flatbuffers::Offset> *refProcesses() const { - return GetPointer> *>(VT_REFPROCESSES); - } - const ::flatbuffers::Vector<::flatbuffers::Offset> *refProcessGroupStates() const { - return GetPointer> *>(VT_REFPROCESSGROUPSTATES); - } - bool Verify(::flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyOffset(verifier, VT_RULECONTEXTKEY) && - verifier.VerifyString(ruleContextKey()) && - VerifyField(verifier, VT_ISSEVERITYCRITICAL, 1) && - VerifyOffset(verifier, VT_LOCALSUPERVISION) && - verifier.VerifyVector(localSupervision()) && - verifier.VerifyVectorOfTables(localSupervision()) && - VerifyOffset(verifier, VT_REFPROCESSES) && - verifier.VerifyVector(refProcesses()) && - verifier.VerifyVectorOfTables(refProcesses()) && - VerifyOffset(verifier, VT_REFPROCESSGROUPSTATES) && - verifier.VerifyVector(refProcessGroupStates()) && - verifier.VerifyVectorOfTables(refProcessGroupStates()) && - verifier.EndTable(); - } -}; - -struct HmGlobalSupervisionBuilder { - typedef HmGlobalSupervision Table; - ::flatbuffers::FlatBufferBuilder &fbb_; - ::flatbuffers::uoffset_t start_; - void add_ruleContextKey(::flatbuffers::Offset<::flatbuffers::String> ruleContextKey) { - fbb_.AddOffset(HmGlobalSupervision::VT_RULECONTEXTKEY, ruleContextKey); - } - void add_isSeverityCritical(bool isSeverityCritical) { - fbb_.AddElement(HmGlobalSupervision::VT_ISSEVERITYCRITICAL, static_cast(isSeverityCritical), 0); - } - void add_localSupervision(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> localSupervision) { - fbb_.AddOffset(HmGlobalSupervision::VT_LOCALSUPERVISION, localSupervision); - } - void add_refProcesses(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> refProcesses) { - fbb_.AddOffset(HmGlobalSupervision::VT_REFPROCESSES, refProcesses); - } - void add_refProcessGroupStates(::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> refProcessGroupStates) { - fbb_.AddOffset(HmGlobalSupervision::VT_REFPROCESSGROUPSTATES, refProcessGroupStates); - } - explicit HmGlobalSupervisionBuilder(::flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - ::flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_); - auto o = ::flatbuffers::Offset(end); - return o; - } -}; - -inline ::flatbuffers::Offset CreateHmGlobalSupervision( - ::flatbuffers::FlatBufferBuilder &_fbb, - ::flatbuffers::Offset<::flatbuffers::String> ruleContextKey = 0, - bool isSeverityCritical = false, - ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> localSupervision = 0, - ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> refProcesses = 0, - ::flatbuffers::Offset<::flatbuffers::Vector<::flatbuffers::Offset>> refProcessGroupStates = 0) { - HmGlobalSupervisionBuilder builder_(_fbb); - builder_.add_refProcessGroupStates(refProcessGroupStates); - builder_.add_refProcesses(refProcesses); - builder_.add_localSupervision(localSupervision); - builder_.add_ruleContextKey(ruleContextKey); - builder_.add_isSeverityCritical(isSeverityCritical); - return builder_.Finish(); -} - -inline ::flatbuffers::Offset CreateHmGlobalSupervisionDirect( - ::flatbuffers::FlatBufferBuilder &_fbb, - const char *ruleContextKey = nullptr, - bool isSeverityCritical = false, - const std::vector<::flatbuffers::Offset> *localSupervision = nullptr, - const std::vector<::flatbuffers::Offset> *refProcesses = nullptr, - const std::vector<::flatbuffers::Offset> *refProcessGroupStates = nullptr) { - auto ruleContextKey__ = ruleContextKey ? _fbb.CreateString(ruleContextKey) : 0; - auto localSupervision__ = localSupervision ? _fbb.CreateVector<::flatbuffers::Offset>(*localSupervision) : 0; - auto refProcesses__ = refProcesses ? _fbb.CreateVector<::flatbuffers::Offset>(*refProcesses) : 0; - auto refProcessGroupStates__ = refProcessGroupStates ? _fbb.CreateVector<::flatbuffers::Offset>(*refProcessGroupStates) : 0; - return HMFlatBuffer::CreateHmGlobalSupervision( - _fbb, - ruleContextKey__, - isSeverityCritical, - localSupervision__, - refProcesses__, - refProcessGroupStates__); -} - -struct HmGlobalSupervisionLocalRef FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { - typedef HmGlobalSupervisionLocalRefBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_REFLOCALSUPERVISIONINDEX = 4 - }; - uint32_t refLocalSupervisionIndex() const { - return GetField(VT_REFLOCALSUPERVISIONINDEX, 0); - } - bool Verify(::flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField(verifier, VT_REFLOCALSUPERVISIONINDEX, 4) && - verifier.EndTable(); - } -}; - -struct HmGlobalSupervisionLocalRefBuilder { - typedef HmGlobalSupervisionLocalRef Table; - ::flatbuffers::FlatBufferBuilder &fbb_; - ::flatbuffers::uoffset_t start_; - void add_refLocalSupervisionIndex(uint32_t refLocalSupervisionIndex) { - fbb_.AddElement(HmGlobalSupervisionLocalRef::VT_REFLOCALSUPERVISIONINDEX, refLocalSupervisionIndex, 0); - } - explicit HmGlobalSupervisionLocalRefBuilder(::flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - ::flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_); - auto o = ::flatbuffers::Offset(end); - return o; - } -}; - -inline ::flatbuffers::Offset CreateHmGlobalSupervisionLocalRef( - ::flatbuffers::FlatBufferBuilder &_fbb, - uint32_t refLocalSupervisionIndex = 0) { - HmGlobalSupervisionLocalRefBuilder builder_(_fbb); - builder_.add_refLocalSupervisionIndex(refLocalSupervisionIndex); - return builder_.Finish(); -} - -struct HmRefProcessGroupStatesGlobal FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { - typedef HmRefProcessGroupStatesGlobalBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_IDENTIFIER = 4, - VT_EXPIREDSUPERVISIONTOLERANCE = 6 - }; - const ::flatbuffers::String *identifier() const { - return GetPointer(VT_IDENTIFIER); - } - double expiredSupervisionTolerance() const { - return GetField(VT_EXPIREDSUPERVISIONTOLERANCE, 0.0); - } - bool Verify(::flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyOffset(verifier, VT_IDENTIFIER) && - verifier.VerifyString(identifier()) && - VerifyField(verifier, VT_EXPIREDSUPERVISIONTOLERANCE, 8) && - verifier.EndTable(); - } -}; - -struct HmRefProcessGroupStatesGlobalBuilder { - typedef HmRefProcessGroupStatesGlobal Table; - ::flatbuffers::FlatBufferBuilder &fbb_; - ::flatbuffers::uoffset_t start_; - void add_identifier(::flatbuffers::Offset<::flatbuffers::String> identifier) { - fbb_.AddOffset(HmRefProcessGroupStatesGlobal::VT_IDENTIFIER, identifier); - } - void add_expiredSupervisionTolerance(double expiredSupervisionTolerance) { - fbb_.AddElement(HmRefProcessGroupStatesGlobal::VT_EXPIREDSUPERVISIONTOLERANCE, expiredSupervisionTolerance, 0.0); - } - explicit HmRefProcessGroupStatesGlobalBuilder(::flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - ::flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_); - auto o = ::flatbuffers::Offset(end); - return o; - } -}; - -inline ::flatbuffers::Offset CreateHmRefProcessGroupStatesGlobal( - ::flatbuffers::FlatBufferBuilder &_fbb, - ::flatbuffers::Offset<::flatbuffers::String> identifier = 0, - double expiredSupervisionTolerance = 0.0) { - HmRefProcessGroupStatesGlobalBuilder builder_(_fbb); - builder_.add_expiredSupervisionTolerance(expiredSupervisionTolerance); - builder_.add_identifier(identifier); - return builder_.Finish(); -} - -inline ::flatbuffers::Offset CreateHmRefProcessGroupStatesGlobalDirect( - ::flatbuffers::FlatBufferBuilder &_fbb, - const char *identifier = nullptr, - double expiredSupervisionTolerance = 0.0) { - auto identifier__ = identifier ? _fbb.CreateString(identifier) : 0; - return HMFlatBuffer::CreateHmRefProcessGroupStatesGlobal( - _fbb, - identifier__, - expiredSupervisionTolerance); -} - -struct RecoveryNotification FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { - typedef RecoveryNotificationBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_SHORTNAME = 4, - VT_PROCESSGROUPMETAMODELIDENTIFIER = 6, - VT_REFGLOBALSUPERVISIONINDEX = 8, - VT_SHOULDFIREWATCHDOG = 10 - }; - const ::flatbuffers::String *shortName() const { - return GetPointer(VT_SHORTNAME); - } - const ::flatbuffers::String *processGroupMetaModelIdentifier() const { - return GetPointer(VT_PROCESSGROUPMETAMODELIDENTIFIER); - } - uint32_t refGlobalSupervisionIndex() const { - return GetField(VT_REFGLOBALSUPERVISIONINDEX, 0); - } - bool shouldFireWatchdog() const { - return GetField(VT_SHOULDFIREWATCHDOG, 0) != 0; - } - bool Verify(::flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyOffsetRequired(verifier, VT_SHORTNAME) && - verifier.VerifyString(shortName()) && - VerifyOffset(verifier, VT_PROCESSGROUPMETAMODELIDENTIFIER) && - verifier.VerifyString(processGroupMetaModelIdentifier()) && - VerifyField(verifier, VT_REFGLOBALSUPERVISIONINDEX, 4) && - VerifyField(verifier, VT_SHOULDFIREWATCHDOG, 1) && - verifier.EndTable(); - } -}; - -struct RecoveryNotificationBuilder { - typedef RecoveryNotification Table; - ::flatbuffers::FlatBufferBuilder &fbb_; - ::flatbuffers::uoffset_t start_; - void add_shortName(::flatbuffers::Offset<::flatbuffers::String> shortName) { - fbb_.AddOffset(RecoveryNotification::VT_SHORTNAME, shortName); - } - void add_processGroupMetaModelIdentifier(::flatbuffers::Offset<::flatbuffers::String> processGroupMetaModelIdentifier) { - fbb_.AddOffset(RecoveryNotification::VT_PROCESSGROUPMETAMODELIDENTIFIER, processGroupMetaModelIdentifier); - } - void add_refGlobalSupervisionIndex(uint32_t refGlobalSupervisionIndex) { - fbb_.AddElement(RecoveryNotification::VT_REFGLOBALSUPERVISIONINDEX, refGlobalSupervisionIndex, 0); - } - void add_shouldFireWatchdog(bool shouldFireWatchdog) { - fbb_.AddElement(RecoveryNotification::VT_SHOULDFIREWATCHDOG, static_cast(shouldFireWatchdog), 0); - } - explicit RecoveryNotificationBuilder(::flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - ::flatbuffers::Offset Finish() { - const auto end = fbb_.EndTable(start_); - auto o = ::flatbuffers::Offset(end); - fbb_.Required(o, RecoveryNotification::VT_SHORTNAME); - return o; - } -}; - -inline ::flatbuffers::Offset CreateRecoveryNotification( - ::flatbuffers::FlatBufferBuilder &_fbb, - ::flatbuffers::Offset<::flatbuffers::String> shortName = 0, - ::flatbuffers::Offset<::flatbuffers::String> processGroupMetaModelIdentifier = 0, - uint32_t refGlobalSupervisionIndex = 0, - bool shouldFireWatchdog = false) { - RecoveryNotificationBuilder builder_(_fbb); - builder_.add_refGlobalSupervisionIndex(refGlobalSupervisionIndex); - builder_.add_processGroupMetaModelIdentifier(processGroupMetaModelIdentifier); - builder_.add_shortName(shortName); - builder_.add_shouldFireWatchdog(shouldFireWatchdog); - return builder_.Finish(); -} - -inline ::flatbuffers::Offset CreateRecoveryNotificationDirect( - ::flatbuffers::FlatBufferBuilder &_fbb, - const char *shortName = nullptr, - const char *processGroupMetaModelIdentifier = nullptr, - uint32_t refGlobalSupervisionIndex = 0, - bool shouldFireWatchdog = false) { - auto shortName__ = shortName ? _fbb.CreateString(shortName) : 0; - auto processGroupMetaModelIdentifier__ = processGroupMetaModelIdentifier ? _fbb.CreateString(processGroupMetaModelIdentifier) : 0; - return HMFlatBuffer::CreateRecoveryNotification( - _fbb, - shortName__, - processGroupMetaModelIdentifier__, - refGlobalSupervisionIndex, - shouldFireWatchdog); -} - inline const HMFlatBuffer::HMEcuCfg *GetHMEcuCfg(const void *buf) { return ::flatbuffers::GetRoot(buf); } diff --git a/score/launch_manager/daemon/src/alive_monitor/config/hmcore_flatcfg.fbs b/score/launch_manager/daemon/src/alive_monitor/config/hmcore_flatcfg.fbs index 9cf8826c0..067b96c11 100644 --- a/score/launch_manager/daemon/src/alive_monitor/config/hmcore_flatcfg.fbs +++ b/score/launch_manager/daemon/src/alive_monitor/config/hmcore_flatcfg.fbs @@ -26,8 +26,6 @@ table HmConfig { periodicity: uint32 (id:0); bufferSizeMonitor: uint16 (id:1); bufferSizeAliveSupervision: uint16 (id:2); - bufferSizeLocalSupervision: uint16 (id:3); - bufferSizeGlobalSupervision: uint16 (id:4); } root_type HMCOREEcuCfg; diff --git a/score/launch_manager/daemon/src/alive_monitor/config/hmcore_flatcfg_generated.h b/score/launch_manager/daemon/src/alive_monitor/config/hmcore_flatcfg_generated.h index 4d3fb96d6..b8012ed5b 100644 --- a/score/launch_manager/daemon/src/alive_monitor/config/hmcore_flatcfg_generated.h +++ b/score/launch_manager/daemon/src/alive_monitor/config/hmcore_flatcfg_generated.h @@ -257,9 +257,7 @@ struct HmConfig FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { VT_PERIODICITY = 4, VT_BUFFERSIZEMONITOR = 6, - VT_BUFFERSIZEALIVESUPERVISION = 8, - VT_BUFFERSIZELOCALSUPERVISION = 10, - VT_BUFFERSIZEGLOBALSUPERVISION = 12 + VT_BUFFERSIZEALIVESUPERVISION = 8 }; uint32_t periodicity() const { return GetField(VT_PERIODICITY, 0); @@ -270,19 +268,11 @@ struct HmConfig FLATBUFFERS_FINAL_CLASS : private ::flatbuffers::Table { uint16_t bufferSizeAliveSupervision() const { return GetField(VT_BUFFERSIZEALIVESUPERVISION, 0); } - uint16_t bufferSizeLocalSupervision() const { - return GetField(VT_BUFFERSIZELOCALSUPERVISION, 0); - } - uint16_t bufferSizeGlobalSupervision() const { - return GetField(VT_BUFFERSIZEGLOBALSUPERVISION, 0); - } bool Verify(::flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyField(verifier, VT_PERIODICITY, 4) && VerifyField(verifier, VT_BUFFERSIZEMONITOR, 2) && VerifyField(verifier, VT_BUFFERSIZEALIVESUPERVISION, 2) && - VerifyField(verifier, VT_BUFFERSIZELOCALSUPERVISION, 2) && - VerifyField(verifier, VT_BUFFERSIZEGLOBALSUPERVISION, 2) && verifier.EndTable(); } }; @@ -300,12 +290,6 @@ struct HmConfigBuilder { void add_bufferSizeAliveSupervision(uint16_t bufferSizeAliveSupervision) { fbb_.AddElement(HmConfig::VT_BUFFERSIZEALIVESUPERVISION, bufferSizeAliveSupervision, 0); } - void add_bufferSizeLocalSupervision(uint16_t bufferSizeLocalSupervision) { - fbb_.AddElement(HmConfig::VT_BUFFERSIZELOCALSUPERVISION, bufferSizeLocalSupervision, 0); - } - void add_bufferSizeGlobalSupervision(uint16_t bufferSizeGlobalSupervision) { - fbb_.AddElement(HmConfig::VT_BUFFERSIZEGLOBALSUPERVISION, bufferSizeGlobalSupervision, 0); - } explicit HmConfigBuilder(::flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -321,13 +305,9 @@ inline ::flatbuffers::Offset CreateHmConfig( ::flatbuffers::FlatBufferBuilder &_fbb, uint32_t periodicity = 0, uint16_t bufferSizeMonitor = 0, - uint16_t bufferSizeAliveSupervision = 0, - uint16_t bufferSizeLocalSupervision = 0, - uint16_t bufferSizeGlobalSupervision = 0) { + uint16_t bufferSizeAliveSupervision = 0) { HmConfigBuilder builder_(_fbb); builder_.add_periodicity(periodicity); - builder_.add_bufferSizeGlobalSupervision(bufferSizeGlobalSupervision); - builder_.add_bufferSizeLocalSupervision(bufferSizeLocalSupervision); builder_.add_bufferSizeAliveSupervision(bufferSizeAliveSupervision); builder_.add_bufferSizeMonitor(bufferSizeMonitor); return builder_.Finish(); diff --git a/score/launch_manager/daemon/src/alive_monitor/details/daemon/BUILD b/score/launch_manager/daemon/src/alive_monitor/details/daemon/BUILD index 7fedbdda3..5b767374c 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/daemon/BUILD +++ b/score/launch_manager/daemon/src/alive_monitor/details/daemon/BUILD @@ -36,10 +36,7 @@ cc_library( "//score/launch_manager/daemon/src/alive_monitor/details/ifexm:process_state", "//score/launch_manager/daemon/src/alive_monitor/details/ifexm:process_state_reader", "//score/launch_manager/daemon/src/alive_monitor/details/logging:phm_logging", - "//score/launch_manager/daemon/src/alive_monitor/details/recovery:notification", "//score/launch_manager/daemon/src/alive_monitor/details/supervision:alive", - "//score/launch_manager/daemon/src/alive_monitor/details/supervision:global", - "//score/launch_manager/daemon/src/alive_monitor/details/supervision:local", "//score/launch_manager/daemon/src/alive_monitor/details/timers:timers_os_clock", ], ) @@ -61,8 +58,6 @@ cc_library( "//score/launch_manager/daemon/src/alive_monitor/details/ifexm:process_state_reader", "//score/launch_manager/daemon/src/alive_monitor/details/logging:phm_logging", "//score/launch_manager/daemon/src/alive_monitor/details/supervision:alive", - "//score/launch_manager/daemon/src/alive_monitor/details/supervision:global", - "//score/launch_manager/daemon/src/alive_monitor/details/supervision:local", "//score/launch_manager/daemon/src/alive_monitor/details/timers:cycle_time_validator", "//score/launch_manager/daemon/src/alive_monitor/details/timers:cycle_timer", "//score/launch_manager/daemon/src/alive_monitor/details/timers:timers_os_clock", diff --git a/score/launch_manager/daemon/src/alive_monitor/details/daemon/PhmDaemon.cpp b/score/launch_manager/daemon/src/alive_monitor/details/daemon/PhmDaemon.cpp index 0f8518d51..bc8fef0e7 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/daemon/PhmDaemon.cpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/daemon/PhmDaemon.cpp @@ -16,8 +16,6 @@ #include "score/mw/launch_manager/alive_monitor/details/factory/FlatCfgFactory.hpp" #include "score/mw/launch_manager/alive_monitor/details/ifappl/MonitorIfDaemon.hpp" #include "score/mw/launch_manager/alive_monitor/details/supervision/Alive.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/Global.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/Local.hpp" #include "score/mw/launch_manager/alive_monitor/details/timers/Timers_OsClock.hpp" namespace score @@ -33,9 +31,16 @@ 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(score::lcm::saf::timers::OsClockInterface& f_osClock, logging::PhmLogger& f_logger_r, - std::unique_ptr f_watchdog, std::unique_ptr f_process_state_receiver) : - osClock{f_osClock}, cycleTimer{&osClock}, logger_r{f_logger_r}, swClusterHandlers{}, processStateReader{std::move(f_process_state_receiver)}, watchdog(std::move(f_watchdog)) +PhmDaemon::PhmDaemon(score::lcm::saf::timers::OsClockInterface& f_osClock, + logging::PhmLogger& f_logger_r, + std::unique_ptr f_watchdog, + std::unique_ptr f_process_state_receiver) + : osClock{f_osClock}, + cycleTimer{&osClock}, + logger_r{f_logger_r}, + swClusterHandlers{}, + processStateReader{std::move(f_process_state_receiver)}, + watchdog(std::move(f_watchdog)) { static_cast(f_osClock); } @@ -59,14 +64,12 @@ void PhmDaemon::performCyclicTriggers(void) for (auto& phmHandler : swClusterHandlers) { phmHandler.performCyclicTriggers(syncTimestamp); - isCriticalFailure = isCriticalFailure || phmHandler.hasRecoveryNotificationTimeout(); + isCriticalFailure = isCriticalFailure || phmHandler.hasAnyRecoveryEnqueueFailed(); } } // watchdog is fired iff: - // * A timeout occurs for any RecoveryNotification sent to SM - // * Global Supervision reached status GLOBAL_STATUS_STOPPED for a supervision of SM or LM. In this case the - // recovery notification goes directly to timeout state + // * isCriticalFailure is set (e.g. process state distribution error, recovery ring buffer full) // else: // * watchdog is serviced if (!isCriticalFailure) @@ -105,8 +108,7 @@ bool PhmDaemon::construct(const factory::MachineConfigFactory::SupervisionBuffer for (auto strSwClusterName : listSwClustersPhm.value()) { swClusterHandlers.emplace_back(strSwClusterName); - isSuccess = - swClusterHandlers.back().constructWorkers(recoveryClient, processStateReader, f_bufferConfig_r); + isSuccess = swClusterHandlers.back().constructWorkers(recoveryClient, processStateReader, f_bufferConfig_r); if (!isSuccess) { logger_r.LogError() << "Phm Daemon: failed to create worker objects for swclusterhandler:" diff --git a/score/launch_manager/daemon/src/alive_monitor/details/daemon/SwClusterHandler.cpp b/score/launch_manager/daemon/src/alive_monitor/details/daemon/SwClusterHandler.cpp index dfc3f40f2..5a5643465 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/daemon/SwClusterHandler.cpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/daemon/SwClusterHandler.cpp @@ -17,8 +17,6 @@ #include "score/mw/launch_manager/alive_monitor/details/ifappl/Checkpoint.hpp" #include "score/mw/launch_manager/alive_monitor/details/ifappl/MonitorIfDaemon.hpp" #include "score/mw/launch_manager/alive_monitor/details/supervision/Alive.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/Global.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/Local.hpp" namespace score { @@ -29,17 +27,14 @@ namespace saf namespace daemon { -SwClusterHandler::SwClusterHandler(const std::string& f_swClusterName_r) : - logger_r(logging::PhmLogger::getLogger(logging::PhmLogger::EContext::factory)), - f_swClusterName(f_swClusterName_r), - processStates{}, - monitorIfIpcs{}, - monitorInterfaces{}, - checkpoints{}, - aliveSupervisions{}, - localSupervisions{}, - globalSupervisions{}, - recoveryNotifications{} +SwClusterHandler::SwClusterHandler(const std::string& f_swClusterName_r) + : logger_r(logging::PhmLogger::getLogger(logging::PhmLogger::EContext::factory)), + f_swClusterName(f_swClusterName_r), + processStates{}, + monitorIfIpcs{}, + monitorInterfaces{}, + checkpoints{}, + aliveSupervisions{} { if (f_swClusterName_r.empty()) { @@ -51,7 +46,9 @@ SwClusterHandler::~SwClusterHandler() = default; /* RULECHECKER_comment(0, 3, check_max_cyclomatic_complexity, "Max cyclomatic complexity violation\ is tolerated for this function. ", true_no_defect) */ -bool SwClusterHandler::constructWorkers(std::shared_ptr f_recoveryClient_r, ifexm::ProcessStateReader& f_processStateReader_r, +bool SwClusterHandler::constructWorkers( + std::shared_ptr f_recoveryClient_r, + ifexm::ProcessStateReader& f_processStateReader_r, const factory::MachineConfigFactory::SupervisionBufferConfig& f_bufferConfig_r) noexcept(false) { bool isSuccess{false}; @@ -70,8 +67,7 @@ bool SwClusterHandler::constructWorkers(std::shared_ptr -#include #include "score/mw/launch_manager/alive_monitor/details/factory/MachineConfigFactory.hpp" #include "score/mw/launch_manager/alive_monitor/details/ifappl/DataStructures.hpp" #include "score/mw/launch_manager/alive_monitor/details/ifexm/ProcessState.hpp" #include "score/mw/launch_manager/alive_monitor/details/ifexm/ProcessStateReader.hpp" #include "score/mw/launch_manager/alive_monitor/details/logging/PhmLogger.hpp" -#include "score/mw/launch_manager/alive_monitor/details/recovery/Notification.hpp" #include "score/mw/launch_manager/alive_monitor/details/timers/Timers_OsClock.hpp" +#include +#include namespace score { namespace lcm { + +class IRecoveryClient; + namespace saf { @@ -42,8 +43,6 @@ class Checkpoint; namespace supervision { class Alive; -class Local; -class Global; } // namespace supervision // End Forward declarations @@ -57,7 +56,7 @@ namespace daemon /// for a given Software Cluster. It also provides an abstracted interface to trigger the cyclic evaluation. class SwClusterHandler { -public: + public: /// @brief No Default Constructor SwClusterHandler() = delete; @@ -93,7 +92,8 @@ class SwClusterHandler /// @param [in] f_bufferConfig_r Configuration settings for constructing workers /// @return Construction is successful (true), otherwise failure (false) bool constructWorkers( - std::shared_ptr f_recoveryClient_r, ifexm::ProcessStateReader& f_processStateReader_r, + std::shared_ptr f_recoveryClient_r, + ifexm::ProcessStateReader& f_processStateReader_r, const factory::MachineConfigFactory::SupervisionBufferConfig& f_bufferConfig_r) noexcept(false); /// @brief Perform cyclic execution @@ -101,11 +101,11 @@ class SwClusterHandler /// @param [in] f_syncTimestamp Timestamp for cyclic synchronization void performCyclicTriggers(const timers::NanoSecondType f_syncTimestamp); - /// @brief Check for recovery notificaiton timeout - /// @return True, if any recovery notification has a timeout. Else false. - bool hasRecoveryNotificationTimeout() const noexcept; + /// @brief Check whether any alive supervision failed to enqueue a recovery request + /// @return True if any alive supervision recovery request has failed + bool hasAnyRecoveryEnqueueFailed() const noexcept; -private: + private: /// @brief Check interfaces for new data /// @details All interfaces created during construction will be checked for new data. /// @param [in] f_syncTimestamp Timestamp for cyclic synchronization @@ -116,11 +116,6 @@ class SwClusterHandler /// @param [in] f_syncTimestamp Timestamp for cyclic synchronization void evaluateSupervisions(const timers::NanoSecondType f_syncTimestamp); - /// @brief Evaluate recovery notifications - /// @details Evaluate all recovery notifications created during construction. - /// @note Has to be called after evaluateGlobalSupervisions - void evaluateRecoveryNotifications(void); - /// @brief Logger logging::PhmLogger& logger_r; @@ -141,15 +136,6 @@ class SwClusterHandler /// Vector of Alive Supervisions std::vector aliveSupervisions; - - /// Vector of Local Supervisions - std::vector localSupervisions; - - /// Vector of Global Supervisions - std::vector globalSupervisions; - - /// Vector of Recovery Notifications - std::vector recoveryNotifications; }; } // namespace daemon diff --git a/score/launch_manager/daemon/src/alive_monitor/details/factory/BUILD b/score/launch_manager/daemon/src/alive_monitor/details/factory/BUILD index 760e1c207..8ecfb62cd 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/factory/BUILD +++ b/score/launch_manager/daemon/src/alive_monitor/details/factory/BUILD @@ -74,10 +74,7 @@ cc_library( "//score/launch_manager/daemon/src/alive_monitor/details/ifexm:process_state", "//score/launch_manager/daemon/src/alive_monitor/details/ifexm:process_state_reader", "//score/launch_manager/daemon/src/alive_monitor/details/logging:phm_logging", - "//score/launch_manager/daemon/src/alive_monitor/details/recovery:notification", "//score/launch_manager/daemon/src/alive_monitor/details/supervision:alive", - "//score/launch_manager/daemon/src/alive_monitor/details/supervision:global", - "//score/launch_manager/daemon/src/alive_monitor/details/supervision:local", "//score/launch_manager/daemon/src/alive_monitor/details/supervision:supervision_cfg", "//score/launch_manager/daemon/src/alive_monitor/details/timers:time_conversion", "//score/launch_manager/daemon/src/alive_monitor/details/timers:timers_os_clock", diff --git a/score/launch_manager/daemon/src/alive_monitor/details/factory/FlatCfgFactory.cpp b/score/launch_manager/daemon/src/alive_monitor/details/factory/FlatCfgFactory.cpp index c40c75f8d..9622c9885 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/factory/FlatCfgFactory.cpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/factory/FlatCfgFactory.cpp @@ -24,10 +24,7 @@ #include "score/mw/launch_manager/alive_monitor/details/ifappl/MonitorIfDaemon.hpp" #include "score/mw/launch_manager/alive_monitor/details/ifexm/ProcessState.hpp" #include "score/mw/launch_manager/alive_monitor/details/logging/PhmLogger.hpp" -#include "score/mw/launch_manager/alive_monitor/details/recovery/Notification.hpp" #include "score/mw/launch_manager/alive_monitor/details/supervision/Alive.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/Global.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/Local.hpp" #include "score/mw/launch_manager/alive_monitor/details/supervision/SupervisionCfg.hpp" #include "score/mw/launch_manager/alive_monitor/details/timers/TimeConversion.hpp" #include "score/mw/launch_manager/alive_monitor/details/timers/Timers_OsClock.hpp" @@ -45,14 +42,16 @@ namespace { /// @brief Prefix for all log messages // coverity[autosar_cpp14_a2_10_4_violation:FALSE] Empty namespace ensures uniqueness for cpp file scope -static constexpr char const* kLogPrefix{"Factory for FlatCfg AR24-11:"}; +static constexpr const char* kLogPrefix{"Factory for FlatCfg AR24-11:"}; -std::unique_ptr read_flatbuffer_file(const std::string& f_filename_r) { +std::unique_ptr read_flatbuffer_file(const std::string& f_filename_r) +{ const std::string configFilePath = std::string("etc/") + f_filename_r.c_str(); std::ifstream infile; infile.open(configFilePath, std::ios::binary | std::ios::in); - if (!infile.is_open()) { + if (!infile.is_open()) + { return nullptr; } infile.seekg(0, std::ios::end); @@ -68,12 +67,12 @@ std::unique_ptr read_flatbuffer_file(const std::string& f_filename_r) { /* RULECHECKER_comment(0, 7, check_incomplete_data_member_construction, "Members processDataBase is not \ required to be initialized using member initializer list.", true_no_defect) */ -FlatCfgFactory::FlatCfgFactory(const factory::MachineConfigFactory::SupervisionBufferConfig& f_bufferConfig_r) : - IPhmFactory(), - bufferConfig_r(f_bufferConfig_r), - flatBuffer_p(nullptr), - // loadBuffer_p(nullptr), - logger_r(logging::PhmLogger::getLogger(logging::PhmLogger::EContext::factory)) +FlatCfgFactory::FlatCfgFactory(const factory::MachineConfigFactory::SupervisionBufferConfig& f_bufferConfig_r) + : IPhmFactory(), + bufferConfig_r(f_bufferConfig_r), + flatBuffer_p(nullptr), + // loadBuffer_p(nullptr), + logger_r(logging::PhmLogger::getLogger(logging::PhmLogger::EContext::factory)) { static_cast(flatBuffer_p); } @@ -81,7 +80,8 @@ FlatCfgFactory::FlatCfgFactory(const factory::MachineConfigFactory::SupervisionB bool FlatCfgFactory::init(const std::string& f_filename_r) { loadBuffer_p = read_flatbuffer_file(f_filename_r); - if(!loadBuffer_p) { + if (!loadBuffer_p) + { logger_r.LogError() << kLogPrefix << "Could not open config file."; return false; } @@ -96,7 +96,6 @@ bool FlatCfgFactory::init(const std::string& f_filename_r) return true; } - bool FlatCfgFactory::createProcessStates(std::vector& f_processStates_r, ifexm::ProcessStateReader& f_processStateReader_r) { @@ -123,7 +122,8 @@ bool FlatCfgFactory::createProcessStates(std::vector& f_pro // coverity[cert_exp34_c_violation] PHM.ecucfgdsl Process.refProcessGroupStates MANDATORY // coverity[dereference] PHM.ecucfgdsl Process.refProcessGroupStates MANDATORY const auto* pgStates_p{process_p->refProcessGroupStates()}; - /* RULECHECKER_comment(2, 3, check_csa_call_null_object_pointer, "PHM.ecucfgdsl Process.refProcessGroupStates MANDATORY", true_no_defect) */ + /* RULECHECKER_comment(2, 3, check_csa_call_null_object_pointer, "PHM.ecucfgdsl + * Process.refProcessGroupStates MANDATORY", true_no_defect) */ // coverity[cert_exp34_c_violation] PHM.ecucfgdsl Process.refProcessGroupStates MANDATORY // coverity[dereference] PHM.ecucfgdsl Process.refProcessGroupStates MANDATORY refProcessGroupStatePaths.reserve(static_cast(pgStates_p->size())); @@ -184,8 +184,8 @@ bool FlatCfgFactory::createProcessStates(std::vector& f_pro catch (const std::exception& f_exception_r) { isSuccess = false; - logger_r.LogError() << kLogPrefix - << "Could not create Process States due to exception:" << std::string_view{f_exception_r.what()}; + logger_r.LogError() << kLogPrefix << "Could not create Process States due to exception:" + << std::string_view{f_exception_r.what()}; } } else @@ -257,13 +257,12 @@ bool FlatCfgFactory::createMonitorIfIpcs(std::vector& f_interfaces_r, - std::vector& f_interfaceIpcs_r, - std::vector& f_processStates_r) + std::vector& f_interfaceIpcs_r, + std::vector& f_processStates_r) { bool isSuccess{true}; try @@ -317,8 +315,8 @@ bool FlatCfgFactory::createMonitorIf(std::vector& f_int f_processStates_r.at(static_cast(refProcessIndex)).attachObserver(f_interfaces_r.back()); - logger_r.LogDebug() << kLogPrefix << "Successfully created MonitorInterface:" - << f_interfaces_r.back().getInterfaceName(); + logger_r.LogDebug() << kLogPrefix + << "Successfully created MonitorInterface:" << f_interfaces_r.back().getInterfaceName(); // coverity[autosar_cpp14_a4_7_1_violation] Value limited by amount of interfaces, which is smaller. index++; } @@ -330,8 +328,7 @@ bool FlatCfgFactory::createMonitorIf(std::vector& f_int { isSuccess = false; f_interfaces_r.clear(); - logger_r.LogError() << kLogPrefix - << "Could not create all necessary Monitor interfaces due to exception:" + logger_r.LogError() << kLogPrefix << "Could not create all necessary Monitor interfaces due to exception:" << std::string_view{f_exception_r.what()}; } @@ -356,8 +353,9 @@ bool FlatCfgFactory::createSupervisionCheckpoints(std::vectorshortName()->c_str()}; const uint32_t checkpointId{hmSupervisionCheckpoint_p->checkpointId()}; const uint32_t refInterfaceIndex{hmSupervisionCheckpoint_p->refInterfaceIndex()}; - // coverity[cert_exp34_c_violation] PHM.ecucfgdsl ensures valid link btw. PhmSupervisionCheckpoint and PhmMonitorInterface - // coverity[dereference] PHM.ecucfgdsl ensures valid link btw. PhmSupervisionCheckpoint and PhmMonitorInterface + // coverity[cert_exp34_c_violation] PHM.ecucfgdsl ensures valid link btw. PhmSupervisionCheckpoint and + // PhmMonitorInterface coverity[dereference] PHM.ecucfgdsl ensures valid link btw. + // PhmSupervisionCheckpoint and PhmMonitorInterface const auto refProcessIndex{ flatBuffer_p->hmMonitorInterface()->Get(refInterfaceIndex)->refProcessIndex()}; const ifexm::ProcessState* process_p{&f_processStates_r.at(static_cast(refProcessIndex))}; @@ -399,7 +397,8 @@ bool FlatCfgFactory::createSupervisionCheckpoints(std::vector& f_alive_r, std::vector& f_checkpoints_r, - std::vector& f_processStates_r) + std::vector& f_processStates_r, + std::shared_ptr f_recoveryClient_r) { bool isSuccess{true}; @@ -450,7 +449,8 @@ bool FlatCfgFactory::createAliveSupervisions(std::vector& f_ // Construct Alive Supervision supervision::AliveSupervisionCfg aliveSupCfg{ - f_checkpoints_r.at(static_cast(refCheckPointIndexTemp)), refProcessGroupStateIds, + f_checkpoints_r.at(static_cast(refCheckPointIndexTemp)), + refProcessGroupStateIds, refProcesses}; aliveSupCfg.cfgName_p = nameCfgAlive_p; @@ -461,6 +461,12 @@ bool FlatCfgFactory::createAliveSupervisions(std::vector& f_ aliveSupCfg.isMaxCheckDisabled = isMaxCheckDisabledCfg; aliveSupCfg.failedCyclesTolerance = failedCyclesToleranceCfg; aliveSupCfg.checkpointBufferSize = bufferConfig_r.bufferSizeAliveSupervision; + aliveSupCfg.recoveryClient = f_recoveryClient_r; + + // coverity[cert_exp34_c_violation] PHM.ecucfgdsl Process.identifier MANDATORY + // coverity[dereference] PHM.ecucfgdsl Process.identifier MANDATORY + aliveSupCfg.processIdentifier = + score::lcm::IdentifierHash{flatBuffer_p->process()->Get(processIndex)->identifier()->str()}; f_alive_r.emplace_back(aliveSupCfg); @@ -495,252 +501,6 @@ bool FlatCfgFactory::createAliveSupervisions(std::vector& f_ return isSuccess; } -/* RULECHECKER_comment(0, 5, check_max_parameters, "The 4 parameters is better handled individually instead of further\ - combining under a data structure", true_no_defect) */ -bool FlatCfgFactory::createLocalSupervisions(std::vector& f_local_r, - std::vector& f_alive_r) -{ - bool isSuccess{true}; - - // If PhmLocalSupervision is not configured in configuration files, nullptr is returned by PhmLocalSupervision(). - // AR21-11: For each Monitor instance, a local supervision is created. If PhmLocalSupervision() returns - // nullptr, Monitor interface and local supervision are not configured. This is considered as an error. - if (flatBuffer_p->hmLocalSupervision() != nullptr) - { - auto numberOfLocalSup{flatBuffer_p->hmLocalSupervision()->size()}; - try - { - f_local_r.reserve(static_cast(numberOfLocalSup)); - - for (auto hmLocalSupervision_p : *flatBuffer_p->hmLocalSupervision()) - { - // Collect Local Supervision Config - supervision::LocalSupervisionCfg localSupervisionCfg{}; - localSupervisionCfg.cfgName_p = hmLocalSupervision_p->ruleContextKey()->c_str(); - localSupervisionCfg.checkpointEventBufferSize = bufferConfig_r.bufferSizeLocalSupervision; - - // Construct Local Supervision - f_local_r.emplace_back(localSupervisionCfg); - - // Subscribe created Local Supervision to Alive Supervisions - if (hmLocalSupervision_p->hmRefAliveSupervision() != nullptr) - { - for (auto* phmRefAlive_p : *hmLocalSupervision_p->hmRefAliveSupervision()) - { - uint32_t refAliveIndex{phmRefAlive_p->refAliveSupervisionIdx()}; - supervision::Alive& alive_r{f_alive_r.at(static_cast(refAliveIndex))}; - alive_r.attachObserver(f_local_r.back()); - f_local_r.back().registerCheckpointSupervision(alive_r); - } - } - logger_r.LogDebug() << kLogPrefix - << "Successfully created local supervision:" << f_local_r.back().getConfigName(); - } - } - catch (const std::exception& f_exception_r) - { - isSuccess = false; - logger_r.LogError() << kLogPrefix << "Could not create local supervision worker objects, due to exception:" - << std::string_view{f_exception_r.what()}; - } - } - else - { - isSuccess = false; - } - - if (isSuccess) - { - logger_r.LogDebug() << kLogPrefix - << "Number of constructed local supervisions:" << static_cast(f_local_r.size()); - } - else - { - f_local_r.clear(); - logger_r.LogError() << kLogPrefix << "Could not create all necessary local supervision worker objects"; - } - - return isSuccess; -} - -bool FlatCfgFactory::createGlobalSupervisions(std::vector& f_global_r, - std::vector& f_local_r, - std::vector& f_processStates_r) -{ - bool isGlobalSupCfgSuccess{true}; - - // If PhmGlobalSupervision is not configured in configuration files, nullptr is returned by PhmGlobalSupervision(). - // It is valid to have empty (zero) PhmGlobalSupervision in the configuration. - if (flatBuffer_p->hmGlobalSupervision() != nullptr) - { - auto numberOfGlobalSup{flatBuffer_p->hmGlobalSupervision()->size()}; - try - { - f_global_r.reserve(static_cast(numberOfGlobalSup)); - - for (auto hmGlobalSupervision_p : *flatBuffer_p->hmGlobalSupervision()) - { - // Collect Global Supervision configuration - const char* name_p{hmGlobalSupervision_p->ruleContextKey()->c_str()}; - - // Collect referenced ProcessGroupStates and expiredTolerances for Global Supervision - std::vector refProcessGroupStates{}; - - std::vector expiredSupervisionTolerances{}; - // coverity[cert_exp34_c_violation] PHM.ecucfgdsl PhmGlobalSupervision.refProcessGroupStates MANDATORY - // coverity[dereference] PHM.ecucfgdsl PhmGlobalSupervision.refProcessGroupStates MANDATORY - refProcessGroupStates.reserve( - static_cast(hmGlobalSupervision_p->refProcessGroupStates()->size())); - - // coverity[cert_exp34_c_violation] PHM.ecucfgdsl PhmGlobalSupervision.refProcessGroupStates MANDATORY - // coverity[dereference] PHM.ecucfgdsl PhmGlobalSupervision.refProcessGroupStates MANDATORY - expiredSupervisionTolerances.reserve( - static_cast(hmGlobalSupervision_p->refProcessGroupStates()->size())); - - for (auto refProcessGroupState_p : *hmGlobalSupervision_p->refProcessGroupStates()) - { - // coverity[cert_exp34_c_violation] PHM.ecucfgdsl PhmRefProcessGroupStatesGlobal.identifier - // coverity[dereference] PHM.ecucfgdsl PhmRefProcessGroupStatesGlobal.identifier MANDATORY - refProcessGroupStates.push_back(refProcessGroupState_p->identifier()->c_str()); - double tolerance{refProcessGroupState_p->expiredSupervisionTolerance()}; - - timers::NanoSecondType toleranceNs; - if (std::isfinite(tolerance)) - { - toleranceNs = timers::TimeConversion::convertMilliSecToNanoSec(tolerance); - } - else - { - toleranceNs = UINT64_MAX; - } - expiredSupervisionTolerances.push_back(toleranceNs); - } - - const auto result{getProcessGroupStateIds(refProcessGroupStates)}; - std::vector refProcessGroupStateIds{std::move(*result)}; - - // Construct Global Supervision - supervision::GlobalSupervisionCfg globalSupervisionCfg{refProcessGroupStateIds, - expiredSupervisionTolerances}; - globalSupervisionCfg.cfgName_p = name_p; - globalSupervisionCfg.localEventBufferSize = bufferConfig_r.bufferSizeGlobalSupervision; - - f_global_r.emplace_back(globalSupervisionCfg); - - // Subscribe created Global Supervision to Local Supervisions - for (auto localSupervision_p : *hmGlobalSupervision_p->localSupervision()) - { - uint32_t refLocalSupIndex{localSupervision_p->refLocalSupervisionIndex()}; - f_local_r.at(static_cast(refLocalSupIndex)).attachObserver(f_global_r.back()); - f_global_r.back().registerLocalSupervision(f_local_r.at(static_cast(refLocalSupIndex))); - } - - // Subscribe created Global Supervision to ProcessState classes - for (auto refProcess_p : *hmGlobalSupervision_p->refProcesses()) - { - f_processStates_r.at(static_cast(refProcess_p->index())).attachObserver(f_global_r.back()); - } - - logger_r.LogDebug() << kLogPrefix - << "Successfully created global supervision:" << f_global_r.back().getConfigName(); - } - } - catch (const std::exception& f_exception_r) - { - isGlobalSupCfgSuccess = false; - logger_r.LogError() << kLogPrefix << "Could not create all necessary global supervision due to exception:" - << std::string_view{f_exception_r.what()}; - } - } - else - { - isGlobalSupCfgSuccess = false; - } - - if (isGlobalSupCfgSuccess) - { - logger_r.LogDebug() << kLogPrefix - << "Number of constructed global supervisions:" << static_cast(f_global_r.size()); - } - else - { - f_global_r.clear(); - logger_r.LogError() << kLogPrefix << "Could not create all necessary global supervision worker objects"; - } - - return isGlobalSupCfgSuccess; -} - -bool FlatCfgFactory::createRecoveryNotifications(std::shared_ptr f_recoveryClient_r, - std::vector& f_notification_r, - std::vector& f_global_r) -{ - bool isRecoverySuccess{true}; - - if (flatBuffer_p->hmRecoveryNotification() != nullptr) - { - const auto numberOfNotification{flatBuffer_p->hmRecoveryNotification()->size()}; - try - { - f_notification_r.reserve(static_cast(numberOfNotification)); - for (auto recoveryNotification_p : *flatBuffer_p->hmRecoveryNotification()) - { - createNotification(f_recoveryClient_r, f_notification_r, *recoveryNotification_p); - uint32_t refGlobalSupIndex{recoveryNotification_p->refGlobalSupervisionIndex()}; - - f_global_r.at(static_cast(refGlobalSupIndex)) - .registerRecoveryNotification(f_notification_r.back()); - logger_r.LogVerbose() << kLogPrefix << "Successfully registered recovery notification (" - << f_notification_r.back().getConfigName() << ") at Global Supervision (" - << f_global_r.at(static_cast(refGlobalSupIndex)).getConfigName() << ")"; - } - } - catch (const std::exception& f_exception_r) - { - isRecoverySuccess = false; - f_notification_r.clear(); - logger_r.LogError() << kLogPrefix - << "Could not create all necessary recovery notifications " - "due to exception:" - << std::string_view{f_exception_r.what()}; - } - } - - if (isRecoverySuccess) - { - logger_r.LogDebug() << kLogPrefix << "Number of constructed recovery notifications:" - << static_cast(f_notification_r.size()); - } - - return isRecoverySuccess; -} - -void FlatCfgFactory::createNotification(std::shared_ptr f_recoveryClient_r, std::vector& f_notification_r, - const HMFlatBuffer::RecoveryNotification& f_recoveryNotificationData_r) const - noexcept(false) -{ - recovery::NotificationConfig notifConfig{}; - std::string pathInstanceSpecifier{}; - - // Special Case: This is a dummy recovery notification that will fire the watchdog when a global supervision - // of Exm or SM process fails - if (f_recoveryNotificationData_r.shouldFireWatchdog()) - { - f_notification_r.emplace_back(f_recoveryClient_r); - logger_r.LogDebug() << kLogPrefix << "Successfully created dummy recovery notification to fire the watchdog"; - return; - } - - notifConfig.configName = f_recoveryNotificationData_r.shortName()->c_str(); - notifConfig.processGroupMetaModelIdentifier = - f_recoveryNotificationData_r.processGroupMetaModelIdentifier()->c_str(); - - f_notification_r.emplace_back(notifConfig, f_recoveryClient_r); - - logger_r.LogDebug() << kLogPrefix - << "Successfully created recovery notification:" << f_notification_r.back().getConfigName(); -} - std::optional> FlatCfgFactory::getProcessGroupStateIds( std::vector& f_pgStatePaths_r) noexcept(false) { @@ -753,11 +513,9 @@ std::optional> FlatCfgFactory::getProcessGro return stateIds; } -std::optional FlatCfgFactory::getProcessId(const std::string& f_processPath_r) noexcept( - true) +std::optional FlatCfgFactory::getProcessId(const std::string& f_processPath_r) noexcept(true) { return score::lcm::IdentifierHash{f_processPath_r}.data(); - } } // namespace factory diff --git a/score/launch_manager/daemon/src/alive_monitor/details/factory/FlatCfgFactory.hpp b/score/launch_manager/daemon/src/alive_monitor/details/factory/FlatCfgFactory.hpp index c67c01e8b..59144f542 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/factory/FlatCfgFactory.hpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/factory/FlatCfgFactory.hpp @@ -98,33 +98,10 @@ class FlatCfgFactory : public IPhmFactory /// Refer to the description of the base class (IPhmFactory) bool createAliveSupervisions(std::vector& f_alive_r, std::vector& f_checkpoints_r, - std::vector& f_processStates_r) override; - - /// Refer to the description of the base class (IPhmFactory) - bool createLocalSupervisions(std::vector& f_local_r, - std::vector& f_alive_r) override; - - /// Refer to the description of the base class (IPhmFactory) - bool createGlobalSupervisions(std::vector& f_global_r, - std::vector& f_local_r, - std::vector& f_processStates_r) override; - - /// Refer to the description of the base class (IPhmFactory) - bool createRecoveryNotifications(std::shared_ptr f_recoveryClient_r, - std::vector& f_notification_r, - std::vector& f_global_r) override; + std::vector& f_processStates_r, + std::shared_ptr f_recoveryClient_r) override; private: - /// @brief Read the configuration of recovery notification and create notification worker - /// @details Read the configuration of recovery notification and create notification worker and place it in - /// notification vector - /// @param [in] f_recoveryClient_r Recovery interface to the launch manager - /// @param [inout] f_notification_r Vector for notification worker - /// @param [in] f_recoveryNotificationData_r FlatBuffer data for recovery notification - void createNotification(std::shared_ptr f_recoveryClient_r, - std::vector& f_notification_r, - const HMFlatBuffer::RecoveryNotification& f_recoveryNotificationData_r) const - noexcept(false); /// @brief Get the process group state ids based on the process group state asr paths /// @param[in] f_pgStatePaths_r The pg state paths from the configuration diff --git a/score/launch_manager/daemon/src/alive_monitor/details/factory/IPhmFactory.hpp b/score/launch_manager/daemon/src/alive_monitor/details/factory/IPhmFactory.hpp index 8012fb78f..d5e494732 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/factory/IPhmFactory.hpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/factory/IPhmFactory.hpp @@ -47,15 +47,8 @@ class Checkpoint; namespace supervision { class Alive; -class Local; -class Global; } // namespace supervision -namespace recovery -{ -class Notification; -} - namespace factory { @@ -116,39 +109,13 @@ class IPhmFactory /// @param [out] f_alive_r Vector of created alive supervision worker /// @param [in,out] f_checkpoints_r Vector of Supervision Checkpoints /// @param [in,out] f_processStates_r Vector of Process States + /// @param [in] f_recoveryClient_r Recovery interface invoked when a supervision expires /// @return Object creation successful (true), otherwise failed (false) virtual bool createAliveSupervisions(std::vector& f_alive_r, std::vector& f_checkpoints_r, - std::vector& f_processStates_r) = 0; - - /// @brief Create local supervision worker objects - /// @details Create all required local supervision worker objects from configuration - /// @param [out] f_local_r Vector of created local supervision worker - /// @param [in,out] f_alive_r Vector of alive supervision worker - /// @param [in,out] f_deadline_r Vector of deadline supervision worker - /// @param [in,out] f_logical_r Vector of logical supervision worker - /// @return Object creation successful (true), otherwise failed (false) - virtual bool createLocalSupervisions(std::vector& f_local_r, - std::vector& f_alive_r) = 0; + std::vector& f_processStates_r, + std::shared_ptr f_recoveryClient_r) = 0; - /// @brief Create global supervision worker objects - /// @details Create all required global supervision worker objects from configuration - /// @param [out] f_global_r Vector of created global supervision worker - /// @param [in,out] f_local_r Vector of local supervision worker - /// @param [in,out] f_processStates_r Vector of Process States - /// @return Object creation successful (true), otherwise failed (false) - virtual bool createGlobalSupervisions(std::vector& f_global_r, - std::vector& f_local_r, - std::vector& f_processStates_r) = 0; - - /// @brief Create Recovery Notification - /// @param [in] f_recoveryClient_r Recovery interface to the launch manager - /// @param [out] f_notification_r Vector of Recovery Notifications - /// @param [in,out] f_global_r Vector of Global Supervisions required for attaching the Recovery Notifications. - /// @return Object creation successful (true), otherwise failed (false) - virtual bool createRecoveryNotifications(std::shared_ptr f_recoveryClient_r, - std::vector& f_notification_r, - std::vector& f_global_r) = 0; }; } // namespace factory diff --git a/score/launch_manager/daemon/src/alive_monitor/details/factory/MachineConfigFactory.cpp b/score/launch_manager/daemon/src/alive_monitor/details/factory/MachineConfigFactory.cpp index fd958f2cd..a00f3eb0e 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/factory/MachineConfigFactory.cpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/factory/MachineConfigFactory.cpp @@ -142,8 +142,6 @@ void MachineConfigFactory::loadHmSettings(const HMCOREFlatBuffer::HMCOREEcuCfg& { const auto* config{configContainer->Get(0U)}; updateNonDefaultValue(supBufferCfg.bufferSizeAliveSupervision, config->bufferSizeAliveSupervision()); - updateNonDefaultValue(supBufferCfg.bufferSizeLocalSupervision, config->bufferSizeLocalSupervision()); - updateNonDefaultValue(supBufferCfg.bufferSizeGlobalSupervision, config->bufferSizeGlobalSupervision()); updateNonDefaultValue(supBufferCfg.bufferSizeMonitor, config->bufferSizeMonitor()); if (config->periodicity() != 0U) { @@ -184,8 +182,6 @@ void MachineConfigFactory::logConfiguration() noexcept(true) { /* RULECHECKER_comment(0, 18, check_conditional_as_sub_expression, "Ternary operation is very simple", true_no_defect) */ logger_r.LogDebug() << kLogPrefix << "Alive Supervision buffer size:" << supBufferCfg.bufferSizeAliveSupervision; - logger_r.LogDebug() << kLogPrefix << "Local Supervision buffer size:" << supBufferCfg.bufferSizeLocalSupervision; - logger_r.LogDebug() << kLogPrefix << "Global Supervision buffer size:" << supBufferCfg.bufferSizeGlobalSupervision; logger_r.LogDebug() << kLogPrefix << "Monitor buffer size:" << supBufferCfg.bufferSizeMonitor; logger_r.LogDebug() << kLogPrefix << "Periodicity:" << getCycleTimeInNs() << "ns"; logger_r.LogDebug() << kLogPrefix << "Configured watchdogs:" << watchdogConfigs.size(); diff --git a/score/launch_manager/daemon/src/alive_monitor/details/factory/MachineConfigFactory.hpp b/score/launch_manager/daemon/src/alive_monitor/details/factory/MachineConfigFactory.hpp index 3cba842f6..ab4d7b071 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/factory/MachineConfigFactory.hpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/factory/MachineConfigFactory.hpp @@ -54,10 +54,6 @@ class MachineConfigFactory : public watchdog::IDeviceConfigFactory { /// @brief Configured buffer size for alive supervisions std::uint16_t bufferSizeAliveSupervision{StaticConfig::k_DefaultAliveSupCheckpointBufferElements}; - /// @brief Configured buffer size for local supervisions - std::uint16_t bufferSizeLocalSupervision{StaticConfig::k_DefaultLocalSupStatusUpdateBufferElements}; - /// @brief Configured buffer size for global supervisions - std::uint16_t bufferSizeGlobalSupervision{StaticConfig::k_DefaultGlobalSupStatusUpdateBufferElements}; /// @brief Configured buffer size for Monitor entities std::uint16_t bufferSizeMonitor{StaticConfig::k_DefaultMonitorBufferElements}; }; diff --git a/score/launch_manager/daemon/src/alive_monitor/details/factory/StaticConfig.hpp b/score/launch_manager/daemon/src/alive_monitor/details/factory/StaticConfig.hpp index f90e3df16..74e4acfb4 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/factory/StaticConfig.hpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/factory/StaticConfig.hpp @@ -37,10 +37,6 @@ class StaticConfig public: /// Default buffer size of Alive Supervision checkpoint buffer static constexpr uint16_t k_DefaultAliveSupCheckpointBufferElements{100U}; - /// Default buffer size of Local Supervision buffer - static constexpr uint16_t k_DefaultLocalSupStatusUpdateBufferElements{100U}; - /// Default buffer size of Global Supervision buffer - static constexpr uint16_t k_DefaultGlobalSupStatusUpdateBufferElements{100U}; /// Default buffer size of a Monitor (shared memory) static constexpr uint16_t k_DefaultMonitorBufferElements{ifappl::k_maxCheckpointBufferElements}; diff --git a/score/launch_manager/daemon/src/alive_monitor/details/recovery/BUILD b/score/launch_manager/daemon/src/alive_monitor/details/recovery/BUILD deleted file mode 100644 index 799965b94..000000000 --- a/score/launch_manager/daemon/src/alive_monitor/details/recovery/BUILD +++ /dev/null @@ -1,36 +0,0 @@ -# ******************************************************************************* -# Copyright (c) 2026 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License Version 2.0 which is available at -# https://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -# ******************************************************************************* -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") - -cc_library( - name = "notification", - srcs = ["Notification.cpp"], - hdrs = ["Notification.hpp"], - include_prefix = "score/mw/launch_manager/alive_monitor/details/recovery", - strip_include_prefix = "/score/launch_manager/daemon/src/alive_monitor/details/recovery", - visibility = ["//score/launch_manager/daemon/src/alive_monitor:__subpackages__"], - deps = [ - "//score/launch_manager/daemon/src/alive_monitor/details/logging:phm_logging", - "//score/launch_manager/daemon/src/recovery_client", - ], -) - -cc_test( - name = "Notification_UT", - srcs = ["Notification_UT.cpp"], - deps = [ - ":notification", - "@googletest//:gtest_main", - "@score_baselibs//score/mw/log:backend_stub_testutil", - ], -) diff --git a/score/launch_manager/daemon/src/alive_monitor/details/recovery/Notification.cpp b/score/launch_manager/daemon/src/alive_monitor/details/recovery/Notification.cpp deleted file mode 100644 index e7c4dd6b7..000000000 --- a/score/launch_manager/daemon/src/alive_monitor/details/recovery/Notification.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2025 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#include "score/mw/launch_manager/alive_monitor/details/recovery/Notification.hpp" - -namespace score -{ -namespace lcm -{ -namespace saf -{ -namespace recovery -{ - -Notification::Notification(std::shared_ptr f_recoveryClient_r) : - currentState(State::kIdle), - messageHeader("Notification ( / )"), - isNotificationConfigAvailable(false), - recoveryClient(f_recoveryClient_r), - logger_r(logging::PhmLogger::getLogger(logging::PhmLogger::EContext::recovery)) -{ -} - -Notification::Notification(const NotificationConfig& f_notificationConfig_r, std::shared_ptr f_recoveryClient_r) : - currentState(State::kIdle), - k_notificationConfig(f_notificationConfig_r), - messageHeader("Notification (" + k_notificationConfig.configName + ")"), - isNotificationConfigAvailable(true), - recoveryClient(f_recoveryClient_r), - logger_r(logging::PhmLogger::getLogger(logging::PhmLogger::EContext::recovery)) -{ -} - -// explicit declaration of destructor needed to make forward declaration work -Notification::~Notification() = default; - -/* RULECHECKER_comment(0, 7, check_min_instructions, "Default move constructor is not provided\ -a function body", true_no_defect) */ -/* RULECHECKER_comment(0, 5, check_incomplete_data_member_construction, "Default constructor is not provided\ -the member initializer", false) */ -/* RULECHECKER_comment(0, 3, check_copy_in_move_constructor, "The default move constructor invokes parameterized\ -constructor internally. This invokes std::string copy construction", true_no_defect) */ -Notification::Notification(Notification&&) = default; - -bool Notification::initProxy() noexcept(false) -{ - if(!isNotificationConfigAvailable) { - return true; - } - - const auto processGroupStateStartPos = k_notificationConfig.processGroupMetaModelIdentifier.find_last_of('/'); - if(processGroupStateStartPos == std::string::npos || processGroupStateStartPos == 0U) - { - logger_r.LogError() << messageHeader << "Invalid ProcessGroupState identifier:" - << k_notificationConfig.processGroupMetaModelIdentifier; - - return false; - } - - const std::string recoveryProcessGroupId{k_notificationConfig.processGroupMetaModelIdentifier.substr(0, processGroupStateStartPos)}; - recoveryProcessGroup = score::lcm::IdentifierHash(recoveryProcessGroupId); - return true; -} - -void Notification::send(const xaap::lcm::saf::recovery::supervision::SupervisionErrorInfo& f_executionErrorInfo_r) -{ - static_cast(f_executionErrorInfo_r); // Unused, to be removed in the future together with the Notification class - - if (isNotificationConfigAvailable) - { - if (currentState == State::kIdle) - { - currentState = State::kSending; - } - } else { - currentState = State::kTimeout; - } -} - -void Notification::cyclicTrigger(void) -{ - if (currentState == State::kSending) - { - invokeRecoveryHandler(); - } -} - -bool Notification::isFinalTimeoutStateReached(void) const noexcept -{ - return (currentState == State::kTimeout); -} - -void Notification::invokeRecoveryHandler(void) -{ - // TODO: As a next step, we shall pass the Id of the Process which failed supervision - // instead of the process group id. However, this required other refactoring first. - const bool enqueued = recoveryClient->sendRecoveryRequest(recoveryProcessGroup); - - if (enqueued) - { - logger_r.LogInfo() << messageHeader << "Recovery request enqueued successfully"; - currentState = State::kIdle; - } - else - { - logger_r.LogError() << messageHeader << "Failed to enqueue recovery request (ring buffer full)"; - currentState = State::kTimeout; - } -} - -/* RULECHECKER_comment(1:0,2:0, check_min_instructions, "False positive", false) */ -/* RULECHECKER_comment(1:0,1:0, check_member_function_missing_static, "Member function uses non-static members and\ -cannot be made static", false) */ -const std::string& Notification::getConfigName(void) const noexcept -{ - return k_notificationConfig.configName; -} - -} // namespace recovery -} // namespace saf -} // namespace lcm -} // namespace score diff --git a/score/launch_manager/daemon/src/alive_monitor/details/recovery/Notification.hpp b/score/launch_manager/daemon/src/alive_monitor/details/recovery/Notification.hpp deleted file mode 100644 index ceb8b8744..000000000 --- a/score/launch_manager/daemon/src/alive_monitor/details/recovery/Notification.hpp +++ /dev/null @@ -1,200 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2025 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - - -#ifndef NOTIFICATION_HPP_INCLUDED -#define NOTIFICATION_HPP_INCLUDED - -#ifndef PHM_PRIVATE -# define PHM_PRIVATE private -#endif - -#include -#include -#include - -#include -#include -#include "score/mw/launch_manager/alive_monitor/details/logging/PhmLogger.hpp" -#include "score/mw/launch_manager/recovery_client/irecovery_client.h" - -namespace xaap -{ -namespace lcm -{ -namespace saf -{ -namespace recovery -{ -namespace supervision -{ -using SupervisionErrorInfo = struct SupervisionErrorInfo -{ - uint32_t failedProcessExecutionError; - uint32_t failedSupervisionType; - std::array failedprocessGroupMetaModelIdentifier; -}; - -} // namespace supervision -} // namespace recovery -} // namespace saf -} // namespace lcm -} // namespace xaap - -namespace score -{ -namespace lcm -{ -enum class TypeOfSupervision : std::uint32_t -{ - /// @brief Supervision is of type AliveSupervision - AliveSupervision = 0, - /// @brief Supervision is of type DeadlineSupervision - DeadlineSupervision = 1, - /// @brief Supervision is of type LogicalSupervision - LogicalSupervision = 2 -}; - -} // namespace lcm -} // namespace score - -namespace score -{ -namespace lcm -{ -namespace saf -{ -namespace recovery -{ - -/* RULECHECKER_comment(0, 14, check_non_private_non_pod_field, "NotificationConfig data is\ - set to public scope", true_no_defect) */ -/// @brief Structure containing configuration data for Recovery notification -class NotificationConfig final -{ -public: - /// @brief Name of the RecoveryNotification configuration container - std::string configName{""}; - /// @brief Process Group Meta Model identifier of the process that is responsible for the monitoring event - std::string processGroupMetaModelIdentifier{""}; -}; - -/// @brief Notification class which initiates the recovery action. -/// The recovery action could be a notification to State Management, or directly setting the final timeout state -/// which would eventually trigger a reaction via the watchdog -class Notification -{ -public: - /// @brief Default constructor - /// @param [in] f_recoveryClient_r Shared pointer to the recovery interface of launch manager - /// @warning If the default constructor is used for the construction of Notification class, the notification - /// instance will not send the recovery notification to State Management, instead it will directly set the - /// final timeout state so that the recovery can be handled via watchdog - Notification(std::shared_ptr f_recoveryClient_r); - - /// @brief Parametric constructor - /// @param [in] f_notificationConfig_r Shared pointer to the configuration structure of Notification class - /// @param [in] f_recoveryClient_r Reference to the recovery interface of launch manager - /// @note If this parametric constructor is used for the construction of Notification class, the notification - /// instance will send the recovery notification to State Management - explicit Notification(const NotificationConfig& f_notificationConfig_r, std::shared_ptr f_recoveryClient_r); - - /// @brief Copy constructor for this class is not supported - Notification(const Notification&) = delete; - - /// @brief Move assignment operator for this class is not supported - Notification& operator=(Notification&&) & = delete; - - /// @brief Move constructor - Notification(Notification&&); - - /// @brief Copy assignment operator for this class is not supported - Notification& operator=(const Notification&) & = delete; - - /// @brief Default destructor - virtual ~Notification(); - - /// @brief Start initialization of proxy instance - /// @details This invokes StartFindService which will continue to asynchronously look for the proxy instance. - /// @returns True if StartFindService succeeds, False in case of error - bool initProxy() noexcept(false); - - /// @brief Send method to trigger sending the notification - /// This method sends a notification to State Management if this class was constructed with the configuration - /// data for RecoveryNotification. Otherwise, this method sets the timeout state such that a reaction can then - /// be triggered via the watchdog - /// @param [in] f_executionErrorInfo_r Reference to the process error information - /// (supervision) which should be sent to State - /// Management - /// @note The process execution error is used only if this class was constructed with the configuration - /// data for RecoveryNotification, otherwise it is ignored. - void send(const xaap::lcm::saf::recovery::supervision::SupervisionErrorInfo& f_executionErrorInfo_r); - - /// @brief Send the notifications to State Management (if required), in every cycle of PHM daemon - /// @note This is done by invoking the Recovery handler of State Management and verifying the feedback - /// from the Recovery handler methods - /// @warning The current implementation doesn't support parallel calls to the RecoveryHandler - /// remote procedure (i.e., if the previous call to the RecoveryHandler is pending, any subsequent calls to - /// the same remote method will also be in pending state (will be queued)). - void cyclicTrigger(void); - - /// @brief Method to check if the final timeout state of the recovery notification is reached - /// @return Boolean flag to indicate if the final timeout has occurred - /// (true: Final timeout occurred, false: otherwise) - bool isFinalTimeoutStateReached(void) const noexcept; - - /// @brief Read the configuration name of the RecoveryNotification configuration container - /// @details Read the configuration name of the RecoveryNotification - /// @return A String object Configuration name of the RecoveryNotification as text string which was read - const std::string& getConfigName(void) const noexcept; - - PHM_PRIVATE: - /// @brief Internal states of the Notification - enum class State : std::uint8_t - { - kIdle, //< Not sending - kSending, //< Should invoke the RecoveryHandler next - kTimeout //< Final timeout reached - }; - - /// @brief The current internal state - State currentState; - - /// @brief Method to invoke the call to the recovery handler method of State Management - void invokeRecoveryHandler(void); - - /// @brief Instance of the structure containing the configuration data pertaining to the Recovery notification - const NotificationConfig k_notificationConfig{}; - - /// @brief Message header used for logging - const std::string messageHeader; - - /// @brief Boolean flag to indicate if this class was constructed with the recovery notification configuration - /// data (true: this class is to be used to trigger notifications to State Management, false: this class is to be - /// used to directly set the final timeout state such that the recovery is performed via watchdog) - const bool isNotificationConfigAvailable; - - IdentifierHash recoveryProcessGroup; - - std::shared_ptr recoveryClient; - - /// @brief Logger - logging::PhmLogger& logger_r; -}; - -} // namespace recovery -} // namespace saf -} // namespace lcm -} // namespace score - -#endif diff --git a/score/launch_manager/daemon/src/alive_monitor/details/recovery/Notification_UT.cpp b/score/launch_manager/daemon/src/alive_monitor/details/recovery/Notification_UT.cpp deleted file mode 100644 index 78e591268..000000000 --- a/score/launch_manager/daemon/src/alive_monitor/details/recovery/Notification_UT.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2025 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ -#include -#include - -#include "score/mw/launch_manager/alive_monitor/details/recovery/Notification.hpp" - -namespace score -{ -namespace lcm -{ -namespace saf -{ -namespace recovery -{ - -class MockRecoveryClient : public score::lcm::IRecoveryClient -{ -public: - MOCK_METHOD(bool, sendRecoveryRequest, - (const score::lcm::IdentifierHash&), - (noexcept, override)); - MOCK_METHOD(std::optional, getNextRequest, (), (noexcept, override)); - MOCK_METHOD(bool, hasOverflow, (), (const, noexcept, override)); -}; - -class NotificationWithConfigTest : public ::testing::Test -{ - protected: - void SetUp() override - { - RecordProperty("TestType", "interface-test"); - RecordProperty("DerivationTechnique", "explorative-testing "); - } -}; - -class NotificationWithoutConfigTest : public NotificationWithConfigTest -{ -}; - -NotificationConfig getNotificationConfig(const std::string& process_group="TestProcessGroupMetaModelIdentifier") -{ - NotificationConfig config; - config.configName = "TestNotification"; - config.processGroupMetaModelIdentifier = process_group + "/Recovery"; - return config; -} - -using xaap::lcm::saf::recovery::supervision::SupervisionErrorInfo; - -TEST_F(NotificationWithConfigTest, CanGetNotificationName) -{ - RecordProperty("Description", - "Notification created with a configuration returns the correct name from getName method."); - - NotificationConfig config{}; - config.configName = "MyName"; - auto mock_client = std::make_shared(); - Notification notification(config, mock_client); - - ASSERT_EQ(notification.getConfigName(), "MyName"); -} - -TEST_F(NotificationWithConfigTest, SendsRequestAndNeverTimesOut) -{ - RecordProperty("Description", - "Notification created with a configuration forwards supervision failure to RecoveryClient " - "and does not time out."); - - const NotificationConfig config = getNotificationConfig("TestProcessGroup"); - auto mock_client = std::make_shared(); - EXPECT_CALL(*mock_client, sendRecoveryRequest(IdentifierHash("TestProcessGroup"))) - .WillOnce(testing::Return(true)); - - Notification notification(config, mock_client); - ASSERT_TRUE(notification.initProxy()); - notification.send(SupervisionErrorInfo{}); - notification.cyclicTrigger(); - - EXPECT_FALSE(notification.isFinalTimeoutStateReached()); -} - -TEST_F(NotificationWithConfigTest, TimesOutWhenSendingRequestFails) -{ - RecordProperty("Description", - "Notification fails to forward supervision failure to RecoveryClient " - "times out."); - - const NotificationConfig config = getNotificationConfig("TestProcessGroup"); - auto mock_client = std::make_shared(); - EXPECT_CALL(*mock_client, sendRecoveryRequest(IdentifierHash("TestProcessGroup"))) - .WillOnce(testing::Return(false)); - - Notification notification(config, mock_client); - ASSERT_TRUE(notification.initProxy()); - notification.send(SupervisionErrorInfo{}); - notification.cyclicTrigger(); - - EXPECT_TRUE(notification.isFinalTimeoutStateReached()); -} - -TEST_F(NotificationWithConfigTest, ProxyInitializationFails) -{ - RecordProperty("Description", - "Notification created with a configuration containing an invalid process group state " - "identifier returns false on initProxy method."); - - NotificationConfig config; - config.configName = "TestNotification"; - config.processGroupMetaModelIdentifier = "InvalidIdentifier"; - auto mock_client = std::make_shared(); - - Notification notification(config, mock_client); - ASSERT_FALSE(notification.initProxy()); -} - -TEST_F(NotificationWithoutConfigTest, WatchdogNotificationGoesDirectlyToTimeout) -{ - RecordProperty("Description", - "Notifications created without any configuration will directly timeout and " - "not forward supervision failure to recoveryclient."); - - auto mock_client = std::make_shared(); - EXPECT_CALL(*mock_client, sendRecoveryRequest(testing::_)).Times(0); - - Notification notification(mock_client); - ASSERT_TRUE(notification.initProxy()); - notification.send(SupervisionErrorInfo{}); - - EXPECT_TRUE(notification.isFinalTimeoutStateReached()); -} - -} // namespace recovery -} // namespace saf -} // namespace lcm -} // namespace score diff --git a/score/launch_manager/daemon/src/alive_monitor/details/supervision/Alive.cpp b/score/launch_manager/daemon/src/alive_monitor/details/supervision/Alive.cpp index 985d7c533..f628f1b69 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/supervision/Alive.cpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/supervision/Alive.cpp @@ -29,28 +29,37 @@ namespace saf namespace supervision { -Alive::Alive(const AliveSupervisionCfg& f_aliveCfg_r) : - ICheckpointSupervision(f_aliveCfg_r), - Observable(), - k_aliveReferenceCycle(f_aliveCfg_r.aliveReferenceCycle), - k_minAliveIndications(f_aliveCfg_r.minAliveIndications), - k_maxAliveIndications(f_aliveCfg_r.maxAliveIndications), - k_isMinCheckDisabled(f_aliveCfg_r.isMinCheckDisabled), - k_isMaxCheckDisabled(f_aliveCfg_r.isMaxCheckDisabled), - k_failedSupervisionCyclesTolerance(f_aliveCfg_r.failedCyclesTolerance), - logger_r(logging::PhmLogger::getLogger(logging::PhmLogger::EContext::supervision)), - timeSortingUpdateEventBuffer(common::TimeSortingBuffer(f_aliveCfg_r.checkpointBufferSize)), - aliveProcess(f_aliveCfg_r.refProcesses_r.front()), - processTracker(f_aliveCfg_r.refFuntionGroupStates_r, f_aliveCfg_r.refProcesses_r) +Alive::Alive(const AliveSupervisionCfg& f_aliveCfg_r) + : ISupervision(f_aliveCfg_r.cfgName_p), + k_aliveReferenceCycle(f_aliveCfg_r.aliveReferenceCycle), + k_minAliveIndications(f_aliveCfg_r.minAliveIndications), + k_maxAliveIndications(f_aliveCfg_r.maxAliveIndications), + k_isMinCheckDisabled(f_aliveCfg_r.isMinCheckDisabled), + k_isMaxCheckDisabled(f_aliveCfg_r.isMaxCheckDisabled), + k_failedSupervisionCyclesTolerance(f_aliveCfg_r.failedCyclesTolerance), + logger_r(logging::PhmLogger::getLogger(logging::PhmLogger::EContext::supervision)), + recoveryClient_p(f_aliveCfg_r.recoveryClient), + processIdentifier_(f_aliveCfg_r.processIdentifier), + timeSortingUpdateEventBuffer(common::TimeSortingBuffer(f_aliveCfg_r.checkpointBufferSize)), + aliveProcess(f_aliveCfg_r.refProcesses_r.front()), + processTracker(f_aliveCfg_r.refFuntionGroupStates_r, f_aliveCfg_r.refProcesses_r) { + // coverity[autosar_cpp14_m0_1_3_violation:FALSE] process_p is read for creating map of process and execution error + for (const auto* process_p : f_aliveCfg_r.refProcesses_r) + { + processExecErrs.insert({process_p, ifexm::ProcessCfg::kDefaultProcessExecutionError}); + } + f_aliveCfg_r.checkpoint_r.attachObserver(*this); assert((k_aliveReferenceCycle != 0U) && "k_aliveReferenceCycle=0 causes infinite loop during evaluation."); // Consider process active only after reporting kRunning processTracker.setMarkProcessActiveAt(ifexm::ProcessState::EProcState::running); - assert((aliveStatus == EStatus::deactivated) && + assert((aliveStatus == EStatus::kDeactivated) && ("Alive Supervision must start in deactivated state, see SWS_PHM_00204")); + + assert((recoveryClient_p != nullptr) && "Recovery client must be provided"); } // coverity[exn_spec_violation:FALSE] std::length_error is not thrown from push() which uses fixed-size-vector @@ -133,32 +142,31 @@ void Alive::evaluate(const timers::NanoSecondType f_syncTimestamp) eventTimestamp = referenceCycleEnd; } - ICheckpointSupervision::EUpdateEventType currentUpdateType{ - getAliveEventType(isEvaluationEvent, *sortedUpdateEvent_p)}; + EUpdateEventType currentUpdateType{getAliveEventType(isEvaluationEvent, *sortedUpdateEvent_p)}; switch (aliveStatus) { - case Alive::EStatus::deactivated: + case EStatus::kDeactivated: { checkTransitionsOutOfDeactivated(currentUpdateType, timestampOfUpdateEvent); break; } - case Alive::EStatus::ok: + case EStatus::kOk: { checkTransitionsOutOfOk(currentUpdateType, timestampOfUpdateEvent); break; } - case Alive::EStatus::failed: + case EStatus::kFailed: { checkTransitionsOutOfFailed(currentUpdateType, timestampOfUpdateEvent); break; } - case Alive::EStatus::expired: + case EStatus::kExpired: { - // Alive::EStatus::expired can only be exited with a switch to deactivated. + // EStatus::kExpired can only be exited with a switch to deactivated. // A common switch to deactivation is handled in the end, therefore nothing additionally has to be // done for this state. break; @@ -205,7 +213,7 @@ void Alive::storeSyncEvent(const timers::NanoSecondType f_syncTimestamp) void Alive::handleDataLossReaction(void) noexcept(true) { // In case of data loss event, state transition from deactivated to expired is accepted. - if (Alive::EStatus::expired != aliveStatus) + if (EStatus::kExpired != aliveStatus) { switchToExpired(EReason::kDataLoss); } @@ -223,7 +231,7 @@ bool Alive::detectEvaluationEvent(const timers::NanoSecondType f_timestampOfUpda // If current state is deactivated or expired, referenceCyclEnd is reset to the highest value. This means that // there is no need of evaluation. - if ((aliveStatus == Alive::EStatus::deactivated) || (aliveStatus == Alive::EStatus::expired)) + if ((aliveStatus == EStatus::kDeactivated) || (aliveStatus == EStatus::kExpired)) { return false; } @@ -268,14 +276,14 @@ bool Alive::detectEvaluationEvent(const timers::NanoSecondType f_timestampOfUpda return isEvaluationEvent; } -ICheckpointSupervision::EUpdateEventType Alive::getAliveEventType( - bool f_isEvaluationEvent, const TimeSortedUpdateEvent f_updateEvent) noexcept(true) +Alive::EUpdateEventType Alive::getAliveEventType(bool f_isEvaluationEvent, + const TimeSortedUpdateEvent f_updateEvent) noexcept(true) { - ICheckpointSupervision::EUpdateEventType currentUpdateType{ICheckpointSupervision::EUpdateEventType::kNoChange}; + EUpdateEventType currentUpdateType{EUpdateEventType::kNoChange}; if (f_isEvaluationEvent) { - currentUpdateType = ICheckpointSupervision::EUpdateEventType::kEvaluation; + currentUpdateType = EUpdateEventType::kEvaluation; } else { @@ -285,10 +293,10 @@ ICheckpointSupervision::EUpdateEventType Alive::getAliveEventType( return currentUpdateType; } -void Alive::checkTransitionsOutOfDeactivated(const ICheckpointSupervision::EUpdateEventType f_updateEventType, +void Alive::checkTransitionsOutOfDeactivated(const EUpdateEventType f_updateEventType, const timers::NanoSecondType f_updateEventTimestamp) noexcept(true) { - if (f_updateEventType == ICheckpointSupervision::EUpdateEventType::kActivation) + if (f_updateEventType == EUpdateEventType::kActivation) { if (!setReferenceCycleTimestamps(f_updateEventTimestamp)) { @@ -298,40 +306,39 @@ void Alive::checkTransitionsOutOfDeactivated(const ICheckpointSupervision::EUpda } } -void Alive::checkTransitionsToDeactivated(const ICheckpointSupervision::EUpdateEventType f_updateEventType, +void Alive::checkTransitionsToDeactivated(const EUpdateEventType f_updateEventType, const timers::NanoSecondType f_updateEventTimestamp) noexcept(true) { - if ((f_updateEventType == ICheckpointSupervision::EUpdateEventType::kDeactivation) && - (aliveStatus != Alive::EStatus::deactivated)) + if ((f_updateEventType == EUpdateEventType::kDeactivation) && (aliveStatus != EStatus::kDeactivated)) { eventTimestamp = f_updateEventTimestamp; switchToDeactivated(); } } -bool Alive::checkForRecoveryTransition(const ICheckpointSupervision::EUpdateEventType f_updateEventType, +bool Alive::checkForRecoveryTransition(const EUpdateEventType f_updateEventType, const timers::NanoSecondType f_updateEventTimestamp) noexcept(true) { - if (f_updateEventType == ICheckpointSupervision::EUpdateEventType::kRecoveredFromCrash) + if (f_updateEventType == EUpdateEventType::kRecoveredFromCrash) { logger_r.LogDebug() << "Alive Supervision (" << getConfigName() << ") about to recover from crash"; switchToDeactivated(); - checkTransitionsOutOfDeactivated(ICheckpointSupervision::EUpdateEventType::kActivation, f_updateEventTimestamp); + checkTransitionsOutOfDeactivated(EUpdateEventType::kActivation, f_updateEventTimestamp); return true; } return false; } -void Alive::checkTransitionsOutOfOk(const ICheckpointSupervision::EUpdateEventType f_updateEventType, +void Alive::checkTransitionsOutOfOk(const EUpdateEventType f_updateEventType, const timers::NanoSecondType f_updateEventTimestamp) noexcept(true) { // Accept only alive checkpoint or evaluation event. // Deactivation event is handled at the end of evaluate function. - if (f_updateEventType == ICheckpointSupervision::EUpdateEventType::kEvaluation) + if (f_updateEventType == EUpdateEventType::kEvaluation) { evaluateRefCycleOutOfOk(); } - else if (f_updateEventType == ICheckpointSupervision::EUpdateEventType::kCheckpoint) + else if (f_updateEventType == EUpdateEventType::kCheckpoint) { incIndicationCount(f_updateEventTimestamp); } @@ -388,16 +395,16 @@ void Alive::evaluateRefCycleOutOfOk(void) noexcept(true) } } -void Alive::checkTransitionsOutOfFailed(const ICheckpointSupervision::EUpdateEventType f_updateEventType, +void Alive::checkTransitionsOutOfFailed(const EUpdateEventType f_updateEventType, const timers::NanoSecondType f_updateEventTimestamp) noexcept(true) { // Accept only alive checkpoint or evaluation event. // Deactivation event is handled at the end of evaluate function. - if (f_updateEventType == ICheckpointSupervision::EUpdateEventType::kEvaluation) + if (f_updateEventType == EUpdateEventType::kEvaluation) { evaluateRefCycleOutOfFailed(); } - else if (f_updateEventType == ICheckpointSupervision::EUpdateEventType::kCheckpoint) + else if (f_updateEventType == EUpdateEventType::kCheckpoint) { incIndicationCount(f_updateEventTimestamp); } @@ -445,7 +452,7 @@ void Alive::evaluateRefCycleOutOfFailed(void) noexcept(true) void Alive::switchToDeactivated(void) noexcept(true) { - aliveStatus = Alive::EStatus::deactivated; + aliveStatus = EStatus::kDeactivated; failedSupervisionCycles = 0U; indicationCount = 0U; referenceCycleStart = 0U; @@ -458,7 +465,7 @@ void Alive::switchToDeactivated(void) noexcept(true) void Alive::switchToOk(void) noexcept(true) { - aliveStatus = Alive::EStatus::ok; + aliveStatus = EStatus::kOk; failedSupervisionCycles = 0U; logger_r.LogInfo() << "Alive Supervision (" << getConfigName() << ") switched to OK."; pushResultToObservers(); @@ -466,7 +473,7 @@ void Alive::switchToOk(void) noexcept(true) void Alive::switchToFailed(void) noexcept(true) { - aliveStatus = Alive::EStatus::failed; + aliveStatus = EStatus::kFailed; // Method caller is responsible for preventing overflow // coverity[autosar_cpp14_a4_7_1_violation] value can only reach k_failedSupervisionCyclesTolerance failedSupervisionCycles++; @@ -478,7 +485,7 @@ void Alive::switchToFailed(void) noexcept(true) void Alive::switchToExpired(Alive::EReason reason) noexcept(true) { - aliveStatus = Alive::EStatus::expired; + aliveStatus = EStatus::kExpired; lastProcessExecutionError = ifexm::ProcessCfg::kDefaultProcessExecutionError; switch (reason) @@ -524,9 +531,27 @@ void Alive::switchToExpired(Alive::EReason reason) noexcept(true) referenceCycleEnd = UINT64_MAX; dataLossReason = EDataLossReason::kNoDataLoss; + const bool enqueued = recoveryClient_p->sendRecoveryRequest(processIdentifier_); + if (enqueued) + { + logger_r.LogDebug() << "Recovery request enqueued successfully for alive supervision " << getConfigName() + << "failure"; + } + else + { + logger_r.LogError() << "Failed to enqueue recovery request for alive supervision" << getConfigName() + << "failure (ring buffer full)"; + recoveryEnqueueFailed_ = true; + } + pushResultToObservers(); } +bool Alive::hasRecoveryEnqueueFailed(void) const noexcept +{ + return recoveryEnqueueFailed_; +} + void Alive::setNextCycle(void) noexcept(true) { if (!setReferenceCycleTimestamps(referenceCycleEnd)) @@ -548,18 +573,19 @@ bool Alive::isMaxError(void) const noexcept(true) void Alive::logExpiredFailedStateDetails() const noexcept(true) { std::string_view failedState{""}; - if (aliveStatus == Alive::EStatus::failed) + if (aliveStatus == EStatus::kFailed) { // failedSupervisionCycles == 1 if just switched to FAILED and > 1 if were already in FAILED before failedState = (failedSupervisionCycles > 1U) ? "next cycle FAILED" : "switched to FAILED"; } - if (aliveStatus == Alive::EStatus::expired) + if (aliveStatus == EStatus::kExpired) { failedState = "switched to EXPIRED"; } const bool minError{isMinError()}; - /* RULECHECKER_comment(0, 4, check_conditional_as_sub_expression, "Ternary operation is very simple", true_no_defect) */ + /* RULECHECKER_comment(0, 4, check_conditional_as_sub_expression, "Ternary operation is very simple", + * true_no_defect) */ const std::uint64_t aliveIndicationMargin{minError ? k_minAliveIndications : k_maxAliveIndications}; const std::string_view expectedComparison{minError ? ">=" : "<="}; logger_r.LogWarn() << "Alive Supervision (" << getConfigName() << ")" << failedState << ", due to" @@ -568,6 +594,90 @@ void Alive::logExpiredFailedStateDetails() const noexcept(true) << k_failedSupervisionCyclesTolerance; } +timers::NanoSecondType Alive::getTimestampOfUpdateEvent(const TimeSortedUpdateEvent f_updateEvent) noexcept(true) +{ + timers::NanoSecondType timestamp{0U}; + if (std::holds_alternative(f_updateEvent)) + { + timestamp = std::get(f_updateEvent).timestamp; + } + else if (std::holds_alternative(f_updateEvent)) + { + timestamp = std::get(f_updateEvent).timestamp; + } + else + { + assert(std::holds_alternative(f_updateEvent)); + // coverity[cert_exp34_c_violation] SyncSnapshot type is stored also check assert above + // coverity[dereference] SyncSnapshot type is stored also check assert above + timestamp = std::get(f_updateEvent); + } + + return timestamp; +} + +Alive::EUpdateEventType Alive::getEventType(ProcessStateTracker& f_processTracker_r, + const TimeSortedUpdateEvent f_updateEvent) noexcept(true) +{ + EUpdateEventType currentUpdateType{EUpdateEventType::kNoChange}; + + if (std::holds_alternative(f_updateEvent)) + { + const auto processStateSnapshot{std::get(f_updateEvent)}; + const auto processEvent{f_processTracker_r.generateProcessChangeEvent(processStateSnapshot)}; + + setProcessExecutionErrorForProcess(processStateSnapshot.identifier_p, processStateSnapshot.executionError); + + if (processEvent.changeType == ProcessStateTracker::EProcessChangeType::kActivation) + { + currentUpdateType = EUpdateEventType::kActivation; + } + else if (processEvent.changeType == ProcessStateTracker::EProcessChangeType::kDeactivation) + { + currentUpdateType = EUpdateEventType::kDeactivation; + } + else if (processEvent.changeType == ProcessStateTracker::EProcessChangeType::kRecoveredFromCrash) + { + currentUpdateType = EUpdateEventType::kRecoveredFromCrash; + } + else + { + currentUpdateType = EUpdateEventType::kNoChange; + } + } + else if (std::holds_alternative(f_updateEvent)) + { + // Address for checkpoint is not known/stored + currentUpdateType = EUpdateEventType::kCheckpoint; + } + else + { + assert(std::holds_alternative(f_updateEvent)); + currentUpdateType = EUpdateEventType::kSync; + } + + return currentUpdateType; +} + +ifexm::ProcessCfg::ProcessExecutionError Alive::getProcessExecutionError(void) const noexcept(true) +{ + return lastProcessExecutionError; +} + +ifexm::ProcessCfg::ProcessExecutionError Alive::getProcessExecutionErrorForProcess( + const ifexm::ProcessState* f_process_p) noexcept(true) +{ + assert(processExecErrs.find(f_process_p) != processExecErrs.end()); + return processExecErrs[f_process_p]; +} + +void Alive::setProcessExecutionErrorForProcess(const ifexm::ProcessState* f_process_p, + ifexm::ProcessCfg::ProcessExecutionError f_error) noexcept(true) +{ + assert(processExecErrs.find(f_process_p) != processExecErrs.end()); + processExecErrs[f_process_p] = f_error; +} + } // namespace supervision } // namespace saf } // namespace lcm diff --git a/score/launch_manager/daemon/src/alive_monitor/details/supervision/Alive.hpp b/score/launch_manager/daemon/src/alive_monitor/details/supervision/Alive.hpp index 7ab320c3e..02e064e6d 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/supervision/Alive.hpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/supervision/Alive.hpp @@ -15,16 +15,20 @@ #define ALIVE_HPP_INCLUDED #ifndef PHM_PRIVATE -# define PHM_PRIVATE private +#define PHM_PRIVATE private #endif #include +#include +#include #include "score/mw/launch_manager/alive_monitor/Monitor.h" +#include "score/mw/launch_manager/alive_monitor/details/common/Observer.hpp" #include "score/mw/launch_manager/alive_monitor/details/common/TimeSortingBuffer.hpp" #include "score/mw/launch_manager/alive_monitor/details/ifappl/Checkpoint.hpp" +#include "score/mw/launch_manager/alive_monitor/details/ifexm/ProcessState.hpp" #include "score/mw/launch_manager/alive_monitor/details/logging/PhmLogger.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/ICheckpointSupervision.hpp" +#include "score/mw/launch_manager/alive_monitor/details/supervision/ISupervision.hpp" #include "score/mw/launch_manager/alive_monitor/details/supervision/ProcessStateTracker.hpp" #include "score/mw/launch_manager/alive_monitor/details/supervision/SupervisionCfg.hpp" #include "score/mw/launch_manager/alive_monitor/details/timers/Timers_OsClock.hpp" @@ -35,14 +39,8 @@ namespace lcm { namespace saf { -namespace ifexm -{ -class ProcessState; -} // namespace ifexm namespace supervision { -/// Forward Declaration -class Local; /// @brief Alive Supervision /// @details Alive Supervision contains the logic for health monitoring - Alive supervision @@ -61,9 +59,12 @@ class Local; /// @endverbatim /* RULECHECKER_comment(0, 3, check_multiple_non_interface_bases, "Observable and Observer are tolerated\ exceptions of this rule.", false) */ -class Alive : public ICheckpointSupervision, public saf::common::Observable +class Alive : public ISupervision, + public saf::common::Observable, + public saf::common::Observer, + public saf::common::Observer { -public: + public: /// @brief No Default Constructor Alive() = delete; @@ -92,33 +93,120 @@ class Alive : public ICheckpointSupervision, public saf::common::Observable; + + /// @brief Enumeration of supervision update events + enum class EUpdateEventType : std::uint8_t + { + kNoChange = 0U, ///< update event for no change in activation/deactivation + kActivation = 1U, ///< update event for activation of supervision + kDeactivation = 2U, ///< update event for deactivation of supervision + kCheckpoint = 3U, ///< update event for reported checkpoint + kEvaluation = 4U, ///< artificial update event for evaluation of supervision (relevant for Alive only) + kSync = 5U, ///< artificial update event for synchronization (relevant for Alive and Deadline only) + kRecoveredFromCrash = 6U ///< update event for a crashed process which has been successfully restarted + }; + + /// @brief Get timestamp of current update event + /// @param [in] f_updateEvent Sorted update event (e.g, Activation, Deactivation, Checkpoint, ...) from Buffer + /// @return Timestamp of update event + static timers::NanoSecondType getTimestampOfUpdateEvent(const TimeSortedUpdateEvent f_updateEvent) noexcept(true); + + /// @brief Get the type of update event + /// @details Get the type of update event. If it is process event, internal buffer of process tracker is updated + /// with this process event. + /// @param [in] f_processTracker_r Process tracker object + /// @param [in] f_updateEvent Sorted update event (e.g, Activation, Deactivation, Checkpoint, ...) from + /// Buffer + /// @return Type of update event + EUpdateEventType getEventType(ProcessStateTracker& f_processTracker_r, + const TimeSortedUpdateEvent f_updateEvent) noexcept(true); + + /// @brief Get the processExecutionError for a specific process + /// @param[in] f_process_p The process state + /// @return The stored ProcessExecutionError for that process + ifexm::ProcessCfg::ProcessExecutionError getProcessExecutionErrorForProcess( + const ifexm::ProcessState* f_process_p) noexcept(true); + + /// @brief Stores the processExecutionError for a specific process + /// @param[in] f_process_p The process state + /// @param[in] f_error The ProcessExecutionError for the given process state + void setProcessExecutionErrorForProcess(const ifexm::ProcessState* f_process_p, + ifexm::ProcessCfg::ProcessExecutionError f_error) noexcept(true); -PHM_PRIVATE: /// @brief Check and trigger transition out of state Deactivated /// @param [in] f_updateEventType Type of update event (e.g, Activation, Deactivation, Checkpoint, ...) /// @param [in] f_updateEventTimestamp Timestamp of update event - void - checkTransitionsOutOfDeactivated(const ICheckpointSupervision::EUpdateEventType f_updateEventType, - const timers::NanoSecondType f_updateEventTimestamp) noexcept(true); + void checkTransitionsOutOfDeactivated(const EUpdateEventType f_updateEventType, + const timers::NanoSecondType f_updateEventTimestamp) noexcept(true); /// @brief Check and trigger common transitions to state Deactivated /// @param [in] f_updateEventType Type of update event (e.g, Activation, Deactivation, Checkpoint, ...) /// @param [in] f_updateEventTimestamp Timestamp of update event - void checkTransitionsToDeactivated(const ICheckpointSupervision::EUpdateEventType f_updateEventType, + void checkTransitionsToDeactivated(const EUpdateEventType f_updateEventType, const timers::NanoSecondType f_updateEventTimestamp) noexcept(true); /// @brief Check and trigger recovery transition @@ -128,19 +216,19 @@ class Alive : public ICheckpointSupervision, public saf::common::Observable recoveryClient_p; + + /// @brief Identifier of the supervised process, sent via recovery client when supervision expires + const score::lcm::IdentifierHash processIdentifier_; + + /// @brief Set to true when sendRecoveryRequest fails (ring buffer full) + bool recoveryEnqueueFailed_{false}; + /// @brief Data loss reason EDataLossReason dataLossReason{EDataLossReason::kNoDataLoss}; /// @brief status of Alive supervision - EStatus aliveStatus{EStatus::deactivated}; + EStatus aliveStatus{EStatus::kDeactivated}; /// @brief alive reference cycle start time in [nano seconds] timers::NanoSecondType referenceCycleStart{0U}; @@ -285,6 +382,14 @@ class Alive : public ICheckpointSupervision, public saf::common::Observable processExecErrs{}; }; } // namespace supervision diff --git a/score/launch_manager/daemon/src/alive_monitor/details/supervision/Alive_UT.cpp b/score/launch_manager/daemon/src/alive_monitor/details/supervision/Alive_UT.cpp new file mode 100644 index 000000000..9b7efaf6a --- /dev/null +++ b/score/launch_manager/daemon/src/alive_monitor/details/supervision/Alive_UT.cpp @@ -0,0 +1,249 @@ +/******************************************************************************** + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include +#include + +#include +#include + +#include "score/mw/launch_manager/common/identifier_hash.hpp" +#include "score/mw/launch_manager/recovery_client/irecovery_client.h" +#include "score/mw/launch_manager/alive_monitor/details/ifappl/Checkpoint.hpp" +#include "score/mw/launch_manager/alive_monitor/details/ifexm/ProcessCfg.hpp" +#include "score/mw/launch_manager/alive_monitor/details/ifexm/ProcessState.hpp" +#include "score/mw/launch_manager/alive_monitor/details/supervision/Alive.hpp" +#include "score/mw/launch_manager/alive_monitor/details/supervision/SupervisionCfg.hpp" + +using namespace testing; + +using EStatus = score::lcm::saf::supervision::Alive::EStatus; + +namespace +{ + +class MockRecoveryClient : public score::lcm::IRecoveryClient +{ + public: + MOCK_METHOD(bool, + sendRecoveryRequest, + (const score::lcm::IdentifierHash& process_group_identifier), + (noexcept, override)); + MOCK_METHOD(std::optional, getNextRequest, (), (noexcept, override)); + MOCK_METHOD(bool, hasOverflow, (), (const, noexcept, override)); +}; + +/// Helper: build a minimal Alive under test. +/// Owns all supporting objects so they outlive the Alive. +struct AliveFixture +{ + static constexpr char kProcessName[] = "test_proc"; + static constexpr char kCheckpointName[] = "test_cp"; + static constexpr score::lcm::saf::common::ProcessId kProcessId = 42U; + + struct Builder + { + uint32_t failedCyclesTolerance = 0U; + uint32_t minIndications = 1U; + uint32_t maxIndications = 3U; + score::lcm::saf::timers::NanoSecondType referenceCycleNs = 1000U; + + Builder& withFailedCyclesTolerance(uint32_t val) + { + failedCyclesTolerance = val; + return *this; + } + Builder& withMinIndications(uint32_t val) + { + minIndications = val; + return *this; + } + Builder& withMaxIndications(uint32_t val) + { + maxIndications = val; + return *this; + } + Builder& withReferenceCycleNs(score::lcm::saf::timers::NanoSecondType val) + { + referenceCycleNs = val; + return *this; + } + + [[nodiscard]] AliveFixture build() const + { + return AliveFixture{*this}; + } + }; + + const score::lcm::saf::common::ProcessGroupId kRunningPgId = score::lcm::IdentifierHash{"MainPG/Full"}.data(); + + const score::lcm::IdentifierHash kProcessIdentifier{"test_proc"}; + + std::shared_ptr mockClient = std::make_shared(); + + score::lcm::saf::ifexm::ProcessState processState; + score::lcm::saf::ifappl::Checkpoint checkpoint; + + std::vector pgStateIds; + std::vector refProcesses; + + std::unique_ptr alive; + + explicit AliveFixture(const Builder& bld) + : processState(makeProcessCfg()), checkpoint(kCheckpointName, 1U, &processState) + { + pgStateIds = {kRunningPgId}; + refProcesses = {&processState}; + + score::lcm::saf::supervision::AliveSupervisionCfg cfg{checkpoint, pgStateIds, refProcesses}; + cfg.cfgName_p = "test_alive"; + cfg.aliveReferenceCycle = bld.referenceCycleNs; + cfg.minAliveIndications = bld.minIndications; + cfg.maxAliveIndications = bld.maxIndications; + cfg.isMinCheckDisabled = (bld.minIndications == 0U); + cfg.isMaxCheckDisabled = (bld.maxIndications == 0U); + cfg.failedCyclesTolerance = bld.failedCyclesTolerance; + cfg.checkpointBufferSize = 16U; + cfg.recoveryClient = mockClient; + cfg.processIdentifier = kProcessIdentifier; + + alive = std::make_unique(cfg); + processState.attachObserver(*alive); + } + + /// Simulate the process reporting kRunning at the given timestamp in the configured PG state. + void activateProcess(score::lcm::saf::timers::NanoSecondType timestamp) + { + processState.setTimestamp(timestamp); + processState.setProcessGroupState(kRunningPgId); + processState.setState(score::lcm::saf::ifexm::ProcessState::EProcState::running); + processState.pushData(); + } + + /// Report one alive heartbeat checkpoint at the given timestamp. + void reportHeartbeat(score::lcm::saf::timers::NanoSecondType timestamp) + { + checkpoint.pushData(timestamp); + } + + private: + static score::lcm::saf::ifexm::ProcessCfg makeProcessCfg() + { + score::lcm::saf::ifexm::ProcessCfg cfg{}; + cfg.processShortName = kProcessName; + cfg.processId = kProcessId; + cfg.configuredProcessGroupStates = {score::lcm::IdentifierHash{"MainPG/Full"}.data()}; + cfg.processExecutionErrors = {1U}; + return cfg; + } +}; + +} // namespace + +class AliveSupervisionTest : public ::testing::Test +{ + protected: + void SetUp() override + { + RecordProperty("TestType", "interface-test"); + RecordProperty("DerivationTechnique", "explorative-testing "); + } +}; + +TEST_F(AliveSupervisionTest, AliveTransitionsOkToExpiredOnMissingHeartbeat) +{ + RecordProperty("Description", + "Verify that Alive transitions from deactivated -> ok -> expired when no heartbeats are reported " + "and failedCyclesTolerance == 0. sendRecoveryRequest must be called exactly once with the " + "configured recovery target hash."); + AliveFixture fix = AliveFixture::Builder{}.build(); + + EXPECT_CALL(*fix.mockClient, sendRecoveryRequest(fix.kProcessIdentifier)).Times(1).WillOnce(Return(true)); + + EXPECT_EQ(fix.alive->getStatus(), EStatus::kDeactivated); + + fix.activateProcess(10U); + fix.alive->evaluate(11U); + EXPECT_EQ(fix.alive->getStatus(), EStatus::kOk); + + // No heartbeats; reference cycle ends at 10 + 1000 = 1010 + fix.alive->evaluate(1011U); + EXPECT_EQ(fix.alive->getStatus(), EStatus::kExpired); +} + +TEST_F(AliveSupervisionTest, AliveStaysOkWithCorrectHeartbeats) +{ + RecordProperty("Description", + "Verify that sending at least minIndications heartbeats per cycle keeps Alive in ok."); + AliveFixture fix = AliveFixture::Builder{}.build(); + + EXPECT_CALL(*fix.mockClient, sendRecoveryRequest(_)).Times(0); + + fix.activateProcess(10U); + fix.alive->evaluate(11U); + EXPECT_EQ(fix.alive->getStatus(), EStatus::kOk); + + // Cycle 1: one heartbeat at t=500 (within [10, 1010]), evaluate at t=1011 + fix.reportHeartbeat(500U); + fix.alive->evaluate(1011U); + EXPECT_EQ(fix.alive->getStatus(), EStatus::kOk); + + // Cycle 2: one heartbeat at t=1500 (within [1010, 2010]), evaluate at t=2011 + fix.reportHeartbeat(1500U); + fix.alive->evaluate(2011U); + EXPECT_EQ(fix.alive->getStatus(), EStatus::kOk); +} + +TEST_F(AliveSupervisionTest, AliveReportsEnqueueFailureWhenRingBufferFull) +{ + RecordProperty( + "Description", + "Verify that when sendRecoveryRequest fails (ring buffer full), hasRecoveryEnqueueFailed reports true."); + + AliveFixture fix = AliveFixture::Builder{}.build(); + + EXPECT_CALL(*fix.mockClient, sendRecoveryRequest(fix.kProcessIdentifier)).Times(1).WillOnce(Return(false)); + + fix.activateProcess(10U); + fix.alive->evaluate(11U); + + EXPECT_FALSE(fix.alive->hasRecoveryEnqueueFailed()); + + fix.alive->evaluate(1011U); + EXPECT_EQ(fix.alive->getStatus(), EStatus::kExpired); + EXPECT_TRUE(fix.alive->hasRecoveryEnqueueFailed()); +} + +TEST_F(AliveSupervisionTest, AliveDebouncesThroughFailedBeforeExpired) +{ + RecordProperty("Description", + "Verify that failedCyclesTolerance debouncing works: with tolerance=1 the supervision passes " + "through failed before reaching expired."); + AliveFixture fix = AliveFixture::Builder{}.withFailedCyclesTolerance(1U).build(); + + EXPECT_CALL(*fix.mockClient, sendRecoveryRequest(fix.kProcessIdentifier)) + .Times(1) + .WillOnce(::testing::Return(true)); + + fix.activateProcess(10U); + fix.alive->evaluate(11U); + EXPECT_EQ(fix.alive->getStatus(), EStatus::kOk); + + // First missed cycle: ok -> failed (tolerance not yet exceeded) + fix.alive->evaluate(1011U); + EXPECT_EQ(fix.alive->getStatus(), EStatus::kFailed); + + // Second missed cycle: tolerance exceeded -> expired + fix.alive->evaluate(2011U); + EXPECT_EQ(fix.alive->getStatus(), EStatus::kExpired); +} diff --git a/score/launch_manager/daemon/src/alive_monitor/details/supervision/BUILD b/score/launch_manager/daemon/src/alive_monitor/details/supervision/BUILD index 71e213605..6e7d6127b 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/supervision/BUILD +++ b/score/launch_manager/daemon/src/alive_monitor/details/supervision/BUILD @@ -51,23 +51,6 @@ cc_library( ], ) -cc_library( - name = "i_checkpoint_supervision", - srcs = ["ICheckpointSupervision.cpp"], - hdrs = ["ICheckpointSupervision.hpp"], - include_prefix = "score/mw/launch_manager/alive_monitor/details/supervision", - strip_include_prefix = "/score/launch_manager/daemon/src/alive_monitor/details/supervision", - visibility = ["//score/launch_manager/daemon/src/alive_monitor:__subpackages__"], - deps = [ - ":i_supervision", - ":process_state_tracker", - ":supervision_cfg", - "//score/launch_manager/daemon/src/alive_monitor:alive_monitor_h", - "//score/launch_manager/daemon/src/alive_monitor/details/common:observer", - "//score/launch_manager/daemon/src/alive_monitor/details/ifexm:process_state", - ], -) - cc_library( name = "alive", srcs = ["Alive.cpp"], @@ -76,7 +59,7 @@ cc_library( strip_include_prefix = "/score/launch_manager/daemon/src/alive_monitor/details/supervision", visibility = ["//score/launch_manager/daemon/src/alive_monitor:__subpackages__"], deps = [ - ":i_checkpoint_supervision", + ":i_supervision", ":process_state_tracker", ":supervision_cfg", "//score/launch_manager/daemon/src/alive_monitor:alive_monitor_h", @@ -85,48 +68,15 @@ cc_library( "//score/launch_manager/daemon/src/alive_monitor/details/ifexm:process_state", "//score/launch_manager/daemon/src/alive_monitor/details/logging:phm_logging", "//score/launch_manager/daemon/src/alive_monitor/details/timers:timers_os_clock", + "//score/launch_manager/daemon/src/recovery_client", ], ) -cc_library( - name = "local", - srcs = ["Local.cpp"], - hdrs = ["Local.hpp"], - include_prefix = "score/mw/launch_manager/alive_monitor/details/supervision", - strip_include_prefix = "/score/launch_manager/daemon/src/alive_monitor/details/supervision", - visibility = ["//score/launch_manager/daemon/src/alive_monitor:__subpackages__"], +cc_test( + name = "Alive_UT", + srcs = ["Alive_UT.cpp"], deps = [ ":alive", - ":i_checkpoint_supervision", - ":i_supervision", - ":supervision_cfg", - "//score/launch_manager/daemon/src/alive_monitor:alive_monitor_h", - "//score/launch_manager/daemon/src/alive_monitor/details/common:observer", - "//score/launch_manager/daemon/src/alive_monitor/details/common:time_sorting_buffer", - "//score/launch_manager/daemon/src/alive_monitor/details/logging:phm_logging", - "//score/launch_manager/daemon/src/alive_monitor/details/timers:timers_os_clock", - ], -) - -cc_library( - name = "global", - srcs = ["Global.cpp"], - hdrs = ["Global.hpp"], - include_prefix = "score/mw/launch_manager/alive_monitor/details/supervision", - strip_include_prefix = "/score/launch_manager/daemon/src/alive_monitor/details/supervision", - visibility = ["//score/launch_manager/daemon/src/alive_monitor:__subpackages__"], - deps = [ - ":i_checkpoint_supervision", - ":i_supervision", - ":local", - ":supervision_cfg", - "//score/launch_manager/daemon/src/alive_monitor:alive_monitor_h", - "//score/launch_manager/daemon/src/alive_monitor/details/common:observer", - "//score/launch_manager/daemon/src/alive_monitor/details/common:time_sorting_buffer", - "//score/launch_manager/daemon/src/alive_monitor/details/common:types", - "//score/launch_manager/daemon/src/alive_monitor/details/ifexm:process_state", - "//score/launch_manager/daemon/src/alive_monitor/details/logging:phm_logging", - "//score/launch_manager/daemon/src/alive_monitor/details/recovery:notification", - "//score/launch_manager/daemon/src/alive_monitor/details/timers:timers_os_clock", + "@googletest//:gtest_main", ], ) diff --git a/score/launch_manager/daemon/src/alive_monitor/details/supervision/Global.cpp b/score/launch_manager/daemon/src/alive_monitor/details/supervision/Global.cpp deleted file mode 100644 index 46b4baf54..000000000 --- a/score/launch_manager/daemon/src/alive_monitor/details/supervision/Global.cpp +++ /dev/null @@ -1,565 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2025 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#include "score/mw/launch_manager/alive_monitor/details/supervision/Global.hpp" - -#include -#include "score/mw/launch_manager/alive_monitor/details/ifexm/ProcessState.hpp" -#include "score/mw/launch_manager/alive_monitor/details/logging/PhmLogger.hpp" -#include "score/mw/launch_manager/alive_monitor/details/recovery/Notification.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/Local.hpp" - -namespace score -{ -namespace lcm -{ -namespace saf -{ -namespace recovery -{ -class Notification; -} -namespace supervision -{ - -static constexpr ICheckpointSupervision::EType kInternalErrorSupervisionType{ - ICheckpointSupervision::EType::aliveSupervision}; - -Global::Global(const GlobalSupervisionCfg& f_globalCfg_r) : - ISupervision(f_globalCfg_r.cfgName_p), - Observer(), - Observer(), - k_expiredTolerances(f_globalCfg_r.expiredTolerances_r), - k_refFuntionGroupStates(f_globalCfg_r.refFuntionGroupStates_r), - timeSortingLocalSupStateBuffer(common::TimeSortingBuffer(f_globalCfg_r.localEventBufferSize)), - logger_r(logging::PhmLogger::getLogger(logging::PhmLogger::EContext::supervision)) -{ - // Should always be true as the vectors are paired - assert(k_expiredTolerances.size() == k_refFuntionGroupStates.size()); - - assert((globalStatus == score::mw::lifecycle::GlobalSupervisionStatus::kDeactivated) && - ("Global Supervision must start in deactivated state, see SWS_PHM_00218")); -} - -// coverity[exn_spec_violation:FALSE] std::length_error is not thrown from push() which uses fixed-size-vector -void Global::updateData(const ifexm::ProcessState& f_observable_r) noexcept(true) -{ - const ifexm::ProcessState::EProcState kInitState = ifexm::ProcessState::EProcState::starting; - - // Ignore process updates other than init/running, see #58195 - // Depending on the order of Exm process termination/start when performing a PG state change, the - // sigterm/off state from the old PG state may be received after the init/running events for the new PG state. - // Ignoring sigterm/off states makes sure we take the expirationTolerance for the new PG state. - const ifexm::ProcessState::EProcState procState{f_observable_r.getState()}; - if (!((procState == kInitState) || (procState == ifexm::ProcessState::EProcState::running))) - { - return; - } - - common::ProcessGroupId currentState{f_observable_r.getProcessGroupState()}; - const timers::NanoSecondType timestamp{f_observable_r.getTimestamp()}; - bool isFound{false}; - - for (size_t index{0U}; index < k_refFuntionGroupStates.size(); index++) - { - if (currentState == k_refFuntionGroupStates[index]) - { - isFound = true; - // Vector k_refFuntionGroupStates and k_expiredTolerances are 'paired' - // coverity[autosar_cpp14_a8_5_2_violation:FALSE] type auto shall not be initialized with {} AUTOSAR.8.5.3A - const auto stateChange = TimeSortedPGStateChange{k_expiredTolerances[index], timestamp}; - if (!timeSortingLocalSupStateBuffer.push(TimeSortedElem(stateChange), timestamp)) - { - isDataLossEvent = true; - } - break; - } - } - - if (!isFound) - { - // This should theoretically be prevented by TPS_Manifest constraints, to be on the safe side the - // lowest possible debounce time is used for this case. - // coverity[autosar_cpp14_a8_5_2_violation:FALSE] type auto shall not be initialized with {} AUTOSAR.8.5.3A - const auto stateChange = TimeSortedPGStateChange{0U, timestamp}; - if (!timeSortingLocalSupStateBuffer.push(TimeSortedElem(stateChange), timestamp)) - { - isDataLossEvent = true; - } - } -} - -// coverity[exn_spec_violation:FALSE] std::length_error is not thrown from push() which uses fixed-size-vector -void Global::updateData(const Local& f_observable_r) noexcept(true) -{ - TimeSortedLocalSupState localState{}; - localState.localId = &f_observable_r; - localState.state = f_observable_r.getStatus(); - localState.supervisionType = f_observable_r.getSupervisionType(); - localState.timestamp = f_observable_r.getTimestamp(); - localState.executionError = f_observable_r.getProcessExecutionError(); - if (!timeSortingLocalSupStateBuffer.push(TimeSortedElem(localState), localState.timestamp)) - { - isDataLossEvent = true; - } -} - -void Global::registerLocalSupervision(const Local& f_localSupervision_r) -{ - // coverity[autosar_cpp14_a8_5_2_violation:FALSE] type auto shall not be initialized with {} AUTOSAR.8.5.3A - const auto ret = - localStatusOverTime.insert({&f_localSupervision_r, score::mw::lifecycle::LocalSupervisionStatus::kDeactivated}); - static_cast(ret); - assert(ret.second && "Same local supervision element was registered twice!"); -} - -void Global::evaluate(const timers::NanoSecondType f_syncTimestamp) -{ - if (isDataLossEvent) - { - expiredSupervision = kInternalErrorSupervisionType; - executionError = ifexm::ProcessCfg::kDefaultProcessExecutionError; - switchToStopped(EGlobalStoppedReason::history_buffer_overflow); - timeSortingLocalSupStateBuffer.clear(); - isDataLossEvent = false; - return; - } - - processTimeSortedEvents(); - - // We still need to check the debounce timer in case we are in expired state. - // Debouncing was only evaluated against timestamp from local supervision update / pg state change before. - if (score::mw::lifecycle::GlobalSupervisionStatus::kExpired == globalStatus) - { - if (isDebounced(f_syncTimestamp)) - { - switchToStopped(EGlobalStoppedReason::expirationTimeout); - } - } -} - -void Global::processTimeSortedEvents() -{ - const Global::TimeSortedElem* timeSortedEvent{timeSortingLocalSupStateBuffer.getNextElement()}; - - while (timeSortedEvent != nullptr) - { - if (std::holds_alternative(*timeSortedEvent)) - { - evaluatePGStateChange(std::get(*timeSortedEvent)); - } - else - { - // Only two types are possible, therefore it must be TimeSortedLocalSupState - assert(std::holds_alternative(*timeSortedEvent)); - // coverity[cert_exp34_c_violation] TimeSortedLocalSupState type is stored also check assert above - // coverity[dereference] TimeSortedLocalSupState type is stored also check assert above - evaluateLocalSupervisionUpdate(std::get(*timeSortedEvent)); - } - - timeSortedEvent = timeSortingLocalSupStateBuffer.getNextElement(); - } - timeSortingLocalSupStateBuffer.clear(); -} - -void Global::evaluateLocalSupervisionUpdate(const TimeSortedLocalSupState& f_local_r) -{ - // The table reflects the status of all local supervisions at that point in time. - // All local supervisions are already present in the map, no new entries are added - // and no new memory is being allocated. - assert(localStatusOverTime.find(f_local_r.localId) != localStatusOverTime.end()); - localStatusOverTime[f_local_r.localId] = f_local_r.state; - - switch (globalStatus) - { - case score::mw::lifecycle::GlobalSupervisionStatus::kDeactivated: - { - checkTransitionsOutOfDeactivated(f_local_r); - break; - } - - case score::mw::lifecycle::GlobalSupervisionStatus::kOK: - { - checkTransitionsOutOfOk(f_local_r); - break; - } - - case score::mw::lifecycle::GlobalSupervisionStatus::kFailed: - { - checkTransitionsOutOfFailed(f_local_r); - break; - } - case score::mw::lifecycle::GlobalSupervisionStatus::kExpired: - { - checkTransitionsOutOfExpired(f_local_r); - break; - } - case score::mw::lifecycle::GlobalSupervisionStatus::kStopped: - { - checkTransitionsOutOfStopped(); - break; - } - default: - { - // Data corruption - expiredSupervision = kInternalErrorSupervisionType; - executionError = ifexm::ProcessCfg::kDefaultProcessExecutionError; - switchToStopped(EGlobalStoppedReason::data_corruption); - break; - } - } -} -void Global::evaluatePGStateChange(const TimeSortedPGStateChange f_pgChange) noexcept -{ - expiredTolerance = f_pgChange.expiredTolerance; - if ((score::mw::lifecycle::GlobalSupervisionStatus::kExpired == globalStatus) && (isDebounced(f_pgChange.timestamp))) - { - switchToStopped(EGlobalStoppedReason::expirationTimeout); - } -} - -score::mw::lifecycle::GlobalSupervisionStatus Global::getStatus(void) const noexcept -{ - return globalStatus; -} - -void Global::registerRecoveryNotification(score::lcm::saf::recovery::Notification& f_notification_r) -{ - // Register the Recovery Notification by adding a pointer to it in a vector - registeredRecoveryNotifications.push_back(&f_notification_r); -} - -void Global::checkTransitionsOutOfDeactivated(const TimeSortedLocalSupState& f_local_r) -{ - score::mw::lifecycle::LocalSupervisionStatus status{f_local_r.state}; - - if (score::mw::lifecycle::LocalSupervisionStatus::kOK == status) - { - switchToOk(); - } - else if (score::mw::lifecycle::LocalSupervisionStatus::kFailed == status) - { - switchToFailed(); - } - else if (score::mw::lifecycle::LocalSupervisionStatus::kExpired == status) - { - expiredSupervision = f_local_r.supervisionType; - executionError = f_local_r.executionError; - - if (isDebounced(f_local_r.timestamp)) - { - switchToStopped(EGlobalStoppedReason::expirationTimeout); - } - else - { - switchToExpired(f_local_r.timestamp); - } - } - else - { - // Remain in status Deactivated - } -} - -void Global::checkTransitionsOutOfOk(const TimeSortedLocalSupState& f_local_r) -{ - score::mw::lifecycle::LocalSupervisionStatus status{f_local_r.state}; - - if (score::mw::lifecycle::LocalSupervisionStatus::kDeactivated == status) - { - const score::mw::lifecycle::LocalSupervisionStatus accState{getAccumulatedState()}; - if (score::mw::lifecycle::LocalSupervisionStatus::kDeactivated == accState) - { - switchToDeactivated(); - } - } - else if (score::mw::lifecycle::LocalSupervisionStatus::kFailed == status) - { - switchToFailed(); - } - else if (score::mw::lifecycle::LocalSupervisionStatus::kExpired == status) - { - expiredSupervision = f_local_r.supervisionType; - executionError = f_local_r.executionError; - - if (isDebounced(f_local_r.timestamp)) - { - switchToStopped(EGlobalStoppedReason::expirationTimeout); - } - else - { - switchToExpired(f_local_r.timestamp); - } - } - else - { - // Remain in status Ok - } -} - -void Global::checkTransitionsOutOfFailed(const TimeSortedLocalSupState& f_local_r) -{ - score::mw::lifecycle::LocalSupervisionStatus status{f_local_r.state}; - - if (score::mw::lifecycle::LocalSupervisionStatus::kExpired == status) - { - expiredSupervision = f_local_r.supervisionType; - executionError = f_local_r.executionError; - - if (isDebounced(f_local_r.timestamp)) - { - switchToStopped(EGlobalStoppedReason::expirationTimeout); - } - else - { - switchToExpired(f_local_r.timestamp); - } - } - else if (score::mw::lifecycle::LocalSupervisionStatus::kFailed == status) - { - // Remain in status Failed - } - else // Local Supervision reported Deactivated or Ok - { - const score::mw::lifecycle::LocalSupervisionStatus accState{getAccumulatedState()}; - if (score::mw::lifecycle::LocalSupervisionStatus::kDeactivated == accState) - { - switchToDeactivated(); - } - else if (score::mw::lifecycle::LocalSupervisionStatus::kOK == accState) - { - switchToOk(); - } - else - { - // Remain in status Failed - } - } -} - -/* RULECHECKER_comment(0, 3, check_max_control_nesting_depth, "Control nesting greater 3 is tolerated for this\ - function.", true_no_defect) */ -void Global::checkTransitionsOutOfExpired(const TimeSortedLocalSupState& f_local_r) -{ - score::mw::lifecycle::LocalSupervisionStatus status{f_local_r.state}; - - if (isDebounced(f_local_r.timestamp)) - { - switchToStopped(EGlobalStoppedReason::expirationTimeout); - } - else if (score::mw::lifecycle::LocalSupervisionStatus::kExpired == status) - { - // Remain in status Expired - } - else // Local Supervision reported Deactivated, Ok or Failed - { - const score::mw::lifecycle::LocalSupervisionStatus accState{getAccumulatedState()}; - if (score::mw::lifecycle::LocalSupervisionStatus::kDeactivated == accState) - { - switchToDeactivated(); - } - else if (score::mw::lifecycle::LocalSupervisionStatus::kOK == accState) - { - switchToOk(); - } - else if (score::mw::lifecycle::LocalSupervisionStatus::kFailed == accState) - { - switchToFailed(); - } - else - { - // Remain in status Expired - } - } -} - -void Global::checkTransitionsOutOfStopped() -{ - const score::mw::lifecycle::LocalSupervisionStatus accState{getAccumulatedState()}; - if (score::mw::lifecycle::LocalSupervisionStatus::kDeactivated == accState) - { - switchToDeactivated(); - } - else if (score::mw::lifecycle::LocalSupervisionStatus::kOK == accState) - { - switchToOk(); - } - else if (score::mw::lifecycle::LocalSupervisionStatus::kFailed == accState) - { - switchToFailed(); - } - else - { - // Remain in status Stopped - } -} - -void Global::switchToDeactivated() noexcept -{ - logger_r.LogDebug() << "Global Supervision (" << getConfigName() << ") switched to DEACTIVATED."; - globalStatus = score::mw::lifecycle::GlobalSupervisionStatus::kDeactivated; - - startExpired = UINT64_MAX; - expiredTolerance = 0U; -} - -void Global::switchToOk() noexcept -{ - logger_r.LogInfo() << "Global Supervision (" << getConfigName() << ") switched to OK."; - globalStatus = score::mw::lifecycle::GlobalSupervisionStatus::kOK; - - startExpired = UINT64_MAX; -} - -void Global::switchToFailed() noexcept -{ - logger_r.LogWarn() << "Global Supervision (" << getConfigName() << ") switched to FAILED."; - globalStatus = score::mw::lifecycle::GlobalSupervisionStatus::kFailed; - - startExpired = UINT64_MAX; -} - -void Global::switchToExpired(const timers::NanoSecondType f_starttime) noexcept -{ - logger_r.LogWarn() << "Global Supervision (" << getConfigName() << ") switched to EXPIRED."; - globalStatus = score::mw::lifecycle::GlobalSupervisionStatus::kExpired; - startExpired = f_starttime; -} - -void Global::switchToStopped(EGlobalStoppedReason f_reason) noexcept -{ - switch (f_reason) - { - case EGlobalStoppedReason::expirationTimeout: - logger_r.LogWarn() << "Global Supervision (" << getConfigName() - << ") switched to STOPPED due to expired supervision tolerance."; - break; - case EGlobalStoppedReason::history_buffer_overflow: - logger_r.LogWarn() << "Global Supervision (" << getConfigName() - << ") switched to STOPPED due to history buffer overflow."; - break; - default: - logger_r.LogWarn() << "Global Supervision (" << getConfigName() - << ") switched to STOPPED due to data corruption."; - break; - } - - globalStatus = score::mw::lifecycle::GlobalSupervisionStatus::kStopped; - startExpired = UINT64_MAX; - - for (auto notification : registeredRecoveryNotifications) - { - xaap::lcm::saf::recovery::supervision::SupervisionErrorInfo errorInfo{}; - errorInfo.failedProcessExecutionError = executionError; - - // Should always be true otherwise send recovery information will be wrong - static_assert(static_cast(ICheckpointSupervision::EType::aliveSupervision) == - static_cast(score::lcm::TypeOfSupervision::AliveSupervision), - "ICheckpointSupervision Enum for Alive and score::lcm::TypeOfSupervision Enum for Alive match."); - static_assert( - static_cast(ICheckpointSupervision::EType::deadlineSupervision) == - static_cast(score::lcm::TypeOfSupervision::DeadlineSupervision), - "ICheckpointSupervision Enum for Deadline and score::lcm::TypeOfSupervision Enum for Deadline match."); - static_assert( - static_cast(ICheckpointSupervision::EType::logicalSupervision) == - static_cast(score::lcm::TypeOfSupervision::LogicalSupervision), - "ICheckpointSupervision Enum for Logical and score::lcm::TypeOfSupervision Enum for Logical match."); - - errorInfo.failedSupervisionType = static_cast(expiredSupervision); - // NOTE: failedprocessGroupMetaModelIdentifier is maintained in the Notification class directly! - notification->send(errorInfo); - } -} - -score::mw::lifecycle::LocalSupervisionStatus Global::getAccumulatedState(void) noexcept -{ - // Accumulating the state is done by calculating the maximum enum value. - // This approach is only valid if the enum values are in the expected order: - // - Least critical case => lowest value - // - Highest critical case => highest value - // kDeactivated is an exception to this rule, which is treated differently in the - // calculation of accumulated state below - static_assert(static_cast(score::mw::lifecycle::LocalSupervisionStatus::kOK) == 0U, - "Value of score::lcm::LocalSupervision::kOK is 0 as expected."); - static_assert(static_cast(score::mw::lifecycle::LocalSupervisionStatus::kFailed) == 1U, - "Value of score::lcm::LocalSupervision::kFailed is 1 as expected."); - static_assert(static_cast(score::mw::lifecycle::LocalSupervisionStatus::kExpired) == 2U, - "Value of score::lcm::LocalSupervision::kExpired is 2 as expected."); - static_assert(static_cast(score::mw::lifecycle::LocalSupervisionStatus::kDeactivated) == 4U, - "Value of score::lcm::LocalSupervision::kDeactivated is 4 as expected."); - - // Value of -1 is treated as kDeactivated. Using the underlying integer of kDeactivated would - // mess up the usage of std::max - static constexpr std::int32_t kDeactivatedPlaceholder{-1}; - std::int32_t aggregateState{kDeactivatedPlaceholder}; - - for (const auto& local : localStatusOverTime) - { - // coverity[autosar_cpp14_a8_5_2_violation:FALSE] type auto shall not be initialized with {} AUTOSAR.8.5.3A - const auto localStatus = local.second; - if (localStatus != score::mw::lifecycle::LocalSupervisionStatus::kDeactivated) - { - aggregateState = std::max(static_cast(localStatus), aggregateState); - if (score::mw::lifecycle::LocalSupervisionStatus::kExpired == localStatus) - { - break; // Worst state already reached - } - } - } - - score::mw::lifecycle::LocalSupervisionStatus accState{score::mw::lifecycle::LocalSupervisionStatus::kDeactivated}; - if (aggregateState != kDeactivatedPlaceholder) - { - accState = static_cast(aggregateState); - } - - return accState; -} - -bool Global::isDebounced(timers::NanoSecondType f_time) noexcept -{ - bool retVal{false}; - - // Clock error - if (0U == f_time) - { - f_time = UINT64_MAX; - expiredSupervision = kInternalErrorSupervisionType; - executionError = ifexm::ProcessCfg::kDefaultProcessExecutionError; - } - - if (0U == expiredTolerance) - { - retVal = true; - } - else - { - timers::NanoSecondType toleranceEnd{startExpired + expiredTolerance}; - if (toleranceEnd <= startExpired) - { - // Overflow occurred - toleranceEnd = UINT64_MAX; - } - if (f_time >= toleranceEnd) - { - retVal = true; - } - } - - return retVal; -} - -} // namespace supervision -} // namespace saf -} // namespace lcm -} // namespace score diff --git a/score/launch_manager/daemon/src/alive_monitor/details/supervision/Global.hpp b/score/launch_manager/daemon/src/alive_monitor/details/supervision/Global.hpp deleted file mode 100644 index 31838f55f..000000000 --- a/score/launch_manager/daemon/src/alive_monitor/details/supervision/Global.hpp +++ /dev/null @@ -1,282 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2025 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - - -#ifndef GLOBAL_HPP_INCLUDED -#define GLOBAL_HPP_INCLUDED - -#ifndef PHM_PRIVATE -# define PHM_PRIVATE private -#endif - -#include -#include -#include - -#include - -#include "score/mw/launch_manager/alive_monitor/Monitor.h" -#include "score/mw/launch_manager/alive_monitor/details/common/Observer.hpp" -#include "score/mw/launch_manager/alive_monitor/details/common/TimeSortingBuffer.hpp" -#include "score/mw/launch_manager/alive_monitor/details/common/Types.hpp" -#include "score/mw/launch_manager/alive_monitor/details/logging/PhmLogger.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/ICheckpointSupervision.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/ISupervision.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/Local.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/SupervisionCfg.hpp" -#include "score/mw/launch_manager/alive_monitor/details/timers/Timers_OsClock.hpp" - -namespace score -{ -namespace lcm -{ -namespace saf -{ -namespace ifexm -{ -class ProcessState; -} -namespace recovery -{ -class Notification; -} -namespace supervision -{ -class Local; - -/// @brief Global Supervision -/// @details Global Supervision contains the logic for health monitoring - global supervision -/* RULECHECKER_comment(0, 9, check_source_character_set, "Special character in comment is mandatory\ - due to sphinx-need syntax.", false) */ -/// @verbatim embed:rst:leading-slashes -/// The Local Supervision state machine implementation is influenced by Adaptive Autosar Requirements -/// The detailed state machine is documented here: -/// -/// - :ref:`Global Supervision - State Machine` -/// - :ref:`Global timing diagram for single process group state` -/// - :ref:`Global timing diagram for changed process group state` -/// -/// @endverbatim -/* RULECHECKER_comment(0, 3, check_multiple_non_interface_bases, "Observable and Observer are tolerated\ - exceptions of this rule.", false) */ -class Global : public ISupervision, public common::Observer, public common::Observer -{ -public: - /// @brief No default constructor - Global() = delete; - - /// @brief Move constructors - /* RULECHECKER_comment(0, 7, check_min_instructions, "Default constructor is not provided\ - a function body", true_no_defect) */ - /* RULECHECKER_comment(0, 5, check_incomplete_data_member_construction, "Default constructor is not provided\ - the member initializer", false) */ - /* RULECHECKER_comment(0, 3, check_copy_in_move_constructor, "Default constructor is not provided\ - the member initializer", false) */ - Global(Global&&) noexcept(false) = default; - /// @brief Move assignment is not supported - Global& operator=(Global&&) = delete; - /// @brief Copy constructor is not supported - Global(const Global&) = delete; - /// @brief Copy assignment is not supported - Global& operator=(const Global&) = delete; - - /// @brief Constructor - /// @param [in] f_globalCfg_r Global Supervision configuration structure - /// @warning Constructor may throw std::exceptions - explicit Global(const GlobalSupervisionCfg& f_globalCfg_r) noexcept(false); - - /// @brief Default Destructor - /* RULECHECKER_comment(0, 3, check_min_instructions, "Default destructor is not provided\ - a function body", true_no_defect) */ - ~Global() override = default; - - /// @brief Update data received for process states - /// @details The process state update is used to update the expirationTolerance according - /// to the PG state of the process. The process state update is ignored if it does not - /// have process state init or running. - /// @param [in] f_observable_r Process state object which has sent the update - void updateData(const ifexm::ProcessState& f_observable_r) noexcept(true) override; - - /// @brief Update data received from Local supervisions - /// @param [in] f_observable_r Local Supervision object which has send the update - void updateData(const Local& f_observable_r) noexcept(true) override; - - /// @brief Register a given local supervision object so it can be queried for its state - /// @param [in] f_localSupervision_r Local supervision object - /// @warning register local supervision may throw std::exceptions - void registerLocalSupervision(const Local& f_localSupervision_r) noexcept(false); - - /// @copydoc ISupervision::evaluate() - void evaluate(const timers::NanoSecondType f_syncTimestamp) override; - - /// @brief Get global supervision status - /// @return GlobalSupervisionStatus Current global supervision status - score::mw::lifecycle::GlobalSupervisionStatus getStatus(void) const noexcept; - - /// @brief Register the given recovery notification object - /// @param [in] f_notification_r Recovery notification object - void registerRecoveryNotification(score::lcm::saf::recovery::Notification& f_notification_r); - -PHM_PRIVATE: - /// @brief Local supervision instance identifier - /// Using the address for Local object for lack of a better id - using LocalSupervisionId = const Local*; - - /// @brief Structure for sorting local supervision updates in TimeSortingBuffer - struct TimeSortedLocalSupState - { - /// @brief The identification of the local supervision - // cppcheck-suppress unusedStructMember - LocalSupervisionId localId{nullptr}; - /// @brief New status of a local supervision - score::mw::lifecycle::LocalSupervisionStatus state{score::mw::lifecycle::LocalSupervisionStatus::kDeactivated}; - /// @brief The type of supervision that caused the local supervision state change - ICheckpointSupervision::EType supervisionType{ICheckpointSupervision::EType::aliveSupervision}; - /// @brief Timestamp of the local supervision state change - score::lcm::saf::timers::NanoSecondType timestamp{0U}; - /// @brief The execution error from Local Supervision - ifexm::ProcessCfg::ProcessExecutionError executionError{ifexm::ProcessCfg::kDefaultProcessExecutionError}; - }; - - /// @brief Structure for sorting PG state updates in TimeSortingBuffer - struct TimeSortedPGStateChange - { - /// @brief The expiration tolerance that has been configured for the current PG state - timers::NanoSecondType expiredTolerance{0U}; - /// @brief The timestamp of the PG state change - score::lcm::saf::timers::NanoSecondType timestamp{0U}; - }; - - /// @brief Enumeration of reason for Stopped state in Global supervision - enum class EGlobalStoppedReason : uint8_t - { - expirationTimeout = 0, ///< Expiration timeout has expired - data_corruption = 1, ///< Corrupted state memory - history_buffer_overflow = 2 ///< Overflow of history buffer - }; - - /// @brief Check potential transitions out of state kOK - /// @param [in] f_local_r Local Supervision update - void checkTransitionsOutOfDeactivated(const TimeSortedLocalSupState& f_local_r); - - /// @brief Check potential transitions out of state kOK - /// @param [in] f_local_r Local Supervision update - void checkTransitionsOutOfOk(const TimeSortedLocalSupState& f_local_r); - - /// @brief Check potential transitions out of state kFailed - /// @param [in] f_local_r Local Supervision update - void checkTransitionsOutOfFailed(const TimeSortedLocalSupState& f_local_r); - - /// @brief Check potential transitions out of state kExpired - /// @param [in] f_local_r Local Supervision update - void checkTransitionsOutOfExpired(const TimeSortedLocalSupState& f_local_r); - - /// @brief Check potential transitions out of state kStopped - void checkTransitionsOutOfStopped(); - - /// @brief Switch to state Deactivated - void switchToDeactivated() noexcept; - - /// @brief Switch to state Ok - void switchToOk() noexcept; - - /// @brief Switch to state Failed - void switchToFailed() noexcept; - - /// @brief Switch to state Expired - /// @param[in] f_starttime The timestamp of the event that caused the switch to expired - void switchToExpired(const timers::NanoSecondType f_starttime) noexcept; - - /// @brief Switch to state Stopped - /// @param[in] f_reason The reason for switch to STOPPED - void switchToStopped(EGlobalStoppedReason f_reason) noexcept; - - /// @brief Get accumulated state of registered Local Supervisions - /// @details Calculate the highest 'error' status of all registered Local Supervision - /// order is as following: - /// 0. Deactivated - /// 1. Ok - /// 2. Failed - /// 3. Expired - score::mw::lifecycle::LocalSupervisionStatus getAccumulatedState(void) noexcept; - - /// @brief Check if escalation to Stopped is required - /// @param [in] f_time Current time (0 ns is treated as error value) - bool isDebounced(timers::NanoSecondType f_time) noexcept; - - /// @brief Evaluate local supervision update entry - /// @param[in] f_local_r The updated local supervision state - void evaluateLocalSupervisionUpdate(const TimeSortedLocalSupState& f_local_r); - - /// @brief Update parameters to the new PG state - /// @param[in] f_pgChange The new PG state parameters - void evaluatePGStateChange(const TimeSortedPGStateChange f_pgChange) noexcept; - - /// @brief Process updates from timesortedbuffer one-by-one - void processTimeSortedEvents(); - - /// @brief Expired Supervision Tolerances for Process Group state - /// @details Each element in the vector is the expired supervision tolerance for a specific process group - /// state. The corresponding state is stored in the 'paired' k_refFuntionGroupStates vector. This means if the - /// current Process Group State matches to vector element e.g. 5, k_expiredTolerances.at(5) must be used as - /// debouncing value - const std::vector k_expiredTolerances; - - /// @brief Referenced Process Group States as EXM IDs - /// @details This vector is 'paired' with k_expiredTolerances - const std::vector k_refFuntionGroupStates; - - /// @brief Current global supervision status - score::mw::lifecycle::GlobalSupervisionStatus globalStatus{score::mw::lifecycle::GlobalSupervisionStatus::kDeactivated}; - - /// @brief Start Timestamp of Expired State - timers::NanoSecondType startExpired{UINT64_MAX}; - - /// @brief Expired Tolerance - timers::NanoSecondType expiredTolerance{0U}; - - /// @brief Type of Supervision which caused transition to expired - /// @note Initial value has no special meaning it just needs to be one of the possible supervision types - ICheckpointSupervision::EType expiredSupervision{ICheckpointSupervision::EType::deadlineSupervision}; - - /// @brief The process execution error from the Local supervision that caused the switch to expired - ifexm::ProcessCfg::ProcessExecutionError executionError{ifexm::ProcessCfg::kDefaultProcessExecutionError}; - - /// @brief Map of the current status of all associated supervisions - /// Map is updated in the timestamp-based order of local supervision updates - std::map localStatusOverTime{}; - - /// @brief Vector of registered Recovery Notifications - std::vector registeredRecoveryNotifications{}; - - /// @brief Data loss event marker - bool isDataLossEvent{false}; - - /// @brief Alias for entry type of time sorted buffer for convenience - using TimeSortedElem = std::variant; - - /// @brief Time sorted local supervision state buffer - /// @details The buffer allows to sort multiple local supervision state changes in correct order. - /// This is required when e.g. a process restarts within one daemon cycle - score::lcm::saf::common::TimeSortingBuffer timeSortingLocalSupStateBuffer; - - /// @brief Logger - logging::PhmLogger& logger_r; -}; - -} // namespace supervision -} // namespace saf -} // namespace lcm -} // namespace score - -#endif diff --git a/score/launch_manager/daemon/src/alive_monitor/details/supervision/ICheckpointSupervision.cpp b/score/launch_manager/daemon/src/alive_monitor/details/supervision/ICheckpointSupervision.cpp deleted file mode 100644 index 2bb8fba65..000000000 --- a/score/launch_manager/daemon/src/alive_monitor/details/supervision/ICheckpointSupervision.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2025 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#include "score/mw/launch_manager/alive_monitor/details/supervision/ICheckpointSupervision.hpp" - -#include - -namespace score -{ -namespace lcm -{ -namespace saf -{ -namespace supervision -{ - -ICheckpointSupervision::ICheckpointSupervision(const CheckpointSupervisionCfg& f_supervisionConfig_r) : - ISupervision(f_supervisionConfig_r.cfgName_p), - Observer(), - Observer(), - processExecErrs() -{ - // coverity[autosar_cpp14_m0_1_3_violation:FALSE] process_p is read for creating map of process and execution error - for (const auto* process_p : f_supervisionConfig_r.refProcesses_r) - { - processExecErrs.insert({process_p, ifexm::ProcessCfg::kDefaultProcessExecutionError}); - } -} - -timers::NanoSecondType ICheckpointSupervision::getTimestampOfUpdateEvent( - const TimeSortedUpdateEvent f_updateEvent) noexcept(true) -{ - timers::NanoSecondType timestamp{0U}; - if (std::holds_alternative(f_updateEvent)) - { - timestamp = std::get(f_updateEvent).timestamp; - } - else if (std::holds_alternative(f_updateEvent)) - { - timestamp = std::get(f_updateEvent).timestamp; - } - else - { - assert(std::holds_alternative(f_updateEvent)); - // coverity[cert_exp34_c_violation] SyncSnapshot type is stored also check assert above - // coverity[dereference] SyncSnapshot type is stored also check assert above - timestamp = std::get(f_updateEvent); - } - - return timestamp; -} - -ICheckpointSupervision::EUpdateEventType ICheckpointSupervision::getEventType( - ProcessStateTracker& f_processTracker_r, const TimeSortedUpdateEvent f_updateEvent) noexcept(true) -{ - ICheckpointSupervision::EUpdateEventType currentUpdateType{ICheckpointSupervision::EUpdateEventType::kNoChange}; - - if (std::holds_alternative(f_updateEvent)) - { - const auto processStateSnapshot{std::get(f_updateEvent)}; - const auto processEvent{f_processTracker_r.generateProcessChangeEvent(processStateSnapshot)}; - - setProcessExecutionErrorForProcess(processStateSnapshot.identifier_p, processStateSnapshot.executionError); - - if (processEvent.changeType == ProcessStateTracker::EProcessChangeType::kActivation) - { - currentUpdateType = ICheckpointSupervision::EUpdateEventType::kActivation; - } - else if (processEvent.changeType == ProcessStateTracker::EProcessChangeType::kDeactivation) - { - currentUpdateType = ICheckpointSupervision::EUpdateEventType::kDeactivation; - } - else if (processEvent.changeType == ProcessStateTracker::EProcessChangeType::kRecoveredFromCrash) - { - currentUpdateType = ICheckpointSupervision::EUpdateEventType::kRecoveredFromCrash; - } - else - { - currentUpdateType = ICheckpointSupervision::EUpdateEventType::kNoChange; - } - } - else if (std::holds_alternative(f_updateEvent)) - { - // Address for checkpoint is not known/stored - currentUpdateType = ICheckpointSupervision::EUpdateEventType::kCheckpoint; - } - else - { - assert(std::holds_alternative(f_updateEvent)); - currentUpdateType = ICheckpointSupervision::EUpdateEventType::kSync; - } - - return currentUpdateType; -} - -ifexm::ProcessCfg::ProcessExecutionError ICheckpointSupervision::getProcessExecutionError(void) const noexcept(true) -{ - return lastProcessExecutionError; -} - -ifexm::ProcessCfg::ProcessExecutionError ICheckpointSupervision::getProcessExecutionErrorForProcess( - const ifexm::ProcessState* f_process_p) noexcept(true) -{ - assert(processExecErrs.find(f_process_p) != processExecErrs.end()); - return processExecErrs[f_process_p]; -} - -void ICheckpointSupervision::setProcessExecutionErrorForProcess( - const ifexm::ProcessState* f_process_p, ifexm::ProcessCfg::ProcessExecutionError f_error) noexcept(true) -{ - assert(processExecErrs.find(f_process_p) != processExecErrs.end()); - processExecErrs[f_process_p] = f_error; -} - -} // namespace supervision -} // namespace saf -} // namespace lcm -} // namespace score diff --git a/score/launch_manager/daemon/src/alive_monitor/details/supervision/ICheckpointSupervision.hpp b/score/launch_manager/daemon/src/alive_monitor/details/supervision/ICheckpointSupervision.hpp deleted file mode 100644 index dda8d0e39..000000000 --- a/score/launch_manager/daemon/src/alive_monitor/details/supervision/ICheckpointSupervision.hpp +++ /dev/null @@ -1,203 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2025 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#ifndef ICHECKPOINTSUPERVISION_HPP_INCLUDED -#define ICHECKPOINTSUPERVISION_HPP_INCLUDED - -#include -#include - -#include - -#include "score/mw/launch_manager/alive_monitor/Monitor.h" -#include "score/mw/launch_manager/alive_monitor/details/common/Observer.hpp" -#include "score/mw/launch_manager/alive_monitor/details/ifexm/ProcessState.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/ISupervision.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/ProcessStateTracker.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/SupervisionCfg.hpp" -#include "score/mw/launch_manager/alive_monitor/details/timers/Timers_OsClock.hpp" - -namespace score -{ -namespace lcm -{ -namespace saf -{ -namespace ifexm -{ -class ProcessState; -} -namespace ifappl -{ -class Checkpoint; -} -namespace supervision -{ - -/// @brief Checkpoint based supervision -/// @details Declares the common methods for checkpoint based supervisions. -/// All checkpoint based supervision shall comply to the ICheckpointSupervision interface class. -/* RULECHECKER_comment(0, 3, check_multiple_non_interface_bases, "Here Observer is an interface\ - with a pure virtual function, hence the rule is followed.", false) */ -class ICheckpointSupervision : public ISupervision, - public saf::common::Observer, - public saf::common::Observer -{ -public: - /// @brief No default constructor - ICheckpointSupervision() = delete; - - /// @brief Constructor - /// @param [in] f_supervisionConfig_r Supervision configuration - /// @warning Constructor may throw std::exceptions - explicit ICheckpointSupervision(const CheckpointSupervisionCfg& f_supervisionConfig_r) noexcept(false); - - /// @brief Destructor - /* RULECHECKER_comment(0, 3, check_min_instructions, "Default destructor is not provided\ - a function body", true_no_defect) */ - ~ICheckpointSupervision() override = default; - - /// @brief Status enumeration - /// @details Decouple checkpoint based supervision from direct usage of LocalSupervisionStatus, - /// to allow for variation. - enum class EStatus : uint32_t - { - deactivated = static_cast(score::mw::lifecycle::LocalSupervisionStatus::kDeactivated), - ok = static_cast(score::mw::lifecycle::LocalSupervisionStatus::kOK), - failed = static_cast(score::mw::lifecycle::LocalSupervisionStatus::kFailed), - expired = static_cast(score::mw::lifecycle::LocalSupervisionStatus::kExpired) - }; - - /// @brief Supervision Type Enumeration - enum class EType : std::uint32_t - { - aliveSupervision = 0, - deadlineSupervision = 1, - logicalSupervision = 2 - }; - - /// @brief Update checkpoint data - /// @details Checkpoints are pushed into time sorting buffer. - /// @param [in] f_observable_r Checkpoint object which has sent the update - void updateData(const ifappl::Checkpoint& f_observable_r) noexcept(true) override = 0; - - /// @brief Update data received for process states - /// @details Activation event or deactivation event is inserted into buffer if process state and process group - /// state changed. - /// @param [in] f_observable_r Process state object which has sent the update - void updateData(const ifexm::ProcessState& f_observable_r) noexcept(true) override = 0; - - /// @brief Get Supervision status - /// @return Status of Supervision - virtual EStatus getStatus(void) const noexcept(true) = 0; - - /// @brief Get timestamp of supervision event - /// @return Timestamp of checkpoint supervision event - virtual timers::NanoSecondType getTimestamp(void) const noexcept(true) = 0; - - /// @brief Returns the last process execution error - /// @return process execution error - ifexm::ProcessCfg::ProcessExecutionError getProcessExecutionError(void) const noexcept(true); - -protected: - /// @brief Default Move Constructor - /* RULECHECKER_comment(0, 7, check_min_instructions, "Default constructor is not provided\ - a function body", true_no_defect) */ - /* RULECHECKER_comment(0, 5, check_incomplete_data_member_construction, "Default constructor is not provided\ - the member initializer", false) */ - /* RULECHECKER_comment(0, 3, check_copy_in_move_constructor, "Default constructor is not provided\ - the member initializer", false) */ - ICheckpointSupervision(ICheckpointSupervision&&) = default; - /// @brief No Move Assignment - ICheckpointSupervision& operator=(ICheckpointSupervision&&) = delete; - /// @brief No Copy Constructor - ICheckpointSupervision(const ICheckpointSupervision&) = delete; - /// @brief No Copy Assignment - ICheckpointSupervision& operator=(const ICheckpointSupervision&) = delete; - - /// @brief The pointer is only stored for the identification of a checkpoint observer. It can be further used for - /// accessing const members only. - using CheckpointIdentifier = const score::lcm::saf::ifappl::Checkpoint*; - - /// @brief Time sorted checkpoint snapshot - struct CheckpointSnapshot final - { - /// @brief Checkpoint identifier - // cppcheck-suppress unusedStructMember - CheckpointIdentifier identifier_p{nullptr}; - /// @brief timestamp of checkpoint - timers::NanoSecondType timestamp{UINT64_MAX}; - }; - - /// @brief Sync snapshot stores sync timestamp in the time sorting buffer - using SyncSnapshot = timers::NanoSecondType; - - /// @brief Defines one element of time sorted update event - using TimeSortedUpdateEvent = - std::variant; - - /// @brief Enumeration of supervision update events - enum class EUpdateEventType : std::uint8_t - { - kNoChange = 0U, ///< update event for no change in activation/deactivation - kActivation = 1U, ///< update event for activation of supervision - kDeactivation = 2U, ///< update event for deactivation of supervision - kCheckpoint = 3U, ///< update event for reported checkpoint - kEvaluation = 4U, ///< artificial update event for evaluation of supervision (relevant for Alive only) - kSync = 5U, ///< artificial update event for synchronization (relevant for Alive and Deadline only) - kRecoveredFromCrash = 6U ///< update event for a crashed process which has been successfully restarted - }; - - /// @brief Get timestamp of current update event - /// @param [in] f_updateEvent Sorted update event (e.g, Activation, Deactivation, Checkpoint, ...) from Buffer - /// @return Timestamp of update event - static timers::NanoSecondType getTimestampOfUpdateEvent(const TimeSortedUpdateEvent f_updateEvent) noexcept(true); - - /// @brief Get the type of update event - /// @details Get the type of update event. If it is process event, internal buffer of process tracker is updated - /// with this process event. - /// @param [in] f_processTracker_r Process tracker object - /// @param [in] f_updateEvent Sorted update event (e.g, Activation, Deactivation, Checkpoint, ...) from - /// Buffer - /// @return Type of update event - EUpdateEventType getEventType(ProcessStateTracker& f_processTracker_r, - const TimeSortedUpdateEvent f_updateEvent) noexcept(true); - - /// @brief Get the processExecutionError for a specific process - /// @param[in] f_process_p The process state - /// @return The stored ProcessExecutionError for that process - ifexm::ProcessCfg::ProcessExecutionError getProcessExecutionErrorForProcess( - const ifexm::ProcessState* f_process_p) noexcept(true); - - /// @brief The process execution error that belongs to the last process that caused a supervision failure - ifexm::ProcessCfg::ProcessExecutionError lastProcessExecutionError{ - ifexm::ProcessCfg::kDefaultProcessExecutionError}; - -private: - /// @brief Stores the processExecutionError for a specific process - /// @param[in] f_process_p The process state - /// @param[in] f_error The ProcessExecutionError for the given process state - void setProcessExecutionErrorForProcess(const ifexm::ProcessState* f_process_p, - ifexm::ProcessCfg::ProcessExecutionError f_error) noexcept(true); - - /// @brief Keep track of the process execution error of the involved processes over time - /// @details Map is updated while processing the history buffer - std::map processExecErrs{}; -}; - -} // namespace supervision -} // namespace saf -} // namespace lcm -} // namespace score - -#endif diff --git a/score/launch_manager/daemon/src/alive_monitor/details/supervision/ISupervision.hpp b/score/launch_manager/daemon/src/alive_monitor/details/supervision/ISupervision.hpp index ecaae95a0..197fffd66 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/supervision/ISupervision.hpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/supervision/ISupervision.hpp @@ -32,7 +32,7 @@ namespace supervision /// @brief ISupervision /// @details The Interface Supervision class declares/defines methods, which are common for the different -/// supervision types which are: alive-, deadline-, logical-, local-, global-supervision +/// supervision types which are: alive-, deadline-, logical- class ISupervision { public: diff --git a/score/launch_manager/daemon/src/alive_monitor/details/supervision/Local.cpp b/score/launch_manager/daemon/src/alive_monitor/details/supervision/Local.cpp deleted file mode 100644 index 6096ae4bf..000000000 --- a/score/launch_manager/daemon/src/alive_monitor/details/supervision/Local.cpp +++ /dev/null @@ -1,365 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2025 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#include "score/mw/launch_manager/alive_monitor/details/supervision/Local.hpp" - -#include -#include - -#include "score/mw/launch_manager/alive_monitor/details/logging/PhmLogger.hpp" -#include "score/mw/launch_manager/alive_monitor/details/timers/Timers_OsClock.hpp" - -namespace score -{ -namespace lcm -{ -namespace saf -{ -namespace supervision -{ - -Local::Local(const LocalSupervisionCfg f_localCfg) : - ISupervision(f_localCfg.cfgName_p), - Observer(), - Observable(), - logger_r(logging::PhmLogger::getLogger(logging::PhmLogger::EContext::supervision)), - timeSortingCheckpointSupEvent( - common::TimeSortingBuffer(f_localCfg.checkpointEventBufferSize)) -{ - // Satisfy Misra for minimum number of instructions - static_cast(0); - - assert((localStatus == score::mw::lifecycle::LocalSupervisionStatus::kDeactivated) && - ("Local Supervision must start in deactivated state, see SWS_PHM_00204")); -} - -void Local::registerCheckpointSupervision(ICheckpointSupervision& f_supervision_r) noexcept(false) -{ - // coverity[autosar_cpp14_a8_5_2_violation:FALSE] type auto shall not be initialized with {} AUTOSAR.8.5.3A - const auto pairInsertResult = - registeredSupervisionEvents.insert({&f_supervision_r, ICheckpointSupervision::EStatus::deactivated}); - static_cast(pairInsertResult); - assert((pairInsertResult.second) && "Local supervision: Same checkpoint supervision is registered twice."); -} - -void Local::updateData(const Alive& f_observable_r) noexcept(true) -{ - updateDataGeneralized(f_observable_r, ICheckpointSupervision::EType::aliveSupervision); -} - -// coverity[exn_spec_violation:FALSE] std::length_error is not thrown from push() which uses fixed-size-vector -void Local::updateDataGeneralized(const ICheckpointSupervision& f_observable_r, - const ICheckpointSupervision::EType f_type) noexcept(true) -{ - timers::NanoSecondType timestamp{f_observable_r.getTimestamp()}; - if (!timeSortingCheckpointSupEvent.push( - {&f_observable_r, f_observable_r.getStatus(), f_type, timestamp, f_observable_r.getProcessExecutionError()}, - timestamp)) - { - eventTimestamp = lastSyncTimestamp; - isDataLossEvent = true; - supervisionTypeDataLoss = f_type; - } -} - -void Local::evaluate(const timers::NanoSecondType f_syncTimestamp) -{ - if (isDataLossEvent) - { - handleDataLossReaction(); - lastSyncTimestamp = f_syncTimestamp; - return; - } - - CheckpointSupervisionEvent* sortedCheckpointSupEvents_p{timeSortingCheckpointSupEvent.getNextElement()}; - - while (sortedCheckpointSupEvents_p != nullptr) - { - assert((sortedCheckpointSupEvents_p->timestamp <= f_syncTimestamp) && - "Local supervision: Checkpoint events are reported beyond syncTimestamp."); - assert((registeredSupervisionEvents.find(sortedCheckpointSupEvents_p->checkpointSupervision_p) != - registeredSupervisionEvents.end()) && - "Local supervision: Received checkpoint event from unregistered checkpoint supervision."); - - registeredSupervisionEvents[sortedCheckpointSupEvents_p->checkpointSupervision_p] = - sortedCheckpointSupEvents_p->status; - updateState(*sortedCheckpointSupEvents_p); - - sortedCheckpointSupEvents_p = timeSortingCheckpointSupEvent.getNextElement(); - } - - timeSortingCheckpointSupEvent.clear(); - lastSyncTimestamp = f_syncTimestamp; -} - -void Local::handleDataLossReaction(void) noexcept -{ - if (score::mw::lifecycle::LocalSupervisionStatus::kExpired != localStatus) - { - switchToExpired(supervisionTypeDataLoss, ifexm::ProcessCfg::kDefaultProcessExecutionError, "due to data loss."); - } - isDataLossEvent = false; - timeSortingCheckpointSupEvent.clear(); -} - -score::mw::lifecycle::LocalSupervisionStatus Local::getStatus(void) const noexcept -{ - return localStatus; -} - -ICheckpointSupervision::EType Local::getSupervisionType(void) const noexcept -{ - return supervisionType; -} - -timers::NanoSecondType Local::getTimestamp(void) const noexcept -{ - return eventTimestamp; -} - -void Local::updateState(const CheckpointSupervisionEvent& f_checkpointSupervision_r) noexcept -{ - switch (localStatus) - { - case score::mw::lifecycle::LocalSupervisionStatus::kDeactivated: - { - checkTransitionsOutOfDeactivated(f_checkpointSupervision_r); - break; - } - - case score::mw::lifecycle::LocalSupervisionStatus::kOK: - { - checkTransitionsOutOfOk(f_checkpointSupervision_r); - break; - } - - case score::mw::lifecycle::LocalSupervisionStatus::kFailed: - { - checkTransitionsOutOfFailed(f_checkpointSupervision_r); - break; - } - - case score::mw::lifecycle::LocalSupervisionStatus::kExpired: - { - checkTransitionsOutOfExpired(f_checkpointSupervision_r); - break; - } - - default: - { - eventTimestamp = lastSyncTimestamp; - switchToExpired(f_checkpointSupervision_r.type, ifexm::ProcessCfg::kDefaultProcessExecutionError, - "due to data corruption."); - break; - } - } -} - -void Local::checkTransitionsOutOfDeactivated(const CheckpointSupervisionEvent& f_checkpointSupervision_r) noexcept -{ - if (ICheckpointSupervision::EStatus::ok == f_checkpointSupervision_r.status) - { - eventTimestamp = f_checkpointSupervision_r.timestamp; - switchToOk(f_checkpointSupervision_r.type); - } - else if (ICheckpointSupervision::EStatus::failed == f_checkpointSupervision_r.status) - { - // Only alive supervisions can have status failed - eventTimestamp = f_checkpointSupervision_r.timestamp; - switchToFailed(f_checkpointSupervision_r.type, "due to failed Alive Supervision."); - } - // In case of data loss event, state transition from deactivated to expired is accepted. - else if (ICheckpointSupervision::EStatus::expired == f_checkpointSupervision_r.status) - { - eventTimestamp = f_checkpointSupervision_r.timestamp; - switchToExpired(f_checkpointSupervision_r.type, f_checkpointSupervision_r.processExecutionError); - } - else - { - // Do nothing in case state is neither Ok, Failed, Expired - } -} - -void Local::checkTransitionsOutOfOk(const CheckpointSupervisionEvent& f_checkpointSupervision_r) noexcept -{ - if (ICheckpointSupervision::EStatus::deactivated == f_checkpointSupervision_r.status) - { - if (isAllDeactivated()) - { - eventTimestamp = f_checkpointSupervision_r.timestamp; - switchToDeactivated(f_checkpointSupervision_r.type); - } - } - else if (ICheckpointSupervision::EStatus::failed == f_checkpointSupervision_r.status) - { - // Only alive supervisions can have status failed - eventTimestamp = f_checkpointSupervision_r.timestamp; - switchToFailed(f_checkpointSupervision_r.type, "due to failed Alive Supervision."); - } - else if (ICheckpointSupervision::EStatus::expired == f_checkpointSupervision_r.status) - { - eventTimestamp = f_checkpointSupervision_r.timestamp; - switchToExpired(f_checkpointSupervision_r.type, f_checkpointSupervision_r.processExecutionError); - } - else - { - // Nothing to do, since only the following transitions are possible - // Ok -> Deactivated - // Ok -> Failed - // Ok -> Expired - } -} - -void Local::checkTransitionsOutOfFailed(const CheckpointSupervisionEvent& f_checkpointSupervision_r) noexcept -{ - if (ICheckpointSupervision::EStatus::deactivated == f_checkpointSupervision_r.status) - { - if (isAllDeactivated()) - { - eventTimestamp = f_checkpointSupervision_r.timestamp; - switchToDeactivated(f_checkpointSupervision_r.type); - } - } - else if (ICheckpointSupervision::EStatus::ok == f_checkpointSupervision_r.status) - { - if (!isOneFailed()) - { - // If status is failed no Checkpoint Supervision has reported Expired yet. - // Therefore it is sufficient to check if none of the Checkpoint Supervision is still in state failed. - eventTimestamp = f_checkpointSupervision_r.timestamp; - switchToOk(f_checkpointSupervision_r.type); - } - } - else if (ICheckpointSupervision::EStatus::expired == f_checkpointSupervision_r.status) - { - eventTimestamp = f_checkpointSupervision_r.timestamp; - switchToExpired(f_checkpointSupervision_r.type, f_checkpointSupervision_r.processExecutionError); - } - else - { - // Nothing to do, since only the following transitions are possible - // Failed -> Deactivated - // Failed -> Ok - // Failed -> Expired - } -} - -void Local::checkTransitionsOutOfExpired(const CheckpointSupervisionEvent& f_checkpointSupervision_r) noexcept -{ - // Only transition Expired -> Deactivated is possible - if (ICheckpointSupervision::EStatus::deactivated == f_checkpointSupervision_r.status) - { - if (isAllDeactivated()) - { - eventTimestamp = f_checkpointSupervision_r.timestamp; - switchToDeactivated(f_checkpointSupervision_r.type); - } - } -} - -void Local::switchToDeactivated(ICheckpointSupervision::EType f_type) noexcept -{ - supervisionType = f_type; - logger_r.LogDebug() << "Local Supervision (" << getConfigName() << ") switched to DEACTIVATED."; - localStatus = score::mw::lifecycle::LocalSupervisionStatus::kDeactivated; - pushResultToObservers(); -} - -void Local::switchToOk(ICheckpointSupervision::EType f_type) noexcept -{ - supervisionType = f_type; - logger_r.LogInfo() << "Local Supervision (" << getConfigName() << ") switched to OK."; - localStatus = score::mw::lifecycle::LocalSupervisionStatus::kOK; - pushResultToObservers(); -} - -void Local::switchToFailed(ICheckpointSupervision::EType f_type, std::string_view reason_p) noexcept -{ - supervisionType = f_type; - logger_r.LogWarn() << "Local Supervision (" << getConfigName() << ") switched to FAILED," << reason_p; - localStatus = score::mw::lifecycle::LocalSupervisionStatus::kFailed; - pushResultToObservers(); -} - -void Local::switchToExpired(ICheckpointSupervision::EType f_type, - ifexm::ProcessCfg::ProcessExecutionError f_executionError, std::string_view reason_p) noexcept -{ - supervisionType = f_type; - processExecutionError = f_executionError; - if (reason_p.empty()) - { - if (ICheckpointSupervision::EType::aliveSupervision == f_type) - { - logger_r.LogWarn() << "Local Supervision (" << getConfigName() - << ") switched to EXPIRED, due to expired Alive Supervision."; - } - else if (ICheckpointSupervision::EType::deadlineSupervision == f_type) - { - logger_r.LogWarn() << "Local Supervision (" << getConfigName() - << ") switched to EXPIRED, due to expired Deadline Supervision."; - } - else - { - // It is expected that there are only 3 possible types - // Alive - // Deadline - // Logical - logger_r.LogWarn() << "Local Supervision (" << getConfigName() - << ") switched to EXPIRED, due to expired Logical Supervision."; - } - } - else - { - logger_r.LogWarn() << "Local Supervision (" << getConfigName() << ") switched to EXPIRED," << reason_p; - } - localStatus = score::mw::lifecycle::LocalSupervisionStatus::kExpired; - pushResultToObservers(); -} - -bool Local::isAllDeactivated() const noexcept -{ - bool isAllDeactive{true}; - for (const auto& supervision : registeredSupervisionEvents) - { - if (ICheckpointSupervision::EStatus::deactivated != supervision.second) - { - isAllDeactive = false; - break; - } - } - return isAllDeactive; -} - -bool Local::isOneFailed() const noexcept -{ - bool isOneFailing{false}; - for (const auto& supervision : registeredSupervisionEvents) - { - if (ICheckpointSupervision::EStatus::failed == supervision.second) - { - isOneFailing = true; - break; - } - } - return isOneFailing; -} - -ifexm::ProcessCfg::ProcessExecutionError Local::getProcessExecutionError(void) const noexcept -{ - return processExecutionError; -} - -} // namespace supervision -} // namespace saf -} // namespace lcm -} // namespace score diff --git a/score/launch_manager/daemon/src/alive_monitor/details/supervision/Local.hpp b/score/launch_manager/daemon/src/alive_monitor/details/supervision/Local.hpp deleted file mode 100644 index cb08bd4c1..000000000 --- a/score/launch_manager/daemon/src/alive_monitor/details/supervision/Local.hpp +++ /dev/null @@ -1,235 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2025 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Apache License Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - ********************************************************************************/ - -#ifndef LOCAL_HPP_INCLUDED -#define LOCAL_HPP_INCLUDED - -#ifndef PHM_PRIVATE -# define PHM_PRIVATE private -#endif - -#include -#include - -#include - -#include -#include "score/mw/launch_manager/alive_monitor/Monitor.h" -#include "score/mw/launch_manager/alive_monitor/details/common/Observer.hpp" -#include "score/mw/launch_manager/alive_monitor/details/common/TimeSortingBuffer.hpp" -#include "score/mw/launch_manager/alive_monitor/details/logging/PhmLogger.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/Alive.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/ICheckpointSupervision.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/ISupervision.hpp" -#include "score/mw/launch_manager/alive_monitor/details/supervision/SupervisionCfg.hpp" - -namespace score -{ -namespace lcm -{ -namespace saf -{ -namespace supervision -{ - -/// Time sorted checkpoint supervision event -/// Defines one element of the time sorting checkpoint supervision event buffer -struct CheckpointSupervisionEvent final -{ - /// checkpoint supervision object - // cppcheck-suppress unusedStructMember - const ICheckpointSupervision* checkpointSupervision_p{nullptr}; - /// checkpoint supervision status - ICheckpointSupervision::EStatus status{ICheckpointSupervision::EStatus::deactivated}; - /// supervision type - ICheckpointSupervision::EType type{ICheckpointSupervision::EType::aliveSupervision}; - /// captured timestamp - score::lcm::saf::timers::NanoSecondType timestamp{0U}; - /// captured process execution error if supervision failed - ifexm::ProcessCfg::ProcessExecutionError processExecutionError{ifexm::ProcessCfg::kDefaultProcessExecutionError}; -}; - -/// @brief Local Supervision -/// @details Local Supervision contains the logic for health monitoring - Local supervision -/* RULECHECKER_comment(0, 8, check_source_character_set, "Special character in comment is mandatory\ - due to sphinx-need syntax.", false) */ -/// @verbatim embed:rst:leading-slashes -/// The Local Supervision state machine implementation is influenced by Adaptive Autosar Requirements -/// The detailed state machine is documented here: -/// -/// - :ref:`Local Supervision - State Machine` -/// -/// @endverbatim -/* RULECHECKER_comment(0, 3, check_multiple_non_interface_bases, "Here Observer is an interface\ - with a pure virtual function, hence the rule is followed.", false) */ -class Local : public ISupervision, - public common::Observer, - public common::Observable -{ -public: - /// @brief No Default Constructor - Local() = delete; - - /// @brief Default Move Constructor - /* RULECHECKER_comment(0, 7, check_min_instructions, "Default constructor is not provided\ - a function body", true_no_defect) */ - /* RULECHECKER_comment(0, 5, check_incomplete_data_member_construction, "Default constructor is not provided\ - the member initializer", false) */ - /* RULECHECKER_comment(0, 3, check_copy_in_move_constructor, "Default constructor is not provided\ - the member initializer", false) */ - Local(Local&&) = default; - /// @brief No Move Assignment - Local& operator=(Local&&) = delete; - /// @brief No Copy Constructor - Local(const Local&) = delete; - /// @brief No Copy Assignment - Local& operator=(const Local&) = delete; - - /// @brief Constructor - /// @param [in] f_localCfg Local Supervision configuration structure - /// @warning Constructor may throw std::exceptions - explicit Local(const LocalSupervisionCfg f_localCfg) noexcept(false); - - /// @brief Destructor - /* RULECHECKER_comment(0, 3, check_min_instructions, "Default destructor is not provided\ - a function body", true_no_defect) */ - ~Local() override = default; - - /// @brief Register Checkpoint Supervision - /// @details Register a given Checkpoint Supervision - /// @param [in] f_supervision_r Checkpoint Supervision - void registerCheckpointSupervision(ICheckpointSupervision& f_supervision_r) noexcept(false); - - /// @brief Update data received from Alive supervisions - /// @param [in] f_observable_r Checkpoint Supervision object which has sent the update - void updateData(const Alive& f_observable_r) noexcept(true) override; - - /// @copydoc ISupervision::evaluate() - void evaluate(const timers::NanoSecondType f_syncTimestamp) override; - - /// @brief Get local supervision status - /// @return LocalSupervisionStatus Current local supervision status - score::mw::lifecycle::LocalSupervisionStatus getStatus(void) const noexcept; - - /// @brief Get Supervision Type - /// @return Type of Supervision which caused the current state transition - ICheckpointSupervision::EType getSupervisionType(void) const noexcept; - - /// @brief Get timestamp of supervision event - /// @return Timestamp of local supervision event - timers::NanoSecondType getTimestamp(void) const noexcept; - - /// @brief Returns the last process execution error from the failed elementary supervision - /// @return process execution error - ifexm::ProcessCfg::ProcessExecutionError getProcessExecutionError(void) const noexcept; - -PHM_PRIVATE: - /// @brief Update state - /// @param [in] f_checkpointSupervision_r Checkpoint supervision event - void - updateState(const CheckpointSupervisionEvent& f_checkpointSupervision_r) noexcept; - - /// @brief Check and trigger transition out of state Deactivated - /// @param [in] f_checkpointSupervision_r Checkpoint supervision event - void checkTransitionsOutOfDeactivated(const CheckpointSupervisionEvent& f_checkpointSupervision_r) noexcept; - - /// @brief Check and trigger transition out of state Ok - /// @param [in] f_checkpointSupervision_r Checkpoint supervision event - void checkTransitionsOutOfOk(const CheckpointSupervisionEvent& f_checkpointSupervision_r) noexcept; - - /// @brief Check and trigger transition out of state Failed - /// @param [in] f_checkpointSupervision_r Checkpoint supervision event - void checkTransitionsOutOfFailed(const CheckpointSupervisionEvent& f_checkpointSupervision_r) noexcept; - - /// @brief Check and trigger transition out of state Expired - /// @param [in] f_checkpointSupervision_r Checkpoint supervision event - void checkTransitionsOutOfExpired(const CheckpointSupervisionEvent& f_checkpointSupervision_r) noexcept; - - /// @brief Update data received from checkpoint supervisions - /// @param [in] f_observable_r Checkpoint Supervision object which has sent the update - /// @param [in] f_type Type of Supervision - void updateDataGeneralized(const ICheckpointSupervision& f_observable_r, - const ICheckpointSupervision::EType f_type) noexcept(true); - - /// @brief Handle data loss reaction - void handleDataLossReaction(void) noexcept; - - /// @brief Switch to state Deactivated - /// @param [in] f_type Type of Supervision - void switchToDeactivated(const ICheckpointSupervision::EType f_type) noexcept; - - /// @brief Switch to state Ok - /// @param [in] f_type Type of Supervision - void switchToOk(const ICheckpointSupervision::EType f_type) noexcept; - - /// @brief Switch to state Failed - /// @param [in] f_type Type of Supervision - /// @param [in] reason_p Reason for switch to Failed - void switchToFailed(const ICheckpointSupervision::EType f_type, std::string_view reason_p) noexcept; - - /// @brief Switch to state Expired - /// @details In case reason_p was given f_type will be ignored. - /// @param [in] f_type Type of Supervision - /// @param [in] f_executionError The execution error of the supervision that caused the failure - /// @param [in] reason_p [Optional] Other reason for switch to Expired - void switchToExpired(ICheckpointSupervision::EType f_type, - ifexm::ProcessCfg::ProcessExecutionError f_executionError, - std::string_view reason_p = {}) noexcept; - - /// @brief Check if ALL attached Supervisions are in status Deactivated - bool isAllDeactivated() const noexcept; - - /// @brief Check if any attached Supervisions is in status Failed - bool isOneFailed() const noexcept; - - /// @brief Current local supervision status - score::mw::lifecycle::LocalSupervisionStatus localStatus{score::mw::lifecycle::LocalSupervisionStatus::kDeactivated}; - - /// @brief Supervision Type that caused the current state transition - /// @note Initial value has no special meaning it just needs to be one of the possible supervision types - ICheckpointSupervision::EType supervisionType{ICheckpointSupervision::EType::aliveSupervision}; - - /// @brief Data loss event marker - bool isDataLossEvent{false}; - - /// @brief Logger - logging::PhmLogger& logger_r; - - /// @brief Supervision type during data loss event - ICheckpointSupervision::EType supervisionTypeDataLoss{ICheckpointSupervision::EType::aliveSupervision}; - - /// @brief Map of last seen status of all associated checkpoint supervisions - /// @details Map is updated in the timestamp-based order of checkpoint supervision updates - std::map registeredSupervisionEvents{}; - - /// @brief Timestamp in which state change is detected in [nano seconds] - saf::timers::NanoSecondType eventTimestamp{0U}; - - /// @brief Sync timestamp from last evaluation [nano seconds] - /// @details This is required for eventTimestamp in case of data loss - saf::timers::NanoSecondType lastSyncTimestamp{0U}; - - /// @brief Time sorting checkpoint supervision event - /// @details The buffer enables the local supervision to process checkpoint supervision events chronologically - score::lcm::saf::common::TimeSortingBuffer timeSortingCheckpointSupEvent; - - /// @brief The process execution error of the last supervision failure - ifexm::ProcessCfg::ProcessExecutionError processExecutionError{ifexm::ProcessCfg::kDefaultProcessExecutionError}; -}; - -} // namespace supervision -} // namespace saf -} // namespace lcm -} // namespace score - -#endif diff --git a/score/launch_manager/daemon/src/alive_monitor/details/supervision/SupervisionCfg.hpp b/score/launch_manager/daemon/src/alive_monitor/details/supervision/SupervisionCfg.hpp index c0e727295..19571d2e6 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/supervision/SupervisionCfg.hpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/supervision/SupervisionCfg.hpp @@ -14,6 +14,9 @@ #ifndef SUPERVISIONCFG_HPP_INCLUDED #define SUPERVISIONCFG_HPP_INCLUDED +#include + +#include "score/mw/launch_manager/recovery_client/irecovery_client.h" #include "score/mw/launch_manager/alive_monitor/details/common/Types.hpp" #include "score/mw/launch_manager/alive_monitor/details/ifexm/ProcessState.hpp" #include "score/mw/launch_manager/alive_monitor/details/timers/Timers_OsClock.hpp" @@ -38,10 +41,10 @@ namespace supervision /* RULECHECKER_comment(0, 140, check_mixed_non_static_data_member_initialization, "All POD values are initialized\ during declaration, only references are set via constructor.", false) */ -/// Common configuration structure for elementary supervisions -class CheckpointSupervisionCfg +/// Alive Supervision configuration structure +class AliveSupervisionCfg final { -public: + public: /// Unique name set by configuration const char* cfgName_p{nullptr}; /// Number of elements which can be stored in the checkpoint buffer @@ -51,38 +54,6 @@ class CheckpointSupervisionCfg /// Referred Process state objects std::vector& refProcesses_r; - /// Supervision configuration constructor - /// @param [in] f_refStates_r Reference to Process Group State EXM IDs vector - /// @param [in] f_refProcesses_r Reference to Process state vector - explicit CheckpointSupervisionCfg(std::vector& f_refStates_r, - std::vector& f_refProcesses_r) : - cfgName_p(nullptr), - checkpointBufferSize(0U), - refFuntionGroupStates_r(f_refStates_r), - refProcesses_r(f_refProcesses_r) - { - } - - virtual ~CheckpointSupervisionCfg() = default; - -protected: - /// Default copy constructor - /* RULECHECKER_comment(0, 4, check_incomplete_data_member_construction, "All data members are initialized - by default copy constructor.", false) */ - /* RULECHECKER_comment(0, 2, check_unused_parameter, "Parameter is used.", false) */ - CheckpointSupervisionCfg(const CheckpointSupervisionCfg& cfg) = default; - /// No copy assignment operator - CheckpointSupervisionCfg& operator=(const CheckpointSupervisionCfg&) = delete; - /// No move constructor - CheckpointSupervisionCfg(CheckpointSupervisionCfg&&) = delete; - /// No move assignment operator - CheckpointSupervisionCfg& operator=(CheckpointSupervisionCfg&&) = delete; -}; - -/// Alive Supervision configuration structure -class AliveSupervisionCfg final : public CheckpointSupervisionCfg -{ -public: /// (Manifest Parameter) Alive reference cycle in [nano seconds] saf::timers::NanoSecondType aliveReferenceCycle{0U}; /// (Manifest Parameter) Minimum alive indications @@ -98,109 +69,37 @@ class AliveSupervisionCfg final : public CheckpointSupervisionCfg /// Reference to checkpoint object saf::ifappl::Checkpoint& checkpoint_r; + /// Recovery client to invoke when supervision expires + std::shared_ptr recoveryClient{}; + /// Identifier of the supervised process, sent via recovery client when supervision expires + score::lcm::IdentifierHash processIdentifier{}; + + /// Default destructor + ~AliveSupervisionCfg() = default; + /// Alive Supervision configuration constructor /// @param [in] f_checkpoint_r Reference to checkpoint object /// @param [in] f_refStates_r Reference to Process Group State EXM IDs vector /// @param [in] f_refProcesses_r Reference to Process state vector explicit AliveSupervisionCfg(saf::ifappl::Checkpoint& f_checkpoint_r, std::vector& f_refStates_r, - std::vector& f_refProcesses_r) : - CheckpointSupervisionCfg(f_refStates_r, f_refProcesses_r), checkpoint_r(f_checkpoint_r) - { - static_cast(cfgName_p); - } -}; - -/// Deadline Supervision configuration structure -class DeadlineSupervisionCfg final : public CheckpointSupervisionCfg -{ -public: - /// (Manifest Parameter) Minimum Deadline in [nano seconds] - saf::timers::NanoSecondType minDeadline{0U}; - /// (Manifest Parameter) Maximum Deadline in [nano seconds] - saf::timers::NanoSecondType maxDeadline{0U}; - /// Flag for disabled status for minimum deadline check - bool isMinCheckDisabled{false}; - /// Flag for disabled status for maximum deadline check - bool isMaxCheckDisabled{false}; - /// Reference to source checkpoint object - saf::ifappl::Checkpoint& source_r; - /// Reference to target checkpoint object - saf::ifappl::Checkpoint& target_r; - - /// No Default Constructor - DeadlineSupervisionCfg() = delete; - - /// Deadline Supervision configuration constructor - /// @param [in] f_source_r Reference to source checkpoint object - /// @param [in] f_target_r Reference to target checkpoint object - /// @param [in] f_refProcessGroupStates_r Reference to Process Group State EXM IDs vector - /// @param [in] f_refProcesses_r Reference to Process state vector - /* RULECHECKER_comment(0, 5, check_max_parameters, "The 4 parameters are better handled individually instead of \ - further combining under nested data structure", true_no_defect) */ - DeadlineSupervisionCfg(saf::ifappl::Checkpoint& f_source_r, saf::ifappl::Checkpoint& f_target_r, - std::vector& f_refProcessGroupStates_r, - std::vector& f_refProcesses_r) : - CheckpointSupervisionCfg(f_refProcessGroupStates_r, f_refProcesses_r), source_r(f_source_r), target_r(f_target_r) - { - static_cast(cfgName_p); - } -}; - -/// Logical Supervision configuration structure -// coverity[autosar_cpp14_a12_1_6_violation:FALSE] inherited constructors are called -class LogicalSupervisionCfg final : public CheckpointSupervisionCfg -{ -public: - /// No Default Constructor - LogicalSupervisionCfg() = delete; - - /// Logical Supervision configuration constructor - /// @param [in] f_refStates_r Reference to Process Group State EXM IDs vector - /// @param [in] f_refProcesses_r Reference to Process state vector - LogicalSupervisionCfg(std::vector& f_refStates_r, - std::vector& f_refProcesses_r) : - CheckpointSupervisionCfg(f_refStates_r, f_refProcesses_r) + std::vector& f_refProcesses_r) + : refFuntionGroupStates_r(f_refStates_r), refProcesses_r(f_refProcesses_r), checkpoint_r(f_checkpoint_r) { - static_cast(cfgName_p); } -}; - -/// Local Supervision configuration structure -class LocalSupervisionCfg final -{ -public: - /// Unique name set by configuration - const char* cfgName_p{nullptr}; - /// Number of elements which can be stored in the checkpoint event buffer - uint16_t checkpointEventBufferSize{0U}; -}; -/// Global Supervision configuration structure -class GlobalSupervisionCfg final -{ -public: - /// Unique name set by configuration - const char* cfgName_p{nullptr}; - /// Refered Process Group States as EXM IDs - std::vector& refFuntionGroupStates_r; - /// Number of elements which can be stored in the local supervision's event buffer - uint16_t localEventBufferSize{0U}; - /// Expired Supervision Tolerances for Process Group state - std::vector& expiredTolerances_r; - - /// @brief Global Supervision configuration constructor - /// @param [in] f_refStates_r Reference to Process Group State EXM IDs vector (use in combination with - /// f_tolerances_r) - /// @param [in] f_tolerances_r Reference to Expired Supervision Tolerances vector (use in combination wtih - /// f_refStates_r). Tolerance (nano seconds) at e.g. vector position [0] is debounce value for Process Group - /// State[0] - GlobalSupervisionCfg(std::vector& f_refStates_r, - std::vector& f_tolerances_r) : - refFuntionGroupStates_r(f_refStates_r), expiredTolerances_r(f_tolerances_r) - { - static_cast(cfgName_p); - } + protected: + /// Default copy constructor + /* RULECHECKER_comment(0, 4, check_incomplete_data_member_construction, "All data members are initialized + by default copy constructor.", false) */ + /* RULECHECKER_comment(0, 2, check_unused_parameter, "Parameter is used.", false) */ + AliveSupervisionCfg(const AliveSupervisionCfg& cfg) = default; + /// No copy assignment operator + AliveSupervisionCfg& operator=(const AliveSupervisionCfg&) = delete; + /// No move constructor + AliveSupervisionCfg(AliveSupervisionCfg&&) = delete; + /// No move assignment operator + AliveSupervisionCfg& operator=(AliveSupervisionCfg&&) = delete; }; } // namespace supervision diff --git a/score/launch_manager/daemon/src/process_group_manager/details/process_group_manager.cpp b/score/launch_manager/daemon/src/process_group_manager/details/process_group_manager.cpp index 47dec5ddd..8080dd52a 100644 --- a/score/launch_manager/daemon/src/process_group_manager/details/process_group_manager.cpp +++ b/score/launch_manager/daemon/src/process_group_manager/details/process_group_manager.cpp @@ -524,12 +524,12 @@ inline void ProcessGroupManager::recoveryActionHandler() for (auto recovery_request = recovery_client_->getNextRequest(); recovery_request.has_value(); recovery_request = recovery_client_->getNextRequest()) { - auto pg = getProcessGroup(recovery_request->process_group_identifier_); + auto pg = getProcessGroupByProcessId(*recovery_request); if (nullptr == pg) { - LM_LOG_ERROR() << "recoveryActionHandler: Unknown process group " - << recovery_request->process_group_identifier_; + LM_LOG_ERROR() << "recoveryActionHandler: Unknown process " + << *recovery_request; continue; } @@ -538,7 +538,7 @@ inline void ProcessGroupManager::recoveryActionHandler() const GraphState graph_state = pg->getState(); LM_LOG_DEBUG() << "recoveryActionHandler: Processing recovery request for PG " - << recovery_request->process_group_identifier_ << " to state " << recovery_state; + << *recovery_request << " to state " << recovery_state; if (GraphState::kInTransition == graph_state) { @@ -744,6 +744,24 @@ std::shared_ptr ProcessGroupManager::getProcessInfoNode(uint32_ return result; } +std::shared_ptr ProcessGroupManager::getProcessGroupByProcessId(const IdentifierHash& process_id) +{ + for (auto& pg : process_groups_) + { + const IdentifierHash pg_name = pg->getProcessGroupName(); + const uint32_t count = configuration_manager_.getNumberOfOsProcesses(pg_name).value_or(0U); + for (uint32_t idx = 0U; idx < count; ++idx) + { + const auto* proc = configuration_manager_.getOsProcessConfiguration(pg_name, idx).value_or(nullptr); + if (proc != nullptr && proc->process_id_ == process_id) + { + return pg; + } + } + } + return nullptr; +} + std::shared_ptr ProcessGroupManager::getProcessGroup(IdentifierHash pg_name) { /* we could use a map, we could use std::find_if diff --git a/score/launch_manager/daemon/src/process_group_manager/process_group_manager.hpp b/score/launch_manager/daemon/src/process_group_manager/process_group_manager.hpp index 951d2424d..ca5b7a49a 100644 --- a/score/launch_manager/daemon/src/process_group_manager/process_group_manager.hpp +++ b/score/launch_manager/daemon/src/process_group_manager/process_group_manager.hpp @@ -96,6 +96,11 @@ class ProcessGroupManager final /// @return a pointer to the Graph, or nullptr if not found std::shared_ptr getProcessGroup(IdentifierHash pg_name); + /// @brief Get the process group that owns the process with the given identifier + /// @param process_id the process identifier to look up + /// @return a pointer to the Graph, or nullptr if not found + std::shared_ptr getProcessGroupByProcessId(const IdentifierHash& process_id); + /// @brief Get a node corresponding to the given process group and process index /// @param pg_index The index of the process group in the list of groups managed by this manager /// @param process_index The index of the process in the list of processes in the process group diff --git a/score/launch_manager/daemon/src/recovery_client/irecovery_client.h b/score/launch_manager/daemon/src/recovery_client/irecovery_client.h index d78a53014..810fcf278 100644 --- a/score/launch_manager/daemon/src/recovery_client/irecovery_client.h +++ b/score/launch_manager/daemon/src/recovery_client/irecovery_client.h @@ -21,13 +21,6 @@ namespace score namespace lcm { -/// @brief Represents a recovery request for a failed process group. -struct RecoveryRequest -{ - /// @brief The id of the process group the failed process is running in - score::lcm::IdentifierHash process_group_identifier_{}; -}; - /// @brief The RecoveryClient allows the AliveMonitor component to report supervision failures to the /// ProcessGroupManager thus requesting recovery for a specific process group. The requests are queued and periodically /// processed by the ProcessGroupManager. In case the buffer is full and request cannot be queued, the overflow flag is @@ -42,14 +35,14 @@ class IRecoveryClient IRecoveryClient(IRecoveryClient&&) = delete; IRecoveryClient& operator=(IRecoveryClient&&) = delete; - /// @brief Send recovery request for a specific process group. + /// @brief Send recovery request for a specific process. /// @details If the internal buffer is full, the request is discarded and the overflow flag is set. - /// @param process_group_identifier The process group that requires recovery. + /// @param process_identifier The process that requires recovery. /// @return true if the request was queued, false if the buffer was full. - virtual bool sendRecoveryRequest(const score::lcm::IdentifierHash& process_group_identifier) noexcept = 0; + virtual bool sendRecoveryRequest(const score::lcm::IdentifierHash& process_identifier) noexcept = 0; /// @brief Retrieve the latest request from the queue, removing it from the queue /// @return The request, or std::nullopt if no request is available - virtual std::optional getNextRequest() noexcept = 0; + virtual std::optional getNextRequest() noexcept = 0; /// @brief Checks if overflow has been set, by previously calling `sendRecoveryRequest` while the queue was already /// full diff --git a/score/launch_manager/daemon/src/recovery_client/recovery_client.cpp b/score/launch_manager/daemon/src/recovery_client/recovery_client.cpp index 75fb3ba73..bd19dfaa3 100644 --- a/score/launch_manager/daemon/src/recovery_client/recovery_client.cpp +++ b/score/launch_manager/daemon/src/recovery_client/recovery_client.cpp @@ -20,9 +20,8 @@ RecoveryClient::RecoveryClient() noexcept : ringBuffer_{} { ringBuffer_.initialize(); } -bool RecoveryClient::sendRecoveryRequest(const score::lcm::IdentifierHash& process_group_identifier) noexcept { - RecoveryRequest req{process_group_identifier}; - if (!ringBuffer_.tryEnqueue(req)) { +bool RecoveryClient::sendRecoveryRequest(const score::lcm::IdentifierHash& process_identifier) noexcept { + if (!ringBuffer_.tryEnqueue(process_identifier)) { overflow_flag_ = true; return false; } @@ -33,8 +32,8 @@ bool RecoveryClient::hasOverflow() const noexcept { return overflow_flag_.load(); } -std::optional RecoveryClient::getNextRequest() noexcept { - RecoveryRequest req; +std::optional RecoveryClient::getNextRequest() noexcept { + score::lcm::IdentifierHash req; if(ringBuffer_.tryDequeue(req)) { return req; } diff --git a/score/launch_manager/daemon/src/recovery_client/recovery_client.hpp b/score/launch_manager/daemon/src/recovery_client/recovery_client.hpp index 70ab5fa5d..5fed222fc 100644 --- a/score/launch_manager/daemon/src/recovery_client/recovery_client.hpp +++ b/score/launch_manager/daemon/src/recovery_client/recovery_client.hpp @@ -34,12 +34,12 @@ class RecoveryClient final : public IRecoveryClient { RecoveryClient(RecoveryClient&&) = delete; RecoveryClient& operator=(RecoveryClient&&) = delete; - bool sendRecoveryRequest(const score::lcm::IdentifierHash& process_group_identifier) noexcept override; - std::optional getNextRequest() noexcept override; + bool sendRecoveryRequest(const score::lcm::IdentifierHash& process_identifier) noexcept override; + std::optional getNextRequest() noexcept override; bool hasOverflow() const noexcept override; private: - static const std::size_t element_size_ = sizeof(RecoveryRequest); + static const std::size_t element_size_ = sizeof(score::lcm::IdentifierHash); ipc_dropin::RingBuffer ringBuffer_; ///< Ring buffer to store recovery requests std::atomic_bool overflow_flag_{false}; }; diff --git a/score/launch_manager/daemon/src/recovery_client/recovery_client_UT.cpp b/score/launch_manager/daemon/src/recovery_client/recovery_client_UT.cpp index c22f3e1a2..1ee888551 100644 --- a/score/launch_manager/daemon/src/recovery_client/recovery_client_UT.cpp +++ b/score/launch_manager/daemon/src/recovery_client/recovery_client_UT.cpp @@ -33,7 +33,7 @@ TEST_F(RecoveryClientTest, SendSingleRequest) "RecoveryClient can send single request successfully."); RecoveryClient client; - const bool result = client.sendRecoveryRequest(IdentifierHash("pg_a")); + const bool result = client.sendRecoveryRequest(IdentifierHash("proc_a")); EXPECT_TRUE(result); EXPECT_FALSE(client.hasOverflow()); } @@ -44,12 +44,12 @@ TEST_F(RecoveryClientTest, GetNextRequest) "RecoveryClient can send and retrieve single request successfully."); RecoveryClient client; - const IdentifierHash expected_pg("pg_b"); - client.sendRecoveryRequest(expected_pg); + const IdentifierHash expected_proc("proc_b"); + client.sendRecoveryRequest(expected_proc); const auto req = client.getNextRequest(); ASSERT_TRUE(req.has_value()); - EXPECT_EQ(req->process_group_identifier_, expected_pg); + EXPECT_EQ(*req, expected_proc); } TEST_F(RecoveryClientTest, GetNextRequestEmpty) @@ -67,16 +67,16 @@ TEST_F(RecoveryClientTest, RingBufferFull) "RecoveryClient sets overflow flag if buffer is full."); RecoveryClient client; - const IdentifierHash pg("pg_c"); + const IdentifierHash proc("proc_c"); // Fill the ring buffer for (std::size_t i = 0U; i < RecoveryClient::kBufferCapacity; ++i) { - EXPECT_TRUE(client.sendRecoveryRequest(pg)); + EXPECT_TRUE(client.sendRecoveryRequest(proc)); } // One more should fail and set overflow - EXPECT_FALSE(client.sendRecoveryRequest(pg)); + EXPECT_FALSE(client.sendRecoveryRequest(proc)); EXPECT_TRUE(client.hasOverflow()); } @@ -86,25 +86,25 @@ TEST_F(RecoveryClientTest, FIFOOrdering) "RecoveryClient maintains the order of inserted requests"); RecoveryClient client; - const IdentifierHash pg_first("pg_first"); - const IdentifierHash pg_second("pg_second"); - const IdentifierHash pg_third("pg_third"); + const IdentifierHash proc_first("proc_first"); + const IdentifierHash proc_second("proc_second"); + const IdentifierHash proc_third("proc_third"); - client.sendRecoveryRequest(pg_first); - client.sendRecoveryRequest(pg_second); - client.sendRecoveryRequest(pg_third); + client.sendRecoveryRequest(proc_first); + client.sendRecoveryRequest(proc_second); + client.sendRecoveryRequest(proc_third); const auto req1 = client.getNextRequest(); ASSERT_TRUE(req1.has_value()); - EXPECT_EQ(req1->process_group_identifier_, pg_first); + EXPECT_EQ(req1.value(), proc_first); const auto req2 = client.getNextRequest(); ASSERT_TRUE(req2.has_value()); - EXPECT_EQ(req2->process_group_identifier_, pg_second); + EXPECT_EQ(req2.value(), proc_second); const auto req3 = client.getNextRequest(); ASSERT_TRUE(req3.has_value()); - EXPECT_EQ(req3->process_group_identifier_, pg_third); + EXPECT_EQ(req3.value(), proc_third); EXPECT_FALSE(client.getNextRequest().has_value()); } diff --git a/scripts/config_mapping/lifecycle_config.py b/scripts/config_mapping/lifecycle_config.py index 33b86b081..6fd4c4785 100644 --- a/scripts/config_mapping/lifecycle_config.py +++ b/scripts/config_mapping/lifecycle_config.py @@ -219,7 +219,7 @@ def get_all_refProcessGroupStates(run_targets): return refProcessGroupStates HM_SCHEMA_VERSION_MAJOR = 8 - HM_SCHEMA_VERSION_MINOR = 0 + HM_SCHEMA_VERSION_MINOR = 1 hm_config = {} hm_config["versionMajor"] = HM_SCHEMA_VERSION_MAJOR hm_config["versionMinor"] = HM_SCHEMA_VERSION_MINOR @@ -227,9 +227,6 @@ def get_all_refProcessGroupStates(run_targets): hm_config["hmMonitorInterface"] = [] hm_config["hmSupervisionCheckpoint"] = [] hm_config["hmAliveSupervision"] = [] - hm_config["hmLocalSupervision"] = [] - hm_config["hmGlobalSupervision"] = [] - hm_config["hmRecoveryNotification"] = [] index = 0 for component_name, component_config in config["components"].items(): if is_supervised( @@ -300,14 +297,6 @@ def get_all_refProcessGroupStates(run_targets): ) hm_config["hmAliveSupervision"].append(alive_supervision) - local_supervision = {} - local_supervision["ruleContextKey"] = component_name + "_local_supervision" - local_supervision["infoRefInterfacePath"] = "" - local_supervision["hmRefAliveSupervision"] = [ - {"refAliveSupervisionIdx": index} - ] - hm_config["hmLocalSupervision"].append(local_supervision) - with open( f"{output_dir}/hmproc_{component_name}.json", "w" ) as process_file: @@ -321,32 +310,6 @@ def get_all_refProcessGroupStates(run_targets): index += 1 - indices = [i for i in range(index)] - if len(indices) > 0: - # Create one global supervision & recovery action for all processes. - global_supervision = {} - global_supervision["ruleContextKey"] = "global_supervision" - global_supervision["isSeverityCritical"] = False - global_supervision["localSupervision"] = [ - {"refLocalSupervisionIndex": idx} for idx in indices - ] - global_supervision["refProcesses"] = [{"index": idx} for idx in indices] - global_supervision["refProcessGroupStates"] = get_all_refProcessGroupStates( - config["run_targets"] - ) - hm_config["hmGlobalSupervision"].append(global_supervision) - - recovery_action = {} - recovery_action["shortName"] = f"recovery_notification" - recovery_action["processGroupMetaModelIdentifier"] = ( - get_recovery_process_group_state(config) - ) - recovery_action["refGlobalSupervisionIndex"] = hm_config[ - "hmGlobalSupervision" - ].index(global_supervision) - recovery_action["shouldFireWatchdog"] = False - hm_config["hmRecoveryNotification"].append(recovery_action) - with open(f"{output_dir}/hm_demo.json", "w") as hm_file: json.dump(hm_config, hm_file, indent=4) diff --git a/scripts/config_mapping/tests/basic_test/expected_output/hm_demo.json b/scripts/config_mapping/tests/basic_test/expected_output/hm_demo.json index e020055dd..d49bc87ad 100644 --- a/scripts/config_mapping/tests/basic_test/expected_output/hm_demo.json +++ b/scripts/config_mapping/tests/basic_test/expected_output/hm_demo.json @@ -1,6 +1,6 @@ { "versionMajor": 8, - "versionMinor": 0, + "versionMinor": 1, "process": [ { "index": 0, @@ -197,81 +197,5 @@ } ] } - ], - "hmLocalSupervision": [ - { - "ruleContextKey": "someip-daemon_local_supervision", - "infoRefInterfacePath": "", - "hmRefAliveSupervision": [ - { - "refAliveSupervisionIdx": 0 - } - ] - }, - { - "ruleContextKey": "test_app1_local_supervision", - "infoRefInterfacePath": "", - "hmRefAliveSupervision": [ - { - "refAliveSupervisionIdx": 1 - } - ] - }, - { - "ruleContextKey": "state_manager_local_supervision", - "infoRefInterfacePath": "", - "hmRefAliveSupervision": [ - { - "refAliveSupervisionIdx": 2 - } - ] - } - ], - "hmGlobalSupervision": [ - { - "ruleContextKey": "global_supervision", - "isSeverityCritical": false, - "localSupervision": [ - { - "refLocalSupervisionIndex": 0 - }, - { - "refLocalSupervisionIndex": 1 - }, - { - "refLocalSupervisionIndex": 2 - } - ], - "refProcesses": [ - { - "index": 0 - }, - { - "index": 1 - }, - { - "index": 2 - } - ], - "refProcessGroupStates": [ - { - "identifier": "MainPG/Startup" - }, - { - "identifier": "MainPG/Full" - }, - { - "identifier": "MainPG/fallback_run_target" - } - ] - } - ], - "hmRecoveryNotification": [ - { - "shortName": "recovery_notification", - "processGroupMetaModelIdentifier": "MainPG/fallback_run_target", - "refGlobalSupervisionIndex": 0, - "shouldFireWatchdog": false - } ] } \ No newline at end of file diff --git a/scripts/config_mapping/tests/basic_test/expected_output/hmproc_someip-daemon.json b/scripts/config_mapping/tests/basic_test/expected_output/hmproc_someip-daemon.json index 724551f01..07b6c8189 100644 --- a/scripts/config_mapping/tests/basic_test/expected_output/hmproc_someip-daemon.json +++ b/scripts/config_mapping/tests/basic_test/expected_output/hmproc_someip-daemon.json @@ -1,6 +1,6 @@ { "versionMajor": 8, - "versionMinor": 0, + "versionMinor": 1, "process": [], "hmMonitorInterface": [ { diff --git a/scripts/config_mapping/tests/basic_test/expected_output/hmproc_state_manager.json b/scripts/config_mapping/tests/basic_test/expected_output/hmproc_state_manager.json index dd4dfdfea..ce5e99c2b 100644 --- a/scripts/config_mapping/tests/basic_test/expected_output/hmproc_state_manager.json +++ b/scripts/config_mapping/tests/basic_test/expected_output/hmproc_state_manager.json @@ -1,6 +1,6 @@ { "versionMajor": 8, - "versionMinor": 0, + "versionMinor": 1, "process": [], "hmMonitorInterface": [ { diff --git a/scripts/config_mapping/tests/basic_test/expected_output/hmproc_test_app1.json b/scripts/config_mapping/tests/basic_test/expected_output/hmproc_test_app1.json index 2de629157..15650ff60 100644 --- a/scripts/config_mapping/tests/basic_test/expected_output/hmproc_test_app1.json +++ b/scripts/config_mapping/tests/basic_test/expected_output/hmproc_test_app1.json @@ -1,6 +1,6 @@ { "versionMajor": 8, - "versionMinor": 0, + "versionMinor": 1, "process": [], "hmMonitorInterface": [ { diff --git a/scripts/config_mapping/tests/empty_health_config_test/expected_output/hm_demo.json b/scripts/config_mapping/tests/empty_health_config_test/expected_output/hm_demo.json index 994017456..eccda019d 100644 --- a/scripts/config_mapping/tests/empty_health_config_test/expected_output/hm_demo.json +++ b/scripts/config_mapping/tests/empty_health_config_test/expected_output/hm_demo.json @@ -1,11 +1,8 @@ { "versionMajor": 8, - "versionMinor": 0, + "versionMinor": 1, "process": [], "hmMonitorInterface": [], "hmSupervisionCheckpoint": [], - "hmAliveSupervision": [], - "hmLocalSupervision": [], - "hmGlobalSupervision": [], - "hmRecoveryNotification": [] + "hmAliveSupervision": [] } \ No newline at end of file diff --git a/scripts/config_mapping/tests/empty_lm_config_test/expected_output/hm_demo.json b/scripts/config_mapping/tests/empty_lm_config_test/expected_output/hm_demo.json index 994017456..90a0a9e50 100644 --- a/scripts/config_mapping/tests/empty_lm_config_test/expected_output/hm_demo.json +++ b/scripts/config_mapping/tests/empty_lm_config_test/expected_output/hm_demo.json @@ -4,8 +4,5 @@ "process": [], "hmMonitorInterface": [], "hmSupervisionCheckpoint": [], - "hmAliveSupervision": [], - "hmLocalSupervision": [], - "hmGlobalSupervision": [], - "hmRecoveryNotification": [] + "hmAliveSupervision": [] } \ No newline at end of file diff --git a/scripts/config_mapping/tests/health_config_test/expected_output/hm_demo.json b/scripts/config_mapping/tests/health_config_test/expected_output/hm_demo.json index aed114c59..e5dc41e98 100644 --- a/scripts/config_mapping/tests/health_config_test/expected_output/hm_demo.json +++ b/scripts/config_mapping/tests/health_config_test/expected_output/hm_demo.json @@ -1,6 +1,6 @@ { "versionMajor": 8, - "versionMinor": 0, + "versionMinor": 1, "process": [ { "index": 0, @@ -197,81 +197,5 @@ } ] } - ], - "hmLocalSupervision": [ - { - "ruleContextKey": "state_manager_local_supervision", - "infoRefInterfacePath": "", - "hmRefAliveSupervision": [ - { - "refAliveSupervisionIdx": 0 - } - ] - }, - { - "ruleContextKey": "reporting_supervised_component_local_supervision", - "infoRefInterfacePath": "", - "hmRefAliveSupervision": [ - { - "refAliveSupervisionIdx": 1 - } - ] - }, - { - "ruleContextKey": "reporting_supervised_component_with_no_max_indications_local_supervision", - "infoRefInterfacePath": "", - "hmRefAliveSupervision": [ - { - "refAliveSupervisionIdx": 2 - } - ] - } - ], - "hmGlobalSupervision": [ - { - "ruleContextKey": "global_supervision", - "isSeverityCritical": false, - "localSupervision": [ - { - "refLocalSupervisionIndex": 0 - }, - { - "refLocalSupervisionIndex": 1 - }, - { - "refLocalSupervisionIndex": 2 - } - ], - "refProcesses": [ - { - "index": 0 - }, - { - "index": 1 - }, - { - "index": 2 - } - ], - "refProcessGroupStates": [ - { - "identifier": "MainPG/Startup" - }, - { - "identifier": "MainPG/Full" - }, - { - "identifier": "MainPG/fallback_run_target" - } - ] - } - ], - "hmRecoveryNotification": [ - { - "shortName": "recovery_notification", - "processGroupMetaModelIdentifier": "MainPG/fallback_run_target", - "refGlobalSupervisionIndex": 0, - "shouldFireWatchdog": false - } ] } \ No newline at end of file diff --git a/scripts/config_mapping/tests/health_config_test/expected_output/hmproc_reporting_supervised_component.json b/scripts/config_mapping/tests/health_config_test/expected_output/hmproc_reporting_supervised_component.json index f77030dd7..68f9a033f 100644 --- a/scripts/config_mapping/tests/health_config_test/expected_output/hmproc_reporting_supervised_component.json +++ b/scripts/config_mapping/tests/health_config_test/expected_output/hmproc_reporting_supervised_component.json @@ -1,6 +1,6 @@ { "versionMajor": 8, - "versionMinor": 0, + "versionMinor": 1, "process": [], "hmMonitorInterface": [ { diff --git a/scripts/config_mapping/tests/health_config_test/expected_output/hmproc_reporting_supervised_component_with_no_max_indications.json b/scripts/config_mapping/tests/health_config_test/expected_output/hmproc_reporting_supervised_component_with_no_max_indications.json index 3846498cd..041d23118 100644 --- a/scripts/config_mapping/tests/health_config_test/expected_output/hmproc_reporting_supervised_component_with_no_max_indications.json +++ b/scripts/config_mapping/tests/health_config_test/expected_output/hmproc_reporting_supervised_component_with_no_max_indications.json @@ -1,6 +1,6 @@ { "versionMajor": 8, - "versionMinor": 0, + "versionMinor": 1, "process": [], "hmMonitorInterface": [ { diff --git a/scripts/config_mapping/tests/health_config_test/expected_output/hmproc_state_manager.json b/scripts/config_mapping/tests/health_config_test/expected_output/hmproc_state_manager.json index fb4d46dd4..87aa2c5b1 100644 --- a/scripts/config_mapping/tests/health_config_test/expected_output/hmproc_state_manager.json +++ b/scripts/config_mapping/tests/health_config_test/expected_output/hmproc_state_manager.json @@ -1,6 +1,6 @@ { "versionMajor": 8, - "versionMinor": 0, + "versionMinor": 1, "process": [], "hmMonitorInterface": [ { diff --git a/scripts/config_mapping/tests/lm_config_test/expected_output/hm_demo.json b/scripts/config_mapping/tests/lm_config_test/expected_output/hm_demo.json index 652a2d2db..a344b3a23 100644 --- a/scripts/config_mapping/tests/lm_config_test/expected_output/hm_demo.json +++ b/scripts/config_mapping/tests/lm_config_test/expected_output/hm_demo.json @@ -260,96 +260,5 @@ } ] } - ], - "hmLocalSupervision": [ - { - "ruleContextKey": "test_app2_local_supervision", - "infoRefInterfacePath": "", - "hmRefAliveSupervision": [ - { - "refAliveSupervisionIdx": 0 - } - ] - }, - { - "ruleContextKey": "someip-daemon_local_supervision", - "infoRefInterfacePath": "", - "hmRefAliveSupervision": [ - { - "refAliveSupervisionIdx": 1 - } - ] - }, - { - "ruleContextKey": "test_app1_local_supervision", - "infoRefInterfacePath": "", - "hmRefAliveSupervision": [ - { - "refAliveSupervisionIdx": 2 - } - ] - }, - { - "ruleContextKey": "state_manager_local_supervision", - "infoRefInterfacePath": "", - "hmRefAliveSupervision": [ - { - "refAliveSupervisionIdx": 3 - } - ] - } - ], - "hmGlobalSupervision": [ - { - "ruleContextKey": "global_supervision", - "isSeverityCritical": false, - "localSupervision": [ - { - "refLocalSupervisionIndex": 0 - }, - { - "refLocalSupervisionIndex": 1 - }, - { - "refLocalSupervisionIndex": 2 - }, - { - "refLocalSupervisionIndex": 3 - } - ], - "refProcesses": [ - { - "index": 0 - }, - { - "index": 1 - }, - { - "index": 2 - }, - { - "index": 3 - } - ], - "refProcessGroupStates": [ - { - "identifier": "MainPG/Startup" - }, - { - "identifier": "MainPG/Full" - }, - { - "identifier": "MainPG/fallback_run_target" - } - ] - } - ], - "hmRecoveryNotification": [ - { - "shortName": "recovery_notification", - "processGroupMetaModelIdentifier": "MainPG/fallback_run_target", - "refGlobalSupervisionIndex": 0, - "shouldFireWatchdog": false - } ] } \ No newline at end of file From bd14523d6fccf4ed0e169a0f83e576cb60418709 Mon Sep 17 00:00:00 2001 From: William Roebuck <244554584+WilliamRoebuck@users.noreply.github.com> Date: Tue, 2 Jun 2026 09:42:17 +0100 Subject: [PATCH 2/6] Add MonitorIfDaemon tests --- .../src/alive_monitor/details/ifappl/BUILD | 11 + .../details/ifappl/MonitorIfDaemon_UT.cpp | 449 ++++++++++++++++++ 2 files changed, 460 insertions(+) create mode 100644 score/launch_manager/daemon/src/alive_monitor/details/ifappl/MonitorIfDaemon_UT.cpp diff --git a/score/launch_manager/daemon/src/alive_monitor/details/ifappl/BUILD b/score/launch_manager/daemon/src/alive_monitor/details/ifappl/BUILD index a192b033c..a74946711 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/ifappl/BUILD +++ b/score/launch_manager/daemon/src/alive_monitor/details/ifappl/BUILD @@ -53,3 +53,14 @@ cc_library( "//score/launch_manager/daemon/src/alive_monitor/details/timers:timers_os_clock", ], ) + +cc_test( + name = "MonitorIfDaemon_UT", + srcs = [ + "MonitorIfDaemon_UT.cpp", + ], + deps = [ + ":monitor_if_daemon", + "@googletest//:gtest_main", + ], +) diff --git a/score/launch_manager/daemon/src/alive_monitor/details/ifappl/MonitorIfDaemon_UT.cpp b/score/launch_manager/daemon/src/alive_monitor/details/ifappl/MonitorIfDaemon_UT.cpp new file mode 100644 index 000000000..554bcbc5b --- /dev/null +++ b/score/launch_manager/daemon/src/alive_monitor/details/ifappl/MonitorIfDaemon_UT.cpp @@ -0,0 +1,449 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include +#include + +#include +#include + +#include "score/mw/launch_manager/alive_monitor/details/ifappl/Checkpoint.hpp" +#include "score/mw/launch_manager/alive_monitor/details/ifappl/DataStructures.hpp" +#include "score/mw/launch_manager/alive_monitor/details/ifappl/MonitorIfDaemon.hpp" +#include "score/mw/launch_manager/alive_monitor/details/ifexm/ProcessCfg.hpp" +#include "score/mw/launch_manager/alive_monitor/details/ifexm/ProcessState.hpp" + +using namespace testing; + +namespace score::lcm::saf +{ + +namespace +{ + +/// Counter used to generate unique POSIX shared-memory names across tests. +std::atomic g_ipcCounter{0}; + +std::string makeUniqueIpcName() +{ + // The ipc_dropin::Socket prepends '/' when the name doesn't start with it. + return "test_monifd_ipc_" + std::to_string(g_ipcCounter.fetch_add(1)); +} + +class CheckpointMock : public common::Observer +{ + public: + MOCK_METHOD(void, updateData, (const ifappl::Checkpoint&), (noexcept)); +}; + +struct MonitorIfDaemonFixture +{ + static constexpr std::string_view kProcessName = "test_proc"; + static constexpr std::string_view kCheckpointName = "test_cp"; + static constexpr uint32_t kCheckpointId = 1U; + static constexpr common::ProcessId kProcessId = 42U; + static constexpr std::string_view kInterfaceName = "test_interface"; + + ifexm::ProcessState processState; + ifappl::Checkpoint checkpoint; + ifappl::CheckpointIpcServer ipcServer; + ifappl::MonitorIfDaemon monitor; + CheckpointMock checkpointMock; + + MonitorIfDaemonFixture() + : processState(makeProcessCfg()), + checkpoint(kCheckpointName.data(), kCheckpointId, &processState), + ipcServer{}, + monitor(ipcServer, kInterfaceName.data()) + { + processState.attachObserver(monitor); + monitor.attachCheckpoint(checkpoint); + checkpoint.attachObserver(checkpointMock); + } + + /// Initialize the IPC server so that peek/pop/hasOverflow use real shared memory. + void initIpc() + { + ipcServer.init(makeUniqueIpcName()); + } + + /// Drive the process to the 'running' state and notify observers. + void activateProcess(timers::NanoSecondType ts) + { + processState.setTimestamp(ts); + processState.setState(ifexm::ProcessState::EProcState::running); + processState.pushData(); + } + + /// Drive the process to the 'starting' state and notify observers. + void startProcess(timers::NanoSecondType ts) + { + processState.setTimestamp(ts); + processState.setState(ifexm::ProcessState::EProcState::starting); + processState.pushData(); + } + + /// Drive the process to the 'off' state and notify observers. + void deactivateProcess(timers::NanoSecondType ts) + { + processState.setTimestamp(ts); + processState.setState(ifexm::ProcessState::EProcState::off); + processState.pushData(); + } + + /// Write a single checkpoint element into the IPC ring buffer. + void sendCheckpoint(uint32_t id, timers::NanoSecondType ts) + { + ipcServer.sendEmplace(ts, id); + } + + /// Fill the IPC ring buffer past its capacity to set the overflow flag. + void fillIpcBufferToTriggerOverflow() + { + // Sending one element beyond capacity sets the ring-buffer overflow flag. + for (uint32_t i = 0U; i <= ifappl::k_maxCheckpointBufferElements; ++i) + { + ipcServer.sendEmplace(static_cast(i), 0U); + } + } + + private: + static ifexm::ProcessCfg makeProcessCfg() + { + ifexm::ProcessCfg cfg{}; + cfg.processShortName = kProcessName; + cfg.processId = kProcessId; + return cfg; + } +}; + +} // namespace + +class MonitorIfDaemonTest : public ::testing::Test +{ + private: + timers::NanoSecondType time_ = 0U; + static constexpr timers::NanoSecondType kTimeStep = 100U; + + protected: + void SetUp() override + { + RecordProperty("TestType", "interface-test"); + RecordProperty("DerivationTechnique", "explorative-testing"); + time_ = 0; + } + + public: + /// @brief Clock that increases at fixed intervals with each call + [[nodiscard]] + timers::NanoSecondType mockClock() + { + return time_ += kTimeStep; + } + + /// @brief Increase the time by @c count mockClock() calls + timers::NanoSecondType mockClockSkip(int count) + { + return time_ += (kTimeStep * count); + } + + /// @brief Get the current time plus an offset smaller than the tick size + [[nodiscard]] + timers::NanoSecondType mockClockOffset() const + { + return time_ + 50U; + } + + /// @brief Get the time @c count mockClock() calls from now + [[nodiscard]] + timers::NanoSecondType mockClockFuture(int count) const + { + return time_ + (kTimeStep * count); + } +}; + +TEST_F(MonitorIfDaemonTest, GetInterfaceName_ReturnsNameGivenAtConstruction) +{ + RecordProperty("Description", "Verify that getInterfaceName() returns the string supplied to the constructor."); + + MonitorIfDaemonFixture fix; + EXPECT_EQ(fix.monitor.getInterfaceName(), MonitorIfDaemonFixture::kInterfaceName); +} + +TEST_F(MonitorIfDaemonTest, InitiallyInactive_CheckForNewData_DoesNotNotifyCheckpoint) +{ + RecordProperty("Description", + "Before any process-state update the monitor is kInactive; " + "checkForNewData must not forward any data."); + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(Exactly(0)); + fix.monitor.checkForNewData(mockClock()); +} + +TEST_F(MonitorIfDaemonTest, ProcessOffBeforeActivation_RemainsInactive) +{ + RecordProperty("Description", + "A process-off event before the monitor has been activated " + "must not cause checkForNewData to read IPC data."); + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(Exactly(0)); + fix.initIpc(); + fix.deactivateProcess(mockClock()); + fix.monitor.checkForNewData(mockClock()); + + fix.sendCheckpoint(MonitorIfDaemonFixture::kCheckpointId, mockClockOffset()); + fix.monitor.checkForNewData(mockClock()); +} + +TEST_F(MonitorIfDaemonTest, ProcessRunning_ActivatesMonitorOnNextCheckForNewData) +{ + RecordProperty("Description", + "A running process-state update must set isActivateRequest so that " + "the next checkForNewData transitions the monitor to kActive."); + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(1); + fix.initIpc(); + fix.activateProcess(mockClock()); + const auto checkpoint_time = mockClockOffset(); + fix.sendCheckpoint(MonitorIfDaemonFixture::kCheckpointId, checkpoint_time); + fix.monitor.checkForNewData(mockClock()); // activates AND reads in the same call + + EXPECT_EQ(fix.checkpoint.getTimestamp(), checkpoint_time); +} + +TEST_F(MonitorIfDaemonTest, ProcessStarting_AlsoActivatesMonitor) +{ + RecordProperty("Description", + "EProcState::starting must be treated as an activation trigger, " + "identical to running."); + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(1); + fix.initIpc(); + fix.startProcess(mockClock()); + const auto checkpoint_time = mockClockOffset(); + fix.sendCheckpoint(MonitorIfDaemonFixture::kCheckpointId, checkpoint_time); + fix.monitor.checkForNewData(mockClock()); + + EXPECT_EQ(fix.checkpoint.getTimestamp(), checkpoint_time); +} + +TEST_F(MonitorIfDaemonTest, ProcessOff_DeactivatesMonitor_NoFurtherDataForwarded) +{ + RecordProperty("Description", + "After a process-off event checkForNewData drains the IPC for the " + "current cycle, then transitions to kInactive. Subsequent cycles " + "must not forward data even when the IPC buffer is non-empty."); + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(Exactly(0)); + fix.initIpc(); + fix.activateProcess(mockClock()); + fix.monitor.checkForNewData(mockClock()); // now kActive + + fix.deactivateProcess(mockClock()); + fix.monitor.checkForNewData(mockClock()); // reads remaining data, then -> kInactive + + // Data written AFTER the deactivation cycle must not reach the checkpoint. + fix.sendCheckpoint(MonitorIfDaemonFixture::kCheckpointId, mockClockOffset()); + fix.monitor.checkForNewData(mockClock()); // kInactive, nothing read +} + +TEST_F(MonitorIfDaemonTest, Active_CheckpointDataForwarded) +{ + RecordProperty("Description", + "When active, an IPC element whose timestamp is within the current " + "sync window must be forwarded to the matching checkpoint observer."); + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(1); + fix.initIpc(); + fix.activateProcess(mockClock()); + const auto checkpoint_time = mockClock(); + fix.sendCheckpoint(MonitorIfDaemonFixture::kCheckpointId, checkpoint_time); + fix.monitor.checkForNewData(mockClock()); + + EXPECT_EQ(fix.checkpoint.getTimestamp(), checkpoint_time); +} + +TEST_F(MonitorIfDaemonTest, Active_FutureTimestamp_NotForwardedInCurrentCycle) +{ + RecordProperty("Description", + "An IPC element whose timestamp exceeds the syncTimestamp must be " + "left in the buffer and not forwarded during that cycle."); + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(Exactly(0)); + fix.initIpc(); + fix.activateProcess(mockClock()); + fix.sendCheckpoint(MonitorIfDaemonFixture::kCheckpointId, mockClockFuture(5)); + fix.monitor.checkForNewData(mockClock()); // future checkpoint not consumed +} + +TEST_F(MonitorIfDaemonTest, Active_FutureTimestampCheckpoint_ConsumedInLaterCycle) +{ + RecordProperty("Description", + "An element held back because its timestamp was in the future must " + "be consumed and forwarded when the sync window catches up."); + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(1); + fix.initIpc(); + fix.activateProcess(mockClock()); + const auto future_time = mockClockFuture(2); + fix.sendCheckpoint(MonitorIfDaemonFixture::kCheckpointId, future_time); + fix.monitor.checkForNewData(mockClock()); // not consumed yet + mockClockSkip(2); + fix.monitor.checkForNewData( mockClock()); // now within window -> consumed + EXPECT_EQ(fix.checkpoint.getTimestamp(), future_time); +} + +TEST_F(MonitorIfDaemonTest, Active_NonMatchingCheckpointId_NotForwarded) +{ + RecordProperty("Description", + "An IPC element whose checkpointId does not match any attached " + "Checkpoint must be silently discarded."); + + constexpr uint32_t kNonMatchingId = 99U; + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(Exactly(0)); + fix.initIpc(); + fix.activateProcess(mockClock()); + fix.sendCheckpoint(kNonMatchingId, mockClock()); + fix.monitor.checkForNewData(mockClock()); +} + +TEST_F(MonitorIfDaemonTest, Active_MultipleCheckpointsInOneCycle_AllForwarded) +{ + RecordProperty("Description", + "All IPC elements whose timestamps fall within the sync window must " + "be forwarded in a single checkForNewData call."); + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(3); + fix.initIpc(); + fix.activateProcess(mockClock()); + fix.sendCheckpoint(MonitorIfDaemonFixture::kCheckpointId, mockClock()); + fix.sendCheckpoint(MonitorIfDaemonFixture::kCheckpointId, mockClock()); + fix.sendCheckpoint(MonitorIfDaemonFixture::kCheckpointId, mockClock()); + fix.monitor.checkForNewData(mockClock()); +} + +TEST_F(MonitorIfDaemonTest, Active_TwoAttachedCheckpoints_RoutedByCheckpointId) +{ + RecordProperty("Description", + "When two Checkpoints with different IDs are attached, each IPC " + "element must be forwarded only to the Checkpoint whose ID matches."); + + constexpr uint32_t kCheckpointId2 = 2U; + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(1); + fix.initIpc(); + + ifappl::Checkpoint checkpoint2("test_cp2", kCheckpointId2, &fix.processState); + CheckpointMock mock2; + EXPECT_CALL(mock2, updateData).Times(1); + checkpoint2.attachObserver(mock2); + fix.monitor.attachCheckpoint(checkpoint2); + + fix.activateProcess(mockClock()); + const auto checkpoint_time = mockClock(); + fix.sendCheckpoint(MonitorIfDaemonFixture::kCheckpointId, checkpoint_time); + fix.sendCheckpoint(kCheckpointId2, checkpoint_time); + fix.monitor.checkForNewData(mockClock()); +} + +TEST_F(MonitorIfDaemonTest, Active_OverflowDetected_TransitionsToInactiveOverflow) +{ + RecordProperty("Description", + "When hasOverflow() is true while in kActive, handleOverflow must be " + "called: the checkpoint observer is notified with a data-loss event " + "and the monitor transitions to kInactiveOverflow."); + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(1); // one overflow notification + fix.initIpc(); + fix.activateProcess(mockClock()); + fix.monitor.checkForNewData(mockClock()); // -> kActive + + fix.fillIpcBufferToTriggerOverflow(); + fix.monitor.checkForNewData(mockClock()); // overflow detected -> kInactiveOverflow + + EXPECT_TRUE(fix.checkpoint.getDataLossEvent()); +} + +TEST_F(MonitorIfDaemonTest, InactiveOverflow_NoProcessRestart_DoesNotRepeatNotification) +{ + RecordProperty("Description", + "While in kInactiveOverflow, repeated checkForNewData calls without " + "a process restart must not push additional overflow notifications."); + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(Exactly(1)); + fix.initIpc(); + fix.activateProcess(mockClock()); + fix.monitor.checkForNewData(mockClock()); + fix.fillIpcBufferToTriggerOverflow(); + fix.monitor.checkForNewData(mockClock()); // -> kInactiveOverflow, mock notified once + fix.monitor.checkForNewData(mockClock()); // still kInactiveOverflow, no restart + fix.monitor.checkForNewData(mockClock()); +} + +TEST_F(MonitorIfDaemonTest, InactiveOverflow_ProcessRestarts_PushesOverflowNotificationAgain) +{ + RecordProperty("Description", + "When the supervised process restarts while the monitor is in " + "kInactiveOverflow, the observers must be notified again so that " + "supervisions remain aware the shared memory is still corrupted."); + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(Exactly(2)); + fix.initIpc(); + fix.activateProcess(mockClock()); + fix.monitor.checkForNewData(mockClock()); + fix.fillIpcBufferToTriggerOverflow(); + fix.monitor.checkForNewData(mockClock()); // -> kInactiveOverflow, mock notified once + + // Simulate: process goes off, then comes back. + fix.deactivateProcess(mockClock()); // sets isDeactivateRequest + fix.activateProcess(mockClock()); // isProcessRestarted = true + fix.monitor.checkForNewData(mockClock()); // still kInactiveOverflow -> push again +} + +TEST_F(MonitorIfDaemonTest, InactiveOverflow_ProcessRestartFlag_ClearedAfterNotification) +{ + RecordProperty("Description", + "isProcessRestarted must be cleared after the overflow notification " + "is re-sent, so that a further checkForNewData without a new restart " + "does not produce another notification."); + + MonitorIfDaemonFixture fix; + EXPECT_CALL(fix.checkpointMock, updateData).Times(Exactly(2)); + fix.initIpc(); + fix.activateProcess(mockClock()); + fix.monitor.checkForNewData(mockClock()); + fix.fillIpcBufferToTriggerOverflow(); + fix.monitor.checkForNewData(mockClock()); + + fix.deactivateProcess(mockClock()); + fix.activateProcess(mockClock()); + fix.monitor.checkForNewData(mockClock()); // restart handled, mock notified twice total + + fix.monitor.checkForNewData(mockClock()); // no new restart -> no additional notification +} + +} // namespace score::lcm::saf From b0e73d2ad0a7382319da0e4bf4c747e4fb764832 Mon Sep 17 00:00:00 2001 From: William Roebuck <244554584+WilliamRoebuck@users.noreply.github.com> Date: Tue, 2 Jun 2026 10:08:10 +0100 Subject: [PATCH 3/6] Add error domain UT --- score/launch_manager/BUILD | 11 +++ score/launch_manager/exec_error_domain_UT.cpp | 94 +++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 score/launch_manager/exec_error_domain_UT.cpp diff --git a/score/launch_manager/BUILD b/score/launch_manager/BUILD index 58812f3c1..968840203 100644 --- a/score/launch_manager/BUILD +++ b/score/launch_manager/BUILD @@ -67,3 +67,14 @@ cc_library( "//score/launch_manager/daemon/src/common:identifier_hash", ], ) + +cc_test( + name = "exec_error_domain_UT", + srcs = ["exec_error_domain_UT.cpp"], + visibility = ["//tests:__subpackages__"], + deps = [ + ":error", + "@score_baselibs//score/result", + "@googletest//:gtest_main", + ], +) diff --git a/score/launch_manager/exec_error_domain_UT.cpp b/score/launch_manager/exec_error_domain_UT.cpp new file mode 100644 index 000000000..ead8fdce7 --- /dev/null +++ b/score/launch_manager/exec_error_domain_UT.cpp @@ -0,0 +1,94 @@ +/******************************************************************************** + * Copyright (c) 2025 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +#include + +#include +#include +#include + +#include "score/mw/lifecycle/execution_error.h" + +using namespace testing; +using score::mw::lifecycle::ExecErrc; +using score::mw::lifecycle::g_ExecErrorDomain; + +namespace +{ + +constexpr std::array kAllKnownCodes = { + ExecErrc::kGeneralError, + ExecErrc::kInvalidArguments, + ExecErrc::kCommunicationError, + ExecErrc::kMetaModelError, + ExecErrc::kCancelled, + ExecErrc::kFailed, + ExecErrc::kFailedUnexpectedTerminationOnExit, + ExecErrc::kFailedUnexpectedTerminationOnEnter, + ExecErrc::kInvalidTransition, + ExecErrc::kAlreadyInState, + ExecErrc::kInTransitionToSameState, + ExecErrc::kNoTimeStamp, + ExecErrc::kCycleOverrun, +}; + +} // namespace + +class ExecErrorDomainTest : public ::testing::Test +{ + protected: + void SetUp() override + { + RecordProperty("TestType", "interface-test"); + RecordProperty("DerivationTechnique", "explorative-testing"); + } + + const score::result::ErrorDomain& domain_ = g_ExecErrorDomain; +}; + +TEST_F(ExecErrorDomainTest, AllKnownCodesReturnNonEmptyMessage) +{ + RecordProperty("Description", + "Verify that every known ExecErrc value produces a non-empty message string."); + + for (auto code : kAllKnownCodes) + { + const auto msg = domain_.MessageFor(static_cast(code)); + EXPECT_FALSE(msg.empty()) << "Empty message for ExecErrc(" << static_cast(code) << ")"; + } +} + +TEST_F(ExecErrorDomainTest, AllKnownCodesHaveDistinctMessages) +{ + RecordProperty("Description", + "Verify that every known ExecErrc value maps to a unique message string."); + + std::set seen; + for (auto code : kAllKnownCodes) + { + const auto msg = domain_.MessageFor(static_cast(code)); + EXPECT_TRUE(seen.insert(msg).second) + << "Duplicate message for ExecErrc(" << static_cast(code) << "): " << msg; + } +} + +TEST_F(ExecErrorDomainTest, UnknownCodeReturnsNonEmptyMessage) +{ + RecordProperty("Description", + "Verify that an unrecognised error code falls through to the default case and still returns a " + "non-empty message."); + + constexpr score::result::ErrorCode kUnknownCode = 0; + const auto msg = domain_.MessageFor(kUnknownCode); + EXPECT_FALSE(msg.empty()); +} From 754ae282396ab61c45c31f09b83194d5aedd02af Mon Sep 17 00:00:00 2001 From: William Roebuck <244554584+WilliamRoebuck@users.noreply.github.com> Date: Tue, 2 Jun 2026 11:10:29 +0100 Subject: [PATCH 4/6] Exclude coverage for files to be removed --- .../src/alive_monitor/details/ifexm/ProcessStateReader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/score/launch_manager/daemon/src/alive_monitor/details/ifexm/ProcessStateReader.cpp b/score/launch_manager/daemon/src/alive_monitor/details/ifexm/ProcessStateReader.cpp index b676a8da2..85b17b6d5 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/ifexm/ProcessStateReader.cpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/ifexm/ProcessStateReader.cpp @@ -15,6 +15,8 @@ #include "score/mw/launch_manager/alive_monitor/details/timers/TimeConversion.hpp" +// LCOV_EXCL_START (slated for removal) + namespace score { namespace lcm @@ -160,3 +162,5 @@ constexpr ProcessState::EProcState ProcessStateReader::translateProcessState( } // namespace saf } // namespace lcm } // namespace score + +// LCOV_EXCL_END \ No newline at end of file From dfd0e716a2ca3f9ce8b93ec4ecc0bc32b31fef15 Mon Sep 17 00:00:00 2001 From: William Roebuck <244554584+WilliamRoebuck@users.noreply.github.com> Date: Tue, 2 Jun 2026 13:02:11 +0100 Subject: [PATCH 5/6] format fix --- score/launch_manager/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/score/launch_manager/BUILD b/score/launch_manager/BUILD index 968840203..dde697b7c 100644 --- a/score/launch_manager/BUILD +++ b/score/launch_manager/BUILD @@ -74,7 +74,7 @@ cc_test( visibility = ["//tests:__subpackages__"], deps = [ ":error", - "@score_baselibs//score/result", "@googletest//:gtest_main", + "@score_baselibs//score/result", ], ) From 2aa71143dfbfdd5e0098b0c5d1194a8b980cba89 Mon Sep 17 00:00:00 2001 From: William Roebuck <244554584+WilliamRoebuck@users.noreply.github.com> Date: Tue, 2 Jun 2026 15:21:19 +0100 Subject: [PATCH 6/6] Revert "Exclude coverage for files to be removed" This reverts commit 5d7fd70e860b7a3d46944ebc881fa25035a43cd1. --- .../src/alive_monitor/details/ifexm/ProcessStateReader.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/score/launch_manager/daemon/src/alive_monitor/details/ifexm/ProcessStateReader.cpp b/score/launch_manager/daemon/src/alive_monitor/details/ifexm/ProcessStateReader.cpp index 85b17b6d5..b676a8da2 100644 --- a/score/launch_manager/daemon/src/alive_monitor/details/ifexm/ProcessStateReader.cpp +++ b/score/launch_manager/daemon/src/alive_monitor/details/ifexm/ProcessStateReader.cpp @@ -15,8 +15,6 @@ #include "score/mw/launch_manager/alive_monitor/details/timers/TimeConversion.hpp" -// LCOV_EXCL_START (slated for removal) - namespace score { namespace lcm @@ -162,5 +160,3 @@ constexpr ProcessState::EProcState ProcessStateReader::translateProcessState( } // namespace saf } // namespace lcm } // namespace score - -// LCOV_EXCL_END \ No newline at end of file