From a2fec84d451b74e14e499daeadd318c28b0569fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arkadiusz=20J=C4=99drzejewski?= Date: Mon, 23 Feb 2026 11:12:54 +0100 Subject: [PATCH] hmon: type-safe tags Replace `IdentTag` with type-safe types. --- examples/cpp_supervised_app/main.cpp | 8 +- examples/rust_supervised_app/src/main.rs | 8 +- src/health_monitoring_lib/BUILD | 1 + .../cpp/deadline_monitor.cpp | 12 +- .../cpp/health_monitor.cpp | 12 +- .../cpp/include/score/hm/common.h | 19 - .../score/hm/deadline/deadline_monitor.h | 5 +- .../cpp/include/score/hm/health_monitor.h | 6 +- .../cpp/include/score/hm/tag.h | 54 +++ .../cpp/tests/health_monitor_test.cpp | 28 +- src/health_monitoring_lib/rust/common.rs | 81 +--- .../rust/deadline/deadline_monitor.rs | 146 ++++---- .../rust/deadline/ffi.rs | 115 +++--- src/health_monitoring_lib/rust/ffi.rs | 68 ++-- src/health_monitoring_lib/rust/lib.rs | 92 +++-- src/health_monitoring_lib/rust/log.rs | 2 +- src/health_monitoring_lib/rust/tag.rs | 346 ++++++++++++++++++ src/health_monitoring_lib/rust/worker.rs | 46 +-- 18 files changed, 701 insertions(+), 348 deletions(-) create mode 100644 src/health_monitoring_lib/cpp/include/score/hm/tag.h create mode 100644 src/health_monitoring_lib/rust/tag.rs diff --git a/examples/cpp_supervised_app/main.cpp b/examples/cpp_supervised_app/main.cpp index 345185ca..b9145ef3 100644 --- a/examples/cpp_supervised_app/main.cpp +++ b/examples/cpp_supervised_app/main.cpp @@ -118,14 +118,14 @@ int main(int argc, char** argv) auto builder_mon = deadline::DeadlineMonitorBuilder() - .add_deadline(IdentTag("deadline_1"), + .add_deadline(DeadlineTag("deadline_1"), TimeRange(std::chrono::milliseconds(50), std::chrono::milliseconds(150))) - .add_deadline(IdentTag("deadline_2"), + .add_deadline(DeadlineTag("deadline_2"), TimeRange(std::chrono::milliseconds(2), std::chrono::milliseconds(20))); // Not used, only shows // that multiple deadlines can be added - IdentTag ident("monitor"); + MonitorTag ident("monitor"); { auto hm = HealthMonitorBuilder() @@ -146,7 +146,7 @@ int main(int argc, char** argv) auto deadline_mon = std::move(*deadline_monitor_res); - auto deadline_res = deadline_mon.get_deadline(IdentTag("deadline_1")); + auto deadline_res = deadline_mon.get_deadline(DeadlineTag("deadline_1")); while (!exitRequested) { if (stopReportingCheckpoints.load()) diff --git a/examples/rust_supervised_app/src/main.rs b/examples/rust_supervised_app/src/main.rs index 3da13b31..f418a30c 100644 --- a/examples/rust_supervised_app/src/main.rs +++ b/examples/rust_supervised_app/src/main.rs @@ -57,7 +57,7 @@ fn set_process_name() { fn main_logic(args: &Args, stop: Arc) -> Result<(), Box> { let mut builder = deadline::DeadlineMonitorBuilder::new(); builder = builder.add_deadline( - &IdentTag::from("deadline1"), + DeadlineTag::from("deadline1"), TimeRange::new( std::time::Duration::from_millis(50), std::time::Duration::from_millis(150), @@ -65,13 +65,13 @@ fn main_logic(args: &Args, stop: Arc) -> Result<(), Box) -> Result<(), Box DeadlineMonitor::get_deadline(const IdentTag& tag) +score::cpp::expected DeadlineMonitor::get_deadline(const DeadlineTag& deadline_tag) { auto handle = monitor_handle_.as_rust_handle(); SCORE_LANGUAGE_FUTURECPP_PRECONDITION(handle.has_value()); FFIHandle ret = nullptr; - auto result = deadline_monitor_get_deadline(handle.value(), &tag, &ret); + auto result = deadline_monitor_get_deadline(handle.value(), &deadline_tag, &ret); if (result != kSuccess) { return score::cpp::unexpected(static_cast(result)); diff --git a/src/health_monitoring_lib/cpp/health_monitor.cpp b/src/health_monitoring_lib/cpp/health_monitor.cpp index 2003e0ed..ca4c8b2f 100644 --- a/src/health_monitoring_lib/cpp/health_monitor.cpp +++ b/src/health_monitoring_lib/cpp/health_monitor.cpp @@ -28,10 +28,10 @@ FFICode health_monitor_builder_build(FFIHandle health_monitor_builder_handle, uint32_t internal_cycle_ms, FFIHandle* health_monitor_handle_out); FFICode health_monitor_builder_add_deadline_monitor(FFIHandle health_monitor_builder_handle, - const IdentTag* monitor_tag, + const MonitorTag* monitor_tag, FFIHandle deadline_monitor_builder_handle); FFICode health_monitor_get_deadline_monitor(FFIHandle health_monitor_handle, - const IdentTag* monitor_tag, + const MonitorTag* monitor_tag, FFIHandle* deadline_monitor_handle_out); FFICode health_monitor_start(FFIHandle health_monitor_handle); FFICode health_monitor_destroy(FFIHandle health_monitor_handle); @@ -57,7 +57,7 @@ HealthMonitorBuilder::HealthMonitorBuilder() { } -HealthMonitorBuilder HealthMonitorBuilder::add_deadline_monitor(const IdentTag& tag, +HealthMonitorBuilder HealthMonitorBuilder::add_deadline_monitor(const MonitorTag& monitor_tag, DeadlineMonitorBuilder&& monitor) && { auto monitor_handle = monitor.drop_by_rust(); @@ -65,7 +65,7 @@ HealthMonitorBuilder HealthMonitorBuilder::add_deadline_monitor(const IdentTag& SCORE_LANGUAGE_FUTURECPP_PRECONDITION(health_monitor_builder_handle_.as_rust_handle().has_value()); auto result{health_monitor_builder_add_deadline_monitor( - health_monitor_builder_handle_.as_rust_handle().value(), &tag, monitor_handle.value())}; + health_monitor_builder_handle_.as_rust_handle().value(), &monitor_tag, monitor_handle.value())}; SCORE_LANGUAGE_FUTURECPP_ASSERT(result == kSuccess); return std::move(*this); @@ -110,10 +110,10 @@ HealthMonitor::HealthMonitor(HealthMonitor&& other) other.health_monitor_ = nullptr; } -score::cpp::expected HealthMonitor::get_deadline_monitor(const IdentTag& tag) +score::cpp::expected HealthMonitor::get_deadline_monitor(const MonitorTag& monitor_tag) { FFIHandle handle{nullptr}; - auto result{health_monitor_get_deadline_monitor(health_monitor_, &tag, &handle)}; + auto result{health_monitor_get_deadline_monitor(health_monitor_, &monitor_tag, &handle)}; if (result != kSuccess) { return score::cpp::unexpected(static_cast(result)); diff --git a/src/health_monitoring_lib/cpp/include/score/hm/common.h b/src/health_monitoring_lib/cpp/include/score/hm/common.h index 4a2be954..a826f210 100644 --- a/src/health_monitoring_lib/cpp/include/score/hm/common.h +++ b/src/health_monitoring_lib/cpp/include/score/hm/common.h @@ -15,7 +15,6 @@ #include #include -#include #include namespace score::hm @@ -88,24 +87,6 @@ enum class Error : internal::FFICode Failed }; -/// -/// Identifier tag used to uniquely identify entities within the health monitoring system. -/// -class IdentTag -{ - public: - /// Create a new IdentTag from a C-style string. - template - explicit IdentTag(const char (&tag)[N]) : tag_(tag), len_(N - 1) - { - } - - private: - /// SAFETY: This has to be FFI compatible with the Rust side representation. - const char* const tag_; - size_t len_; -}; - /// /// Time range representation with minimum and maximum durations in milliseconds. /// diff --git a/src/health_monitoring_lib/cpp/include/score/hm/deadline/deadline_monitor.h b/src/health_monitoring_lib/cpp/include/score/hm/deadline/deadline_monitor.h index b46b8b36..b681a200 100644 --- a/src/health_monitoring_lib/cpp/include/score/hm/deadline/deadline_monitor.h +++ b/src/health_monitoring_lib/cpp/include/score/hm/deadline/deadline_monitor.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -47,7 +48,7 @@ class DeadlineMonitorBuilder final : public internal::RustDroppable __drop_by_rust_impl() @@ -75,7 +76,7 @@ class DeadlineMonitor final DeadlineMonitor(DeadlineMonitor&& other) noexcept = default; DeadlineMonitor& operator=(DeadlineMonitor&& other) noexcept = default; - ::score::cpp::expected get_deadline(const IdentTag& tag); + ::score::cpp::expected get_deadline(const DeadlineTag& deadline_tag); private: explicit DeadlineMonitor(internal::FFIHandle handle); diff --git a/src/health_monitoring_lib/cpp/include/score/hm/health_monitor.h b/src/health_monitoring_lib/cpp/include/score/hm/health_monitor.h index efdae573..369cd802 100644 --- a/src/health_monitoring_lib/cpp/include/score/hm/health_monitor.h +++ b/src/health_monitoring_lib/cpp/include/score/hm/health_monitor.h @@ -15,6 +15,7 @@ #include #include +#include namespace score::hm { @@ -38,7 +39,8 @@ class HealthMonitorBuilder final HealthMonitorBuilder& operator=(HealthMonitorBuilder&&) = delete; /// Adds a deadline monitor to the builder to construct DeadlineMonitor instances during HealthMonitor build. - HealthMonitorBuilder add_deadline_monitor(const IdentTag& tag, deadline::DeadlineMonitorBuilder&& monitor) &&; + HealthMonitorBuilder add_deadline_monitor(const MonitorTag& monitor_tag, + deadline::DeadlineMonitorBuilder&& monitor) &&; /// Sets the cycle duration for supervisor API notifications. /// This duration determines how often the health monitor notifies the supervisor that the system is alive. @@ -69,7 +71,7 @@ class HealthMonitor final ~HealthMonitor(); - score::cpp::expected get_deadline_monitor(const IdentTag& tag); + score::cpp::expected get_deadline_monitor(const MonitorTag& monitor_tag); void start(); diff --git a/src/health_monitoring_lib/cpp/include/score/hm/tag.h b/src/health_monitoring_lib/cpp/include/score/hm/tag.h new file mode 100644 index 00000000..5cb47d37 --- /dev/null +++ b/src/health_monitoring_lib/cpp/include/score/hm/tag.h @@ -0,0 +1,54 @@ +/******************************************************************************** + * 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 + ********************************************************************************/ + +#ifndef SCORE_HM_TAG_H +#define SCORE_HM_TAG_H + +#include + +namespace score::hm +{ + +/// Common string-based tag. +class Tag +{ + public: + /// Create a new tag from a C-style string. + template + explicit Tag(const char (&tag)[N]) : data_(tag), length_(N - 1) + { + } + + private: + /// SAFETY: This has to be FFI compatible with the Rust side representation. + const char* const data_; + size_t length_; +}; + +/// Monitor tag. +class MonitorTag : public Tag +{ + public: + using Tag::Tag; +}; + +/// Deadline tag. +class DeadlineTag : public Tag +{ + public: + using Tag::Tag; +}; + +} // namespace score::hm + +#endif // SCORE_HM_TAG_H diff --git a/src/health_monitoring_lib/cpp/tests/health_monitor_test.cpp b/src/health_monitoring_lib/cpp/tests/health_monitor_test.cpp index 568d76d1..d6b6ae28 100644 --- a/src/health_monitoring_lib/cpp/tests/health_monitor_test.cpp +++ b/src/health_monitoring_lib/cpp/tests/health_monitor_test.cpp @@ -12,6 +12,7 @@ ********************************************************************************/ #include "score/hm/health_monitor.h" #include "score/hm/common.h" +#include "score/hm/tag.h" #include #include @@ -24,34 +25,37 @@ class HealthMonitorTest : public ::testing::Test // For first review round, only single test case to show up API TEST_F(HealthMonitorTest, TestName) { - auto builder_mon = deadline::DeadlineMonitorBuilder() - .add_deadline(IdentTag("deadline_1"), - TimeRange(std::chrono::milliseconds(100), std::chrono::milliseconds(200))) - .add_deadline(IdentTag("deadline_2"), - TimeRange(std::chrono::milliseconds(100), std::chrono::milliseconds(200))); - - IdentTag ident("monitor"); + // Setup deadline monitor construction. + const MonitorTag deadline_monitor_tag{"deadline_monitor"}; + auto deadline_monitor_builder = + deadline::DeadlineMonitorBuilder() + .add_deadline(DeadlineTag("deadline_1"), + TimeRange(std::chrono::milliseconds(100), std::chrono::milliseconds(200))) + .add_deadline(DeadlineTag("deadline_2"), + TimeRange(std::chrono::milliseconds(100), std::chrono::milliseconds(200))); auto hm = HealthMonitorBuilder() - .add_deadline_monitor(ident, std::move(builder_mon)) + .add_deadline_monitor(deadline_monitor_tag, std::move(deadline_monitor_builder)) .with_internal_processing_cycle(std::chrono::milliseconds(50)) .with_supervisor_api_cycle(std::chrono::milliseconds(50)) .build(); - auto deadline_monitor_res = hm.get_deadline_monitor(ident); + // Obtain deadline monitor from HMON. + auto deadline_monitor_res = hm.get_deadline_monitor(deadline_monitor_tag); EXPECT_TRUE(deadline_monitor_res.has_value()); { - // Try again to get the same monitor - auto deadline_monitor_res = hm.get_deadline_monitor(ident); + // Try again to get the same monitor. + auto deadline_monitor_res = hm.get_deadline_monitor(deadline_monitor_tag); EXPECT_FALSE(deadline_monitor_res.has_value()); } auto deadline_mon = std::move(*deadline_monitor_res); + // Start HMON. hm.start(); - auto deadline_res = deadline_mon.get_deadline(IdentTag("deadline_1")); + auto deadline_res = deadline_mon.get_deadline(DeadlineTag("deadline_1")); { auto deadline_guard = deadline_res.value().start().value(); diff --git a/src/health_monitoring_lib/rust/common.rs b/src/health_monitoring_lib/rust/common.rs index fa8cd141..35a8ffa5 100644 --- a/src/health_monitoring_lib/rust/common.rs +++ b/src/health_monitoring_lib/rust/common.rs @@ -11,85 +11,12 @@ // SPDX-License-Identifier: Apache-2.0 // ******************************************************************************* -use core::fmt::Debug; +use crate::tag::MonitorTag; use core::hash::Hash; use core::time::Duration; use std::sync::Arc; -/// Unique identifier for deadlines. -#[derive(Clone, Copy, Eq)] -#[repr(C)] -pub struct IdentTag { - data: *const u8, - len: usize, -} // Internal representation as a leaked string slice for now. It can be also an str to u64 conversion. Since this is internal only, we can change it later if needed. - -unsafe impl Send for IdentTag {} -unsafe impl Sync for IdentTag {} - -impl IdentTag { - /// Returns the string representation of the IdentTag. - pub fn new(data: &'static str) -> Self { - Self { - data: data.as_ptr(), - len: data.len(), - } - } -} - -impl Debug for IdentTag { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let bytes = unsafe { core::slice::from_raw_parts(self.data, self.len) }; - let s = unsafe { core::str::from_utf8_unchecked(bytes) }; // Safety: The underlying data was created out of valid str - write!(f, "IdentTag({})", s) - } -} - -// Safety below for `from_raw_parts` -> Data was constructed from valid str -impl Hash for IdentTag { - fn hash(&self, state: &mut H) { - let bytes = unsafe { core::slice::from_raw_parts(self.data, self.len) }; - bytes.hash(state); - } -} -impl PartialEq for IdentTag { - fn eq(&self, other: &Self) -> bool { - let self_bytes = unsafe { core::slice::from_raw_parts(self.data, self.len) }; - let other_bytes = unsafe { core::slice::from_raw_parts(other.data, other.len) }; - self_bytes == other_bytes - } -} - -impl crate::log::ScoreDebug for IdentTag { - fn fmt(&self, f: crate::log::Writer, spec: &crate::log::FormatSpec) -> Result<(), crate::log::Error> { - let bytes = unsafe { core::slice::from_raw_parts(self.data, self.len) }; - crate::log::DebugStruct::new(f, spec, "IdentTag") - .field("data", unsafe { &core::str::from_utf8_unchecked(bytes) }) // Safety: The underlying data was created out of valid str - .finish() - } -} - -impl From for IdentTag { - fn from(value: String) -> Self { - let leaked = value.leak(); - - Self { - data: leaked.as_ptr(), - len: leaked.len(), - } - } -} - -impl From<&str> for IdentTag { - fn from(value: &str) -> Self { - let leaked = value.to_string().leak(); - - Self { - data: leaked.as_ptr(), - len: leaked.len(), - } - } -} +/// Range of accepted time. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct TimeRange { pub min: Duration, @@ -112,7 +39,7 @@ pub(crate) enum MonitorEvaluationError { /// Trait for evaluating monitors and reporting errors to be used by HealthMonitor. pub(crate) trait MonitorEvaluator { - fn evaluate(&self, on_error: &mut dyn FnMut(&IdentTag, MonitorEvaluationError)); + fn evaluate(&self, on_error: &mut dyn FnMut(&MonitorTag, MonitorEvaluationError)); } /// Handle to a monitor evaluator, allowing for dynamic dispatch. @@ -127,7 +54,7 @@ impl MonitorEvalHandle { } impl MonitorEvaluator for MonitorEvalHandle { - fn evaluate(&self, on_error: &mut dyn FnMut(&IdentTag, MonitorEvaluationError)) { + fn evaluate(&self, on_error: &mut dyn FnMut(&MonitorTag, MonitorEvaluationError)) { self.inner.evaluate(on_error) } } diff --git a/src/health_monitoring_lib/rust/deadline/deadline_monitor.rs b/src/health_monitoring_lib/rust/deadline/deadline_monitor.rs index 5565de0f..995b851d 100644 --- a/src/health_monitoring_lib/rust/deadline/deadline_monitor.rs +++ b/src/health_monitoring_lib/rust/deadline/deadline_monitor.rs @@ -11,7 +11,8 @@ // SPDX-License-Identifier: Apache-2.0 // ******************************************************************************* use super::common::DeadlineTemplate; -use crate::common::{IdentTag, MonitorEvalHandle, MonitorEvaluationError, MonitorEvaluator, TimeRange}; +use crate::common::{MonitorEvalHandle, MonitorEvaluationError, MonitorEvaluator, TimeRange}; +use crate::tag::{DeadlineTag, MonitorTag}; use crate::{ deadline::{ common::StateIndex, @@ -45,7 +46,7 @@ pub enum DeadlineError { /// Builder for DeadlineMonitor #[derive(Debug, Default)] pub struct DeadlineMonitorBuilder { - deadlines: HashMap, + deadlines: HashMap, } impl DeadlineMonitorBuilder { @@ -57,20 +58,20 @@ impl DeadlineMonitorBuilder { } /// Adds a deadline with the given tag and duration range to the monitor. - pub fn add_deadline(mut self, tag: &IdentTag, range: TimeRange) -> Self { - self.add_deadline_internal(tag, range); + pub fn add_deadline(mut self, deadline_tag: DeadlineTag, range: TimeRange) -> Self { + self.add_deadline_internal(deadline_tag, range); self } /// Builds the DeadlineMonitor with the configured deadlines. - pub(crate) fn build(self, _allocator: &ProtectedMemoryAllocator) -> DeadlineMonitor { - DeadlineMonitor::new(self.deadlines) + pub(crate) fn build(self, monitor_tag: MonitorTag, _allocator: &ProtectedMemoryAllocator) -> DeadlineMonitor { + DeadlineMonitor::new(monitor_tag, self.deadlines) } // Used by FFI and config parsing code which prefer not to move builder instance - pub(super) fn add_deadline_internal(&mut self, tag: &IdentTag, range: TimeRange) { - self.deadlines.insert(*tag, range); + pub(super) fn add_deadline_internal(&mut self, deadline_tag: DeadlineTag, range: TimeRange) { + self.deadlines.insert(deadline_tag, range); } } @@ -79,24 +80,25 @@ pub struct DeadlineMonitor { } impl DeadlineMonitor { - fn new(deadlines: HashMap) -> Self { + fn new(monitor_tag: MonitorTag, deadlines: HashMap) -> Self { let mut active_deadlines = vec![]; let deadlines = deadlines .into_iter() .enumerate() - .map(|(index, (tag, range))| { - active_deadlines.push((tag, DeadlineState::new())); - (tag, DeadlineTemplate::new(range, StateIndex::new(index))) + .map(|(index, (deadline_tag, range))| { + active_deadlines.push((deadline_tag, DeadlineState::new())); + (deadline_tag, DeadlineTemplate::new(range, StateIndex::new(index))) }) .collect(); Self { #[allow(clippy::arc_with_non_send_sync)] // This will be fixed once we add background thread inner: Arc::new(DeadlineMonitorInner { + monitor_tag, deadlines, active_deadlines: active_deadlines.into(), - start_time: Instant::now(), + monitor_starting_point: Instant::now(), }), } } @@ -106,12 +108,12 @@ impl DeadlineMonitor { /// - Ok(Deadline) - if the deadline was acquired successfully. /// - Err(DeadlineMonitorError::DeadlineInUse) - if the deadline is already in use /// - Err(DeadlineMonitorError::DeadlineNotFound) - if the deadline tag is not registered - pub fn get_deadline(&self, tag: &IdentTag) -> Result { - if let Some(template) = self.inner.deadlines.get(tag) { + pub fn get_deadline(&self, deadline_tag: DeadlineTag) -> Result { + if let Some(template) = self.inner.deadlines.get(&deadline_tag) { match template.acquire_deadline() { Some(range) => Ok(Deadline { range, - tag: *tag, + deadline_tag, monitor: Arc::clone(&self.inner), state_index: template.assigned_state_index, }), @@ -134,7 +136,7 @@ impl DeadlineMonitor { /// Represents a deadline that can be started and stopped. pub struct Deadline { range: TimeRange, - tag: IdentTag, + deadline_tag: DeadlineTag, state_index: StateIndex, monitor: Arc, } @@ -193,7 +195,7 @@ impl Deadline { }); if is_broken { - warn!("Trying to start deadline {:?} that already failed", self.tag); + warn!("Trying to start deadline {:?} that already failed", self.deadline_tag); Err(DeadlineError::DeadlineAlreadyFailed) } else { Ok(()) @@ -213,7 +215,7 @@ impl Deadline { debug_assert!( current.is_running(), "Deadline({:?}) is not running when trying to stop", - self.tag + self.deadline_tag ); let expected = current.timestamp_ms(); @@ -238,10 +240,10 @@ impl Deadline { match possible_err { (Some(MonitorEvaluationError::TooEarly), val) => { - error!("Deadline {:?} stopped too early by {} ms", self.tag, val); + error!("Deadline {:?} stopped too early by {} ms", self.deadline_tag, val); }, (Some(MonitorEvaluationError::TooLate), val) => { - error!("Deadline {:?} stopped too late by {} ms", self.tag, val); + error!("Deadline {:?} stopped too late by {} ms", self.deadline_tag, val); }, (None, _) => {}, } @@ -254,7 +256,7 @@ impl core::fmt::Debug for Deadline { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Deadline") .field("range", &self.range) - .field("tag", &self.tag) + .field("tag", &self.deadline_tag) .field("state_index", &self.state_index) .finish() } @@ -262,54 +264,57 @@ impl core::fmt::Debug for Deadline { impl Drop for Deadline { fn drop(&mut self) { - self.monitor.release_deadline(&self.tag); + self.monitor.release_deadline(self.deadline_tag); } } struct DeadlineMonitorInner { - // Start time of the monitor creation to calculate relative timestamps - start_time: Instant, + /// Tag of this monitor. + monitor_tag: MonitorTag, + + /// Monitor starting point. + monitor_starting_point: Instant, // Templates for deadlines registered in the monitor to create `Deadline` instances. - deadlines: HashMap, + deadlines: HashMap, // This is shared state. Each deadline template has assigned index into this array. // Each deadline instance updates its state (under given index) and the deadline pointing to a state is Single-Producer // On the other side there is background thread evaluating all deadlines states - this is Single-Consumer for each given state. - active_deadlines: Arc<[(IdentTag, DeadlineState)]>, + active_deadlines: Arc<[(DeadlineTag, DeadlineState)]>, } impl MonitorEvaluator for DeadlineMonitorInner { - fn evaluate(&self, on_error: &mut dyn FnMut(&IdentTag, MonitorEvaluationError)) { + fn evaluate(&self, on_error: &mut dyn FnMut(&MonitorTag, MonitorEvaluationError)) { self.evaluate(on_error); } } impl DeadlineMonitorInner { - fn release_deadline(&self, tag: &IdentTag) { - if let Some(template) = self.deadlines.get(tag) { + fn release_deadline(&self, deadline_tag: DeadlineTag) { + if let Some(template) = self.deadlines.get(&deadline_tag) { template.release_deadline(); } else { - unreachable!("Releasing unknown deadline tag: {:?}", tag); + unreachable!("Releasing unknown deadline tag: {:?}", deadline_tag); } } fn now(&self) -> u32 { - let duration = self.start_time.elapsed(); + let duration = self.monitor_starting_point.elapsed(); // As u32 can hold up to ~49 days in milliseconds, this should be sufficient for our use case // We still have a room up to 60bits timestamp if needed in future u32::try_from(duration.as_millis()).expect("Monitor running for too long") } - fn evaluate(&self, mut on_failed: impl FnMut(&IdentTag, MonitorEvaluationError)) { - for (tag, deadline) in self.active_deadlines.iter() { + fn evaluate(&self, mut on_failed: impl FnMut(&MonitorTag, MonitorEvaluationError)) { + for (deadline_tag, deadline) in self.active_deadlines.iter() { let snapshot = deadline.snapshot(); if snapshot.is_underrun() { // Deadline finished too early, report - warn!("Deadline finished too early!"); + warn!("Deadline ({:?}) finished too early!", deadline_tag); // Here we would normally report the underrun to the monitoring system - on_failed(tag, MonitorEvaluationError::TooEarly); + on_failed(&self.monitor_tag, MonitorEvaluationError::TooEarly); } else if snapshot.is_running() { debug_assert!( snapshot.is_stopped(), @@ -320,10 +325,13 @@ impl DeadlineMonitorInner { let expected = snapshot.timestamp_ms(); if now > expected { // Deadline missed, report - warn!("Deadline missed! Expected: {}, now: {}", expected, now); + warn!( + "Deadline ({:?}) missed! Expected: {}, now: {}", + deadline_tag, expected, now + ); // Here we would normally report the missed deadline to the monitoring system - on_failed(tag, MonitorEvaluationError::TooLate); + on_failed(&self.monitor_tag, MonitorEvaluationError::TooLate); } } } @@ -337,73 +345,75 @@ mod tests { fn create_monitor_with_deadlines() -> DeadlineMonitor { let allocator = ProtectedMemoryAllocator {}; + let monitor_tag = MonitorTag::from("deadline_monitor"); DeadlineMonitorBuilder::new() .add_deadline( - &IdentTag::from("deadline_long"), + DeadlineTag::from("deadline_long"), TimeRange::new(core::time::Duration::from_secs(1), core::time::Duration::from_secs(50)), ) .add_deadline( - &IdentTag::from("deadline_fast"), + DeadlineTag::from("deadline_fast"), TimeRange::new( core::time::Duration::from_millis(0), core::time::Duration::from_millis(50), ), ) - .build(&allocator) + .build(monitor_tag, &allocator) } fn create_monitor_with_multiple_running_deadlines() -> DeadlineMonitor { let allocator = ProtectedMemoryAllocator {}; + let monitor_tag = MonitorTag::from("deadline_monitor"); DeadlineMonitorBuilder::new() .add_deadline( - &IdentTag::from("slow"), + DeadlineTag::from("slow"), TimeRange::new(core::time::Duration::from_secs(0), core::time::Duration::from_secs(50)), ) .add_deadline( - &IdentTag::from("deadline_fast1"), + DeadlineTag::from("deadline_fast1"), TimeRange::new( core::time::Duration::from_millis(0), core::time::Duration::from_millis(50), ), ) .add_deadline( - &IdentTag::from("deadline_fast2"), + DeadlineTag::from("deadline_fast2"), TimeRange::new( core::time::Duration::from_millis(0), core::time::Duration::from_millis(34), ), ) .add_deadline( - &IdentTag::from("deadline_fast3"), + DeadlineTag::from("deadline_fast3"), TimeRange::new( core::time::Duration::from_millis(0), core::time::Duration::from_millis(10), ), ) - .build(&allocator) + .build(monitor_tag, &allocator) } #[test] fn get_deadline_unknown_tag() { let monitor = create_monitor_with_deadlines(); - let result = monitor.get_deadline(&IdentTag::from("unknown")); + let result = monitor.get_deadline(DeadlineTag::from("unknown")); assert_eq!(result.err(), Some(DeadlineMonitorError::DeadlineNotFound)); } #[test] fn start_stop_deadline_within_range_works() { let monitor = create_monitor_with_deadlines(); - let mut deadline = monitor.get_deadline(&IdentTag::from("deadline_long")).unwrap(); + let mut deadline = monitor.get_deadline(DeadlineTag::from("deadline_long")).unwrap(); let handle = deadline.start().unwrap(); std::thread::sleep(core::time::Duration::from_millis(1001)); // Sleep to simulate work within the deadline range drop(handle); // stop the deadline - monitor.inner.evaluate(|tag, deadline_failure| { + monitor.inner.evaluate(|monitor_tag, deadline_failure| { panic!( "Deadline {:?} should not have failed or underrun({:?})", - tag, deadline_failure + monitor_tag, deadline_failure ); }); } @@ -411,17 +421,17 @@ mod tests { #[test] fn start_stop_deadline_outside_ranges_is_error_when_dropped_before_evaluate() { let monitor = create_monitor_with_deadlines(); - let mut deadline = monitor.get_deadline(&IdentTag::from("deadline_long")).unwrap(); + let mut deadline = monitor.get_deadline(DeadlineTag::from("deadline_long")).unwrap(); let handle = deadline.start().unwrap(); drop(handle); // stop the deadline - monitor.inner.evaluate(|tag, deadline_failure| { + monitor.inner.evaluate(|monitor_tag, deadline_failure| { assert_eq!( deadline_failure, MonitorEvaluationError::TooEarly, "Deadline {:?} should not have failed({:?})", - tag, + monitor_tag, deadline_failure ); }); @@ -429,17 +439,17 @@ mod tests { #[test] fn deadline_outside_time_range_is_error_when_dropped_after_evaluate() { let monitor = create_monitor_with_deadlines(); - let mut deadline = monitor.get_deadline(&IdentTag::from("deadline_long")).unwrap(); + let mut deadline = monitor.get_deadline(DeadlineTag::from("deadline_long")).unwrap(); let handle = deadline.start().unwrap(); // So deadline stop happens after evaluate, still it should be reported as failed - monitor.inner.evaluate(|tag, deadline_failure| { + monitor.inner.evaluate(|monitor_tag, deadline_failure| { assert_eq!( deadline_failure, MonitorEvaluationError::TooEarly, "Deadline {:?} should not have failed({:?})", - tag, + monitor_tag, deadline_failure ); }); @@ -450,22 +460,22 @@ mod tests { #[test] fn deadline_failed_on_first_run_and_then_restarted_is_evaluated_as_error() { let monitor = create_monitor_with_deadlines(); - let mut deadline = monitor.get_deadline(&IdentTag::from("deadline_long")).unwrap(); + let mut deadline = monitor.get_deadline(DeadlineTag::from("deadline_long")).unwrap(); let handle = deadline.start().unwrap(); // So deadline failed, then we start it again so it shall be already expired and also evaluation shall work drop(handle); // stop the deadline drop(deadline); // drop the deadline to release it - let mut deadline = monitor.get_deadline(&IdentTag::from("deadline_long")).unwrap(); + let mut deadline = monitor.get_deadline(DeadlineTag::from("deadline_long")).unwrap(); let handle = deadline.start(); assert_eq!(handle.err(), Some(DeadlineError::DeadlineAlreadyFailed)); - monitor.inner.evaluate(|tag, deadline_failure| { + monitor.inner.evaluate(|monitor_tag, deadline_failure| { assert_eq!( deadline_failure, MonitorEvaluationError::TooEarly, "Deadline {:?} should not have failed ({:?})", - tag, + monitor_tag, deadline_failure ); }); @@ -474,17 +484,17 @@ mod tests { #[test] fn start_stop_deadline_outside_ranges_is_evaluated_as_error() { let monitor = create_monitor_with_deadlines(); - let mut deadline = monitor.get_deadline(&IdentTag::from("deadline_fast")).unwrap(); + let mut deadline = monitor.get_deadline(DeadlineTag::from("deadline_fast")).unwrap(); let handle = deadline.start().unwrap(); drop(handle); // stop the deadline - monitor.inner.evaluate(|tag, deadline_failure| { + monitor.inner.evaluate(|monitor_tag, deadline_failure| { assert_eq!( deadline_failure, MonitorEvaluationError::TooLate, "Deadline {:?} should not have failed({:?})", - tag, + monitor_tag, deadline_failure ); }); @@ -494,26 +504,26 @@ mod tests { fn monitor_with_multiple_running_deadlines() { let monitor = create_monitor_with_multiple_running_deadlines(); - let mut deadline = monitor.get_deadline(&IdentTag::from("deadline_fast1")).unwrap(); + let mut deadline = monitor.get_deadline(DeadlineTag::from("deadline_fast1")).unwrap(); let _handle1 = deadline.start().unwrap(); - let mut deadline = monitor.get_deadline(&IdentTag::from("deadline_fast2")).unwrap(); + let mut deadline = monitor.get_deadline(DeadlineTag::from("deadline_fast2")).unwrap(); let _handle2 = deadline.start().unwrap(); - let mut deadline = monitor.get_deadline(&IdentTag::from("deadline_fast3")).unwrap(); + let mut deadline = monitor.get_deadline(DeadlineTag::from("deadline_fast3")).unwrap(); let _handle3 = deadline.start().unwrap(); std::thread::sleep(core::time::Duration::from_millis(51)); // Sleep to simulate work within the deadline range let mut cnt = 0; - monitor.inner.evaluate(|tag, deadline_failure| { + monitor.inner.evaluate(|monitor_tag, deadline_failure| { cnt += 1; assert_eq!( deadline_failure, MonitorEvaluationError::TooLate, "Deadline {:?} should not have failed({:?})", - tag, + monitor_tag, deadline_failure ); }); diff --git a/src/health_monitoring_lib/rust/deadline/ffi.rs b/src/health_monitoring_lib/rust/deadline/ffi.rs index 8b45e67d..ab95dd6b 100644 --- a/src/health_monitoring_lib/rust/deadline/ffi.rs +++ b/src/health_monitoring_lib/rust/deadline/ffi.rs @@ -13,7 +13,8 @@ use crate::deadline::deadline_monitor::Deadline; use crate::deadline::{DeadlineMonitor, DeadlineMonitorBuilder, DeadlineMonitorError}; use crate::ffi::{FFIBorrowed, FFICode, FFIHandle}; -use crate::{IdentTag, TimeRange}; +use crate::tag::DeadlineTag; +use crate::TimeRange; use core::time::Duration; pub(crate) struct DeadlineMonitorCpp { @@ -27,8 +28,8 @@ impl DeadlineMonitorCpp { Self { monitor } } - pub(crate) fn get_deadline(&self, tag: IdentTag) -> Result { - match self.monitor.get_deadline(&tag) { + pub(crate) fn get_deadline(&self, deadline_tag: DeadlineTag) -> Result { + match self.monitor.get_deadline(deadline_tag) { Ok(deadline) => { // Now we allocate at runtime. As next step we will add a memory pool for deadlines into self and this way we will not need allocate anymore Ok(Box::into_raw(Box::new(deadline)).cast()) @@ -72,7 +73,7 @@ pub extern "C" fn deadline_monitor_builder_destroy(deadline_monitor_builder_hand #[no_mangle] pub extern "C" fn deadline_monitor_builder_add_deadline( deadline_monitor_builder_handle: FFIHandle, - deadline_tag: *const IdentTag, + deadline_tag: *const DeadlineTag, min_ms: u32, max_ms: u32, ) -> FFICode { @@ -86,7 +87,7 @@ pub extern "C" fn deadline_monitor_builder_add_deadline( // SAFETY: // Validity of the pointer is ensured. - // `IdentTag` type must be compatible between C++ and Rust. + // `DeadlineTag` type must be compatible between C++ and Rust. let deadline_tag = unsafe { *deadline_tag }; // SAFETY: @@ -97,7 +98,7 @@ pub extern "C" fn deadline_monitor_builder_add_deadline( FFIBorrowed::new(unsafe { Box::from_raw(deadline_monitor_builder_handle as *mut DeadlineMonitorBuilder) }); deadline_monitor_builder.add_deadline_internal( - &deadline_tag, + deadline_tag, TimeRange::new( Duration::from_millis(min_ms as u64), Duration::from_millis(max_ms as u64), @@ -110,7 +111,7 @@ pub extern "C" fn deadline_monitor_builder_add_deadline( #[no_mangle] pub extern "C" fn deadline_monitor_get_deadline( deadline_monitor_handle: FFIHandle, - deadline_tag: *const IdentTag, + deadline_tag: *const DeadlineTag, deadline_handle_out: *mut FFIHandle, ) -> FFICode { if deadline_monitor_handle.is_null() || deadline_tag.is_null() || deadline_handle_out.is_null() { @@ -119,7 +120,7 @@ pub extern "C" fn deadline_monitor_get_deadline( // SAFETY: // Validity of the pointer is ensured. - // `IdentTag` type must be compatible between C++ and Rust. + // `DeadlineTag` type must be compatible between C++ and Rust. let deadline_tag = unsafe { *deadline_tag }; // SAFETY: @@ -220,7 +221,7 @@ mod tests { health_monitor_builder_add_deadline_monitor, health_monitor_builder_build, health_monitor_builder_create, health_monitor_destroy, health_monitor_get_deadline_monitor, FFICode, FFIHandle, }; - use crate::IdentTag; + use crate::tag::{DeadlineTag, MonitorTag}; use core::ptr::null_mut; #[test] @@ -255,11 +256,11 @@ mod tests { let mut deadline_monitor_builder_handle: FFIHandle = null_mut(); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); - let deadline_tag = IdentTag::new("deadline_1"); + let deadline_tag = DeadlineTag::from("deadline_1"); let deadline_monitor_builder_add_deadline_result = deadline_monitor_builder_add_deadline( deadline_monitor_builder_handle, - &deadline_tag as *const IdentTag, + &deadline_tag as *const DeadlineTag, 100, 200, ); @@ -274,11 +275,11 @@ mod tests { let mut deadline_monitor_builder_handle: FFIHandle = null_mut(); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); - let deadline_tag = IdentTag::new("deadline_1"); + let deadline_tag = DeadlineTag::from("deadline_1"); let deadline_monitor_builder_add_deadline_result = deadline_monitor_builder_add_deadline( deadline_monitor_builder_handle, - &deadline_tag as *const IdentTag, + &deadline_tag as *const DeadlineTag, 10000, 100, ); @@ -290,10 +291,10 @@ mod tests { #[test] fn deadline_monitor_builder_add_deadline_null_builder() { - let deadline_tag = IdentTag::new("deadline_1"); + let deadline_tag = DeadlineTag::from("deadline_1"); let deadline_monitor_builder_add_deadline_result = - deadline_monitor_builder_add_deadline(null_mut(), &deadline_tag as *const IdentTag, 100, 200); + deadline_monitor_builder_add_deadline(null_mut(), &deadline_tag as *const DeadlineTag, 100, 200); assert_eq!(deadline_monitor_builder_add_deadline_result, FFICode::NullParameter); } @@ -319,19 +320,19 @@ mod tests { let mut deadline_monitor_handle: FFIHandle = null_mut(); let mut deadline_handle: FFIHandle = null_mut(); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); - let deadline_tag = IdentTag::new("deadline_1"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); + let deadline_tag = DeadlineTag::from("deadline_1"); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = deadline_monitor_builder_add_deadline( deadline_monitor_builder_handle, - &deadline_tag as *const IdentTag, + &deadline_tag as *const DeadlineTag, 100, 200, ); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( @@ -342,13 +343,13 @@ mod tests { ); let _ = health_monitor_get_deadline_monitor( health_monitor_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, &mut deadline_monitor_handle as *mut FFIHandle, ); let deadline_monitor_get_deadline_result = deadline_monitor_get_deadline( deadline_monitor_handle, - &deadline_tag as *const IdentTag, + &deadline_tag as *const DeadlineTag, &mut deadline_handle as *mut FFIHandle, ); assert!(!deadline_handle.is_null()); @@ -368,19 +369,19 @@ mod tests { let mut deadline_monitor_handle: FFIHandle = null_mut(); let mut deadline_handle: FFIHandle = null_mut(); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); - let deadline_tag = IdentTag::new("deadline_1"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); + let deadline_tag = DeadlineTag::from("deadline_1"); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = deadline_monitor_builder_add_deadline( deadline_monitor_builder_handle, - &deadline_tag as *const IdentTag, + &deadline_tag as *const DeadlineTag, 100, 200, ); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( @@ -391,14 +392,14 @@ mod tests { ); let _ = health_monitor_get_deadline_monitor( health_monitor_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, &mut deadline_monitor_handle as *mut FFIHandle, ); - let unknown_deadline_tag = IdentTag::new("deadline_2"); + let unknown_deadline_tag = DeadlineTag::from("deadline_2"); let deadline_monitor_get_deadline_result = deadline_monitor_get_deadline( deadline_monitor_handle, - &unknown_deadline_tag as *const IdentTag, + &unknown_deadline_tag as *const DeadlineTag, &mut deadline_handle as *mut FFIHandle, ); assert!(deadline_handle.is_null()); @@ -413,11 +414,11 @@ mod tests { fn deadline_monitor_get_deadline_null_monitor() { let mut deadline_handle: FFIHandle = null_mut(); - let deadline_tag = IdentTag::new("deadline_1"); + let deadline_tag = DeadlineTag::from("deadline_1"); let deadline_monitor_get_deadline_result = deadline_monitor_get_deadline( null_mut(), - &deadline_tag as *const IdentTag, + &deadline_tag as *const DeadlineTag, &mut deadline_handle as *mut FFIHandle, ); assert_eq!(deadline_monitor_get_deadline_result, FFICode::NullParameter); @@ -431,12 +432,12 @@ mod tests { let mut deadline_monitor_handle: FFIHandle = null_mut(); let mut deadline_handle: FFIHandle = null_mut(); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( @@ -447,7 +448,7 @@ mod tests { ); let _ = health_monitor_get_deadline_monitor( health_monitor_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, &mut deadline_monitor_handle as *mut FFIHandle, ); @@ -470,19 +471,19 @@ mod tests { let mut deadline_monitor_builder_handle: FFIHandle = null_mut(); let mut deadline_monitor_handle: FFIHandle = null_mut(); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); - let deadline_tag = IdentTag::new("deadline_1"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); + let deadline_tag = DeadlineTag::from("deadline_1"); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = deadline_monitor_builder_add_deadline( deadline_monitor_builder_handle, - &deadline_tag as *const IdentTag, + &deadline_tag as *const DeadlineTag, 100, 200, ); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( @@ -493,12 +494,12 @@ mod tests { ); let _ = health_monitor_get_deadline_monitor( health_monitor_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, &mut deadline_monitor_handle as *mut FFIHandle, ); let deadline_monitor_get_deadline_result = - deadline_monitor_get_deadline(deadline_monitor_handle, &deadline_tag as *const IdentTag, null_mut()); + deadline_monitor_get_deadline(deadline_monitor_handle, &deadline_tag as *const DeadlineTag, null_mut()); assert_eq!(deadline_monitor_get_deadline_result, FFICode::NullParameter); // Clean-up. @@ -520,19 +521,19 @@ mod tests { let mut deadline_monitor_handle: FFIHandle = null_mut(); let mut deadline_handle: FFIHandle = null_mut(); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); - let deadline_tag = IdentTag::new("deadline_1"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); + let deadline_tag = DeadlineTag::from("deadline_1"); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = deadline_monitor_builder_add_deadline( deadline_monitor_builder_handle, - &deadline_tag as *const IdentTag, + &deadline_tag as *const DeadlineTag, 100, 200, ); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( @@ -543,12 +544,12 @@ mod tests { ); let _ = health_monitor_get_deadline_monitor( health_monitor_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, &mut deadline_monitor_handle as *mut FFIHandle, ); let _ = deadline_monitor_get_deadline( deadline_monitor_handle, - &deadline_tag as *const IdentTag, + &deadline_tag as *const DeadlineTag, &mut deadline_handle as *mut FFIHandle, ); @@ -569,19 +570,19 @@ mod tests { let mut deadline_monitor_handle: FFIHandle = null_mut(); let mut deadline_handle: FFIHandle = null_mut(); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); - let deadline_tag = IdentTag::new("deadline_1"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); + let deadline_tag = DeadlineTag::from("deadline_1"); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = deadline_monitor_builder_add_deadline( deadline_monitor_builder_handle, - &deadline_tag as *const IdentTag, + &deadline_tag as *const DeadlineTag, 100, 200, ); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( @@ -592,12 +593,12 @@ mod tests { ); let _ = health_monitor_get_deadline_monitor( health_monitor_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, &mut deadline_monitor_handle as *mut FFIHandle, ); let _ = deadline_monitor_get_deadline( deadline_monitor_handle, - &deadline_tag as *const IdentTag, + &deadline_tag as *const DeadlineTag, &mut deadline_handle as *mut FFIHandle, ); @@ -625,19 +626,19 @@ mod tests { let mut deadline_monitor_handle: FFIHandle = null_mut(); let mut deadline_handle: FFIHandle = null_mut(); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); - let deadline_tag = IdentTag::new("deadline_1"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); + let deadline_tag = DeadlineTag::from("deadline_1"); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = deadline_monitor_builder_add_deadline( deadline_monitor_builder_handle, - &deadline_tag as *const IdentTag, + &deadline_tag as *const DeadlineTag, 100, 200, ); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( @@ -648,12 +649,12 @@ mod tests { ); let _ = health_monitor_get_deadline_monitor( health_monitor_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, &mut deadline_monitor_handle as *mut FFIHandle, ); let _ = deadline_monitor_get_deadline( deadline_monitor_handle, - &deadline_tag as *const IdentTag, + &deadline_tag as *const DeadlineTag, &mut deadline_handle as *mut FFIHandle, ); let _ = deadline_start(deadline_handle); diff --git a/src/health_monitoring_lib/rust/ffi.rs b/src/health_monitoring_lib/rust/ffi.rs index a3d3888e..f08b4c08 100644 --- a/src/health_monitoring_lib/rust/ffi.rs +++ b/src/health_monitoring_lib/rust/ffi.rs @@ -12,7 +12,7 @@ // ******************************************************************************* use crate::deadline::ffi::DeadlineMonitorCpp; use crate::deadline::DeadlineMonitorBuilder; -use crate::IdentTag; +use crate::tag::MonitorTag; use crate::{HealthMonitor, HealthMonitorBuilder}; use core::mem::ManuallyDrop; use core::ops::{Deref, DerefMut}; @@ -132,7 +132,7 @@ pub extern "C" fn health_monitor_builder_build( #[no_mangle] pub extern "C" fn health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle: FFIHandle, - monitor_tag: *const IdentTag, + monitor_tag: *const MonitorTag, deadline_monitor_builder_handle: FFIHandle, ) -> FFICode { if health_monitor_builder_handle.is_null() || monitor_tag.is_null() || deadline_monitor_builder_handle.is_null() { @@ -141,7 +141,7 @@ pub extern "C" fn health_monitor_builder_add_deadline_monitor( // SAFETY: // Validity of the pointer is ensured. - // `IdentTag` type must be compatible between C++ and Rust. + // `MonitorTag` type must be compatible between C++ and Rust. let monitor_tag = unsafe { *monitor_tag }; // SAFETY: @@ -158,7 +158,7 @@ pub extern "C" fn health_monitor_builder_add_deadline_monitor( let mut health_monitor_builder = FFIBorrowed::new(unsafe { Box::from_raw(health_monitor_builder_handle as *mut HealthMonitorBuilder) }); - health_monitor_builder.add_deadline_monitor_internal(&monitor_tag, *deadline_monitor_builder); + health_monitor_builder.add_deadline_monitor_internal(monitor_tag, *deadline_monitor_builder); FFICode::Success } @@ -166,7 +166,7 @@ pub extern "C" fn health_monitor_builder_add_deadline_monitor( #[no_mangle] pub extern "C" fn health_monitor_get_deadline_monitor( health_monitor_handle: FFIHandle, - monitor_tag: *const IdentTag, + monitor_tag: *const MonitorTag, deadline_monitor_handle_out: *mut FFIHandle, ) -> FFICode { if health_monitor_handle.is_null() || monitor_tag.is_null() || deadline_monitor_handle_out.is_null() { @@ -175,7 +175,7 @@ pub extern "C" fn health_monitor_get_deadline_monitor( // SAFETY: // Validity of the pointer is ensured. - // `IdentTag` type must be compatible between C++ and Rust. + // `MonitorTag` type must be compatible between C++ and Rust. let monitor_tag = unsafe { *monitor_tag }; // SAFETY: @@ -184,7 +184,7 @@ pub extern "C" fn health_monitor_get_deadline_monitor( // It is assumed that the pointer was not consumed by a call to `health_monitor_destroy`. let mut health_monitor = FFIBorrowed::new(unsafe { Box::from_raw(health_monitor_handle as *mut HealthMonitor) }); - if let Some(deadline_monitor) = health_monitor.get_deadline_monitor(&monitor_tag) { + if let Some(deadline_monitor) = health_monitor.get_deadline_monitor(monitor_tag) { unsafe { *deadline_monitor_handle_out = Box::into_raw(Box::new(DeadlineMonitorCpp::new(deadline_monitor))).cast(); } @@ -248,7 +248,7 @@ mod tests { health_monitor_builder_destroy, health_monitor_destroy, health_monitor_get_deadline_monitor, health_monitor_start, FFICode, FFIHandle, }; - use crate::IdentTag; + use crate::tag::MonitorTag; use core::ptr::null_mut; #[test] @@ -350,12 +350,12 @@ mod tests { let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let health_monitor_builder_add_deadline_monitor_result = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); assert_eq!(health_monitor_builder_add_deadline_monitor_result, FFICode::Success); @@ -368,12 +368,12 @@ mod tests { fn health_monitor_builder_add_deadline_monitor_null_hmon_builder() { let mut deadline_monitor_builder_handle: FFIHandle = null_mut(); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let health_monitor_builder_add_deadline_monitor_result = health_monitor_builder_add_deadline_monitor( null_mut(), - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); assert_eq!( @@ -413,11 +413,11 @@ mod tests { let mut health_monitor_builder_handle: FFIHandle = null_mut(); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); let health_monitor_builder_add_deadline_monitor_result = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, null_mut(), ); assert_eq!( @@ -437,11 +437,11 @@ mod tests { let mut deadline_monitor_handle: FFIHandle = null_mut(); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( @@ -453,7 +453,7 @@ mod tests { let health_monitor_get_deadline_monitor_result = health_monitor_get_deadline_monitor( health_monitor_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, &mut deadline_monitor_handle as *mut FFIHandle, ); assert!(!deadline_monitor_handle.is_null()); @@ -473,11 +473,11 @@ mod tests { let mut deadline_monitor_2_handle: FFIHandle = null_mut(); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( @@ -490,7 +490,7 @@ mod tests { // First get. let health_monitor_get_deadline_monitor_result_1 = health_monitor_get_deadline_monitor( health_monitor_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, &mut deadline_monitor_1_handle as *mut FFIHandle, ); assert!(!deadline_monitor_1_handle.is_null()); @@ -499,7 +499,7 @@ mod tests { // Second get. let health_monitor_get_deadline_monitor_result_2 = health_monitor_get_deadline_monitor( health_monitor_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, &mut deadline_monitor_2_handle as *mut FFIHandle, ); assert!(deadline_monitor_2_handle.is_null()); @@ -518,11 +518,11 @@ mod tests { let mut deadline_monitor_handle: FFIHandle = null_mut(); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( @@ -534,7 +534,7 @@ mod tests { let health_monitor_get_deadline_monitor_result = health_monitor_get_deadline_monitor( null_mut(), - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, &mut deadline_monitor_handle as *mut FFIHandle, ); assert!(deadline_monitor_handle.is_null()); @@ -552,11 +552,11 @@ mod tests { let mut deadline_monitor_handle: FFIHandle = null_mut(); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( @@ -585,11 +585,11 @@ mod tests { let mut deadline_monitor_builder_handle: FFIHandle = null_mut(); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( @@ -601,7 +601,7 @@ mod tests { let health_monitor_get_deadline_monitor_result = health_monitor_get_deadline_monitor( health_monitor_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, null_mut(), ); assert_eq!(health_monitor_get_deadline_monitor_result, FFICode::NullParameter); @@ -618,11 +618,11 @@ mod tests { let mut deadline_monitor_handle: FFIHandle = null_mut(); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( @@ -634,7 +634,7 @@ mod tests { let _ = health_monitor_get_deadline_monitor( health_monitor_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, &mut deadline_monitor_handle as *mut FFIHandle, ); @@ -653,11 +653,11 @@ mod tests { let mut deadline_monitor_builder_handle: FFIHandle = null_mut(); let _ = health_monitor_builder_create(&mut health_monitor_builder_handle as *mut FFIHandle); - let deadline_monitor_tag = IdentTag::new("deadline_monitor"); + let deadline_monitor_tag = MonitorTag::from("deadline_monitor"); let _ = deadline_monitor_builder_create(&mut deadline_monitor_builder_handle as *mut FFIHandle); let _ = health_monitor_builder_add_deadline_monitor( health_monitor_builder_handle, - &deadline_monitor_tag as *const IdentTag, + &deadline_monitor_tag as *const MonitorTag, deadline_monitor_builder_handle, ); let _ = health_monitor_builder_build( diff --git a/src/health_monitoring_lib/rust/lib.rs b/src/health_monitoring_lib/rust/lib.rs index afdbe9e9..492e6378 100644 --- a/src/health_monitoring_lib/rust/lib.rs +++ b/src/health_monitoring_lib/rust/lib.rs @@ -11,57 +11,60 @@ // SPDX-License-Identifier: Apache-2.0 // ******************************************************************************* -use std::collections::HashMap; - mod common; mod ffi; mod log; mod protected_memory; +mod tag; mod worker; pub mod deadline; + use crate::common::MonitorEvalHandle; -pub use common::{IdentTag, TimeRange}; +pub use common::TimeRange; use containers::fixed_capacity::FixedCapacityVec; +use core::time::Duration; +use std::collections::HashMap; +pub use tag::{DeadlineTag, MonitorTag}; #[derive(Default)] pub struct HealthMonitorBuilder { - deadlines: HashMap, - supervisor_api_cycle: core::time::Duration, - internal_processing_cycle: core::time::Duration, + deadline_monitor_builders: HashMap, + supervisor_api_cycle: Duration, + internal_processing_cycle: Duration, } impl HealthMonitorBuilder { /// Create a new [`HealthMonitorBuilder`] instance. pub fn new() -> Self { Self { - deadlines: HashMap::new(), - supervisor_api_cycle: core::time::Duration::from_millis(500), - internal_processing_cycle: core::time::Duration::from_millis(100), + deadline_monitor_builders: HashMap::new(), + supervisor_api_cycle: Duration::from_millis(500), + internal_processing_cycle: Duration::from_millis(100), } } /// Adds a deadline monitor for a specific identifier tag. /// # Arguments - /// * `tag` - The unique identifier for the deadline monitor. + /// * `monitor_tag` - The unique identifier for the deadline monitor. /// * `monitor` - The builder for the deadline monitor. /// # Note /// If a monitor with the same tag already exists, it will be overwritten. - pub fn add_deadline_monitor(mut self, tag: &IdentTag, monitor: deadline::DeadlineMonitorBuilder) -> Self { - self.add_deadline_monitor_internal(tag, monitor); + pub fn add_deadline_monitor(mut self, monitor_tag: MonitorTag, monitor: deadline::DeadlineMonitorBuilder) -> Self { + self.add_deadline_monitor_internal(monitor_tag, monitor); self } /// Sets the cycle duration for supervisor API notifications. /// This duration determines how often the health monitor notifies the supervisor that the system is alive. - pub fn with_supervisor_api_cycle(mut self, cycle_duration: core::time::Duration) -> Self { + pub fn with_supervisor_api_cycle(mut self, cycle_duration: Duration) -> Self { self.with_supervisor_api_cycle_internal(cycle_duration); self } /// Sets the internal processing cycle duration. /// This duration determines how often the health monitor checks deadlines. - pub fn with_internal_processing_cycle(mut self, cycle_duration: core::time::Duration) -> Self { + pub fn with_internal_processing_cycle(mut self, cycle_duration: Duration) -> Self { self.with_internal_processing_cycle_internal(cycle_duration); self } @@ -78,15 +81,19 @@ impl HealthMonitorBuilder { // Used by FFI and config parsing code which prefer not to move builder instance - pub(crate) fn add_deadline_monitor_internal(&mut self, tag: &IdentTag, monitor: deadline::DeadlineMonitorBuilder) { - self.deadlines.insert(*tag, monitor); + pub(crate) fn add_deadline_monitor_internal( + &mut self, + monitor_tag: MonitorTag, + monitor: deadline::DeadlineMonitorBuilder, + ) { + self.deadline_monitor_builders.insert(monitor_tag, monitor); } - pub(crate) fn with_supervisor_api_cycle_internal(&mut self, cycle_duration: core::time::Duration) { + pub(crate) fn with_supervisor_api_cycle_internal(&mut self, cycle_duration: Duration) { self.supervisor_api_cycle = cycle_duration; } - pub(crate) fn with_internal_processing_cycle_internal(&mut self, cycle_duration: core::time::Duration) { + pub(crate) fn with_internal_processing_cycle_internal(&mut self, cycle_duration: Duration) { self.internal_processing_cycle = cycle_duration; } @@ -98,12 +105,18 @@ impl HealthMonitorBuilder { pub(crate) fn build_internal(self) -> HealthMonitor { let allocator = protected_memory::ProtectedMemoryAllocator {}; - let mut monitors = HashMap::new(); - for (tag, builder) in self.deadlines { - monitors.insert(tag, Some(DeadlineMonitorState::Available(builder.build(&allocator)))); + + // Create deadline monitors. + let mut deadline_monitors = HashMap::new(); + for (tag, builder) in self.deadline_monitor_builders { + deadline_monitors.insert( + tag, + Some(DeadlineMonitorState::Available(builder.build(tag, &allocator))), + ); } + HealthMonitor { - deadline_monitors: monitors, + deadline_monitors, worker: worker::UniqueThreadRunner::new(self.internal_processing_cycle), supervisor_api_cycle: self.supervisor_api_cycle, } @@ -116,21 +129,21 @@ enum DeadlineMonitorState { } pub struct HealthMonitor { - deadline_monitors: HashMap>, + deadline_monitors: HashMap>, worker: worker::UniqueThreadRunner, - supervisor_api_cycle: core::time::Duration, + supervisor_api_cycle: Duration, } impl HealthMonitor { /// Retrieves and removes (hand over to user) a deadline monitor associated with the given identifier tag. /// # Arguments - /// * `tag` - The unique identifier for the deadline monitor. + /// * `monitor_tag` - The unique identifier for the deadline monitor. /// # Returns /// An Option containing the DeadlineMonitor if found, or None if /// - no monitor exists for the given tag or was already obtained /// - pub fn get_deadline_monitor(&mut self, tag: &IdentTag) -> Option { - let monitor = self.deadline_monitors.get_mut(tag)?; + pub fn get_deadline_monitor(&mut self, monitor_tag: MonitorTag) -> Option { + let monitor = self.deadline_monitors.get_mut(&monitor_tag)?; match monitor.take() { Some(DeadlineMonitorState::Available(deadline_monitor)) => { @@ -234,27 +247,33 @@ mod tests { #[should_panic(expected = "supervisor API cycle must be multiple of internal processing cycle")] fn hm_with_wrong_cycle_fails_to_build() { super::HealthMonitorBuilder::new() - .with_supervisor_api_cycle(core::time::Duration::from_millis(50)) + .with_supervisor_api_cycle(Duration::from_millis(50)) .build(); } #[test] fn hm_with_taken_monitors_starts() { let mut health_monitor = HealthMonitorBuilder::new() - .add_deadline_monitor(&IdentTag::new("test_monitor"), deadline::DeadlineMonitorBuilder::new()) + .add_deadline_monitor( + MonitorTag::from("test_monitor"), + deadline::DeadlineMonitorBuilder::new(), + ) .build(); - let _monitor = health_monitor.get_deadline_monitor(&IdentTag::new("test_monitor")); + let _monitor = health_monitor.get_deadline_monitor(MonitorTag::from("test_monitor")); health_monitor.start(); } #[test] #[should_panic( - expected = "All monitors must be taken before starting HealthMonitor but IdentTag(test_monitor) is not taken." + expected = "All monitors must be taken before starting HealthMonitor but MonitorTag(test_monitor) is not taken." )] fn hm_with_monitors_shall_not_start_with_not_taken_monitors() { let mut health_monitor = HealthMonitorBuilder::new() - .add_deadline_monitor(&IdentTag::new("test_monitor"), deadline::DeadlineMonitorBuilder::new()) + .add_deadline_monitor( + MonitorTag::from("test_monitor"), + deadline::DeadlineMonitorBuilder::new(), + ) .build(); health_monitor.start(); @@ -263,11 +282,14 @@ mod tests { #[test] fn hm_get_deadline_monitor_works() { let mut health_monitor = HealthMonitorBuilder::new() - .add_deadline_monitor(&IdentTag::new("test_monitor"), deadline::DeadlineMonitorBuilder::new()) + .add_deadline_monitor( + MonitorTag::from("test_monitor"), + deadline::DeadlineMonitorBuilder::new(), + ) .build(); { - let monitor = health_monitor.get_deadline_monitor(&IdentTag::new("test_monitor")); + let monitor = health_monitor.get_deadline_monitor(MonitorTag::from("test_monitor")); assert!( monitor.is_some(), "Expected to retrieve the deadline monitor, but got None" @@ -275,7 +297,7 @@ mod tests { } { - let monitor = health_monitor.get_deadline_monitor(&IdentTag::new("test_monitor")); + let monitor = health_monitor.get_deadline_monitor(MonitorTag::from("test_monitor")); assert!( monitor.is_none(), "Expected None when retrieving the monitor a second time, but got Some" diff --git a/src/health_monitoring_lib/rust/log.rs b/src/health_monitoring_lib/rust/log.rs index 9a442509..ea200e51 100644 --- a/src/health_monitoring_lib/rust/log.rs +++ b/src/health_monitoring_lib/rust/log.rs @@ -62,5 +62,5 @@ macro_rules! trace { pub(crate) use {debug, error, fatal, info, trace, warning as warn}; // Re-export symbols from `score_log`. -pub(crate) use score_log::fmt::{DebugStruct, Error, FormatSpec, ScoreDebug, Writer}; +pub(crate) use score_log::fmt::{score_write, DebugStruct, Error, FormatSpec, ScoreDebug, Writer}; pub(crate) use score_log::ScoreDebug; diff --git a/src/health_monitoring_lib/rust/tag.rs b/src/health_monitoring_lib/rust/tag.rs new file mode 100644 index 00000000..eca868df --- /dev/null +++ b/src/health_monitoring_lib/rust/tag.rs @@ -0,0 +1,346 @@ +// ******************************************************************************* +// 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 +// +// +// SPDX-License-Identifier: Apache-2.0 +// ******************************************************************************* + +use crate::log; +use core::fmt; +use core::hash::{Hash, Hasher}; + +/// Common string-based tag. +#[derive(Clone, Copy, Eq)] +#[repr(C)] +struct Tag { + data: *const u8, + length: usize, +} + +unsafe impl Send for Tag {} +unsafe impl Sync for Tag {} + +impl fmt::Debug for Tag { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // SAFETY: the underlying data was created from a valid `&str`. + let bytes = unsafe { core::slice::from_raw_parts(self.data, self.length) }; + let s = unsafe { core::str::from_utf8_unchecked(bytes) }; + write!(f, "Tag({})", s) + } +} + +impl log::ScoreDebug for Tag { + fn fmt(&self, f: log::Writer, _spec: &log::FormatSpec) -> Result<(), log::Error> { + // SAFETY: the underlying data was created from a valid `&str`. + let bytes = unsafe { core::slice::from_raw_parts(self.data, self.length) }; + let s = unsafe { core::str::from_utf8_unchecked(bytes) }; + log::score_write!(f, "Tag({})", s) + } +} + +impl Hash for Tag { + fn hash(&self, state: &mut H) { + // SAFETY: the underlying data was created from a valid `&str`. + let bytes = unsafe { core::slice::from_raw_parts(self.data, self.length) }; + bytes.hash(state); + } +} + +impl PartialEq for Tag { + fn eq(&self, other: &Self) -> bool { + // SAFETY: the underlying data was created from a valid `&str`. + let self_bytes = unsafe { core::slice::from_raw_parts(self.data, self.length) }; + let other_bytes = unsafe { core::slice::from_raw_parts(other.data, other.length) }; + self_bytes == other_bytes + } +} + +impl From for Tag { + fn from(value: String) -> Self { + let leaked = value.leak(); + Self { + data: leaked.as_ptr(), + length: leaked.len(), + } + } +} + +impl From<&str> for Tag { + fn from(value: &str) -> Self { + let leaked = value.to_string().leak(); + Self { + data: leaked.as_ptr(), + length: leaked.len(), + } + } +} + +/// Monitor tag. +#[derive(Clone, Copy, Eq, Hash, PartialEq)] +#[repr(C)] +pub struct MonitorTag(Tag); + +impl fmt::Debug for MonitorTag { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // SAFETY: the underlying data was created from a valid `&str`. + let bytes = unsafe { core::slice::from_raw_parts(self.0.data, self.0.length) }; + let s = unsafe { core::str::from_utf8_unchecked(bytes) }; + write!(f, "MonitorTag({})", s) + } +} + +impl log::ScoreDebug for MonitorTag { + fn fmt(&self, f: log::Writer, _spec: &log::FormatSpec) -> Result<(), log::Error> { + // SAFETY: the underlying data was created from a valid `&str`. + let bytes = unsafe { core::slice::from_raw_parts(self.0.data, self.0.length) }; + let s = unsafe { core::str::from_utf8_unchecked(bytes) }; + log::score_write!(f, "MonitorTag({})", s) + } +} + +impl From for MonitorTag { + fn from(value: String) -> Self { + Self(Tag::from(value)) + } +} + +impl From<&str> for MonitorTag { + fn from(value: &str) -> Self { + Self(Tag::from(value)) + } +} + +/// Deadline tag. +#[derive(Clone, Copy, Eq, Hash, PartialEq)] +#[repr(C)] +pub struct DeadlineTag(Tag); + +impl fmt::Debug for DeadlineTag { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // SAFETY: the underlying data was created from a valid `&str`. + let bytes = unsafe { core::slice::from_raw_parts(self.0.data, self.0.length) }; + let s = unsafe { core::str::from_utf8_unchecked(bytes) }; + write!(f, "DeadlineTag({})", s) + } +} + +impl log::ScoreDebug for DeadlineTag { + fn fmt(&self, f: log::Writer, _spec: &log::FormatSpec) -> Result<(), log::Error> { + // SAFETY: the underlying data was created from a valid `&str`. + let bytes = unsafe { core::slice::from_raw_parts(self.0.data, self.0.length) }; + let s = unsafe { core::str::from_utf8_unchecked(bytes) }; + log::score_write!(f, "DeadlineTag({})", s) + } +} + +impl From for DeadlineTag { + fn from(value: String) -> Self { + Self(Tag::from(value)) + } +} + +impl From<&str> for DeadlineTag { + fn from(value: &str) -> Self { + Self(Tag::from(value)) + } +} + +#[cfg(test)] +mod tests { + use crate::log::score_write; + use crate::tag::{DeadlineTag, MonitorTag, Tag}; + use core::fmt::Write; + use core::hash::{Hash, Hasher}; + use score_log::fmt::{Error, FormatSpec, Result as FmtResult, ScoreWrite}; + use std::hash::DefaultHasher; + + struct StringWriter { + buffer: String, + } + + impl StringWriter { + pub fn new() -> Self { + Self { buffer: String::new() } + } + + pub fn get(&self) -> &str { + self.buffer.as_str() + } + } + + impl ScoreWrite for StringWriter { + fn write_bool(&mut self, v: &bool, _spec: &FormatSpec) -> FmtResult { + write!(self.buffer, "{}", v).map_err(|_| Error) + } + + fn write_f32(&mut self, v: &f32, _spec: &FormatSpec) -> FmtResult { + write!(self.buffer, "{}", v).map_err(|_| Error) + } + + fn write_f64(&mut self, v: &f64, _spec: &FormatSpec) -> FmtResult { + write!(self.buffer, "{}", v).map_err(|_| Error) + } + + fn write_i8(&mut self, v: &i8, _spec: &FormatSpec) -> FmtResult { + write!(self.buffer, "{}", v).map_err(|_| Error) + } + + fn write_i16(&mut self, v: &i16, _spec: &FormatSpec) -> FmtResult { + write!(self.buffer, "{}", v).map_err(|_| Error) + } + + fn write_i32(&mut self, v: &i32, _spec: &FormatSpec) -> FmtResult { + write!(self.buffer, "{}", v).map_err(|_| Error) + } + + fn write_i64(&mut self, v: &i64, _spec: &FormatSpec) -> FmtResult { + write!(self.buffer, "{}", v).map_err(|_| Error) + } + + fn write_u8(&mut self, v: &u8, _spec: &FormatSpec) -> FmtResult { + write!(self.buffer, "{}", v).map_err(|_| Error) + } + + fn write_u16(&mut self, v: &u16, _spec: &FormatSpec) -> FmtResult { + write!(self.buffer, "{}", v).map_err(|_| Error) + } + + fn write_u32(&mut self, v: &u32, _spec: &FormatSpec) -> FmtResult { + write!(self.buffer, "{}", v).map_err(|_| Error) + } + + fn write_u64(&mut self, v: &u64, _spec: &FormatSpec) -> FmtResult { + write!(self.buffer, "{}", v).map_err(|_| Error) + } + + fn write_str(&mut self, v: &str, _spec: &FormatSpec) -> FmtResult { + write!(self.buffer, "{}", v).map_err(|_| Error) + } + } + + fn compare_tag(tag: Tag, expected: &str) { + let tag_as_bytes = unsafe { core::slice::from_raw_parts(tag.data, tag.length) }; + let tag_as_str = unsafe { core::str::from_utf8_unchecked(tag_as_bytes) }; + assert_eq!(tag_as_str, expected); + } + + #[test] + fn tag_debug() { + let example_str = "EXAMPLE"; + let tag = Tag::from(example_str.to_string()); + assert_eq!(format!("{:?}", tag), "Tag(EXAMPLE)"); + } + + #[test] + fn tag_score_debug() { + let example_str = "EXAMPLE"; + let tag = Tag::from(example_str.to_string()); + let mut writer = StringWriter::new(); + assert!(score_write!(&mut writer, "{:?}", tag).is_ok()); + assert_eq!(writer.get(), "Tag(EXAMPLE)"); + } + + #[test] + fn tag_hash() { + let example_str = "EXAMPLE"; + let tag = Tag::from(example_str.to_string()); + let mut hasher = DefaultHasher::new(); + tag.hash(&mut hasher); + let hash = hasher.finish(); + assert_eq!(hash, 14738755424381306335); + } + + #[test] + fn tag_partial_eq_is_eq() { + let tag1 = Tag::from("same"); + let tag2 = Tag::from("same"); + assert_eq!(tag1, tag2); + } + + #[test] + fn tag_partial_eq_is_ne() { + let tag1 = Tag::from("first"); + let tag2 = Tag::from("second"); + assert_ne!(tag1, tag2); + } + + #[test] + fn test_from_string() { + let example_str = "EXAMPLE"; + let tag = Tag::from(example_str.to_string()); + compare_tag(tag, example_str); + } + + #[test] + fn test_from_str() { + let example_str = "EXAMPLE"; + let tag = Tag::from(example_str); + compare_tag(tag, example_str); + } + + #[test] + fn monitor_tag_debug() { + let example_str = "EXAMPLE"; + let tag = MonitorTag::from(example_str.to_string()); + assert_eq!(format!("{:?}", tag), "MonitorTag(EXAMPLE)"); + } + + #[test] + fn monitor_tag_score_debug() { + let example_str = "EXAMPLE"; + let tag = MonitorTag::from(example_str.to_string()); + let mut writer = StringWriter::new(); + assert!(score_write!(&mut writer, "{:?}", tag).is_ok()); + assert_eq!(writer.get(), "MonitorTag(EXAMPLE)"); + } + + #[test] + fn monitor_tag_from_string() { + let example_str = "EXAMPLE"; + let tag = MonitorTag::from(example_str.to_string()); + compare_tag(tag.0, example_str); + } + + #[test] + fn monitor_tag_from_str() { + let example_str = "EXAMPLE"; + let tag = MonitorTag::from(example_str); + compare_tag(tag.0, example_str); + } + + #[test] + fn deadline_tag_debug() { + let example_str = "EXAMPLE"; + let tag = DeadlineTag::from(example_str.to_string()); + assert_eq!(format!("{:?}", tag), "DeadlineTag(EXAMPLE)"); + } + + #[test] + fn deadline_tag_score_debug() { + let example_str = "EXAMPLE"; + let tag = DeadlineTag::from(example_str.to_string()); + let mut writer = StringWriter::new(); + assert!(score_write!(&mut writer, "{:?}", tag).is_ok()); + assert_eq!(writer.get(), "DeadlineTag(EXAMPLE)"); + } + + #[test] + fn deadline_tag_from_string() { + let example_str = "EXAMPLE"; + let tag = DeadlineTag::from(example_str.to_string()); + compare_tag(tag.0, example_str); + } + + #[test] + fn deadline_tag_from_str() { + let example_str = "EXAMPLE"; + let tag = DeadlineTag::from(example_str); + compare_tag(tag.0, example_str); + } +} diff --git a/src/health_monitoring_lib/rust/worker.rs b/src/health_monitoring_lib/rust/worker.rs index bed7091c..8830e153 100644 --- a/src/health_monitoring_lib/rust/worker.rs +++ b/src/health_monitoring_lib/rust/worker.rs @@ -10,14 +10,10 @@ // // SPDX-License-Identifier: Apache-2.0 // ******************************************************************************* -use crate::{common::MonitorEvaluator, log::debug}; +use crate::common::{MonitorEvalHandle, MonitorEvaluator}; +use crate::log::{debug, info, warn}; use containers::fixed_capacity::FixedCapacityVec; -use crate::{ - common::MonitorEvalHandle, - log::{info, warn}, -}; - /// An abstraction over the API used to notify the supervisor about process liveness. pub(super) trait SupervisorAPIClient { fn notify_alive(&self); @@ -53,9 +49,10 @@ impl MonitoringLogic { let mut has_any_error = false; for monitor in self.monitors.iter() { - monitor.evaluate(&mut |tag, error| { + monitor.evaluate(&mut |monitor_tag, error| { has_any_error = true; - warn!("Monitor with tag {:?} reported error: {:?}.", tag, error); + // TODO: monitor type should be mentioned. + warn!("Monitor with tag {:?} reported error: {:?}.", monitor_tag, error); }); } @@ -185,12 +182,10 @@ impl SupervisorAPIClient for ScoreSupervisorAPIClient { #[score_testing_macros::test_mod_with_log] #[cfg(test)] mod tests { - - use crate::{ - deadline::{DeadlineMonitor, DeadlineMonitorBuilder}, - protected_memory::ProtectedMemoryAllocator, - IdentTag, TimeRange, - }; + use crate::deadline::{DeadlineMonitor, DeadlineMonitorBuilder}; + use crate::protected_memory::ProtectedMemoryAllocator; + use crate::tag::{DeadlineTag, MonitorTag}; + use crate::TimeRange; use super::*; @@ -219,19 +214,20 @@ mod tests { fn create_monitor_with_deadlines() -> DeadlineMonitor { let allocator = ProtectedMemoryAllocator {}; + let monitor_tag = MonitorTag::from("deadline_monitor"); DeadlineMonitorBuilder::new() .add_deadline( - &IdentTag::from("deadline_long"), + DeadlineTag::from("deadline_long"), TimeRange::new(core::time::Duration::from_secs(1), core::time::Duration::from_secs(50)), ) .add_deadline( - &IdentTag::from("deadline_fast"), + DeadlineTag::from("deadline_fast"), TimeRange::new( core::time::Duration::from_millis(0), core::time::Duration::from_millis(50), ), ) - .build(&allocator) + .build(monitor_tag, &allocator) } #[test] @@ -249,7 +245,9 @@ mod tests { alive_mock.clone(), ); - let mut deadline = deadline_monitor.get_deadline(&IdentTag::from("deadline_long")).unwrap(); + let mut deadline = deadline_monitor + .get_deadline(DeadlineTag::from("deadline_long")) + .unwrap(); let handle = deadline.start().unwrap(); drop(handle); @@ -273,7 +271,9 @@ mod tests { alive_mock.clone(), ); - let mut deadline = deadline_monitor.get_deadline(&IdentTag::from("deadline_long")).unwrap(); + let mut deadline = deadline_monitor + .get_deadline(DeadlineTag::from("deadline_long")) + .unwrap(); let _handle = deadline.start().unwrap(); assert!(logic.run()); @@ -300,7 +300,9 @@ mod tests { alive_mock.clone(), ); - let mut deadline = deadline_monitor.get_deadline(&IdentTag::from("deadline_long")).unwrap(); + let mut deadline = deadline_monitor + .get_deadline(DeadlineTag::from("deadline_long")) + .unwrap(); let _handle = deadline.start().unwrap(); std::thread::sleep(core::time::Duration::from_millis(30)); @@ -340,7 +342,9 @@ mod tests { let mut worker = UniqueThreadRunner::new(core::time::Duration::from_millis(10)); worker.start(logic); - let mut deadline = deadline_monitor.get_deadline(&IdentTag::from("deadline_fast")).unwrap(); + let mut deadline = deadline_monitor + .get_deadline(DeadlineTag::from("deadline_fast")) + .unwrap(); let handle = deadline.start().unwrap();