From 9b83e6bf4482d7bd6c6ed07a5067fa33a003edbb Mon Sep 17 00:00:00 2001 From: Pawel Rutka Date: Thu, 22 Jan 2026 14:55:53 +0100 Subject: [PATCH 1/5] Enable clangd indexing for codebase --- .clang-format | 50 ++++++++++++++++++++++++ .gitignore | 1 - .vscode/settings.json | 17 +++++++- MODULE.bazel | 26 ++++++++++-- MODULE.bazel.lock | 6 +-- README.md | 9 +++++ scripts/generate_cpp_compile_commands.sh | 3 ++ 7 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 .clang-format create mode 100755 scripts/generate_cpp_compile_commands.sh diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..4656b8ce --- /dev/null +++ b/.clang-format @@ -0,0 +1,50 @@ +--- +BasedOnStyle: Google +AccessModifierOffset: -2 +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: false +# Empty is required in AllowShortFunctionsOnASingleLine over Inline because Inline contradicts with AUTOSAR rule A7-1-7 +# Such rule is no longer existing in MISRA C++:2023, once we are fully migrated to MISRA C++:2023, switching to Inline +# could be reconsidered +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: Empty +AllowShortLoopsOnASingleLine: false +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBraces: Custom +ColumnLimit: 120 +DerivePointerAlignment: false +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^(<|")(assert|complex|ctype|errno|fenv|float|inttypes|iso646|limits|locale|math|setjmp|signal|stdalign|stdargh|stdatomic|stdbool|stddef|stdint|stdio|stdlib|stdnoreturn|string|tgmath|threads|time|uchar|wchar|wctype)\.h(>|")$' + Priority: 2 + - Regex: '^(<|")(cstdlib|csignal|csetjmp|cstdarg|typeinfo|typeindex|type_traits|bitset|functional|utility|ctime|chrono|cstddef|initializer_list|tuple|any|optional|variant|new|memory|scoped_allocator|memory_resource|climits|cfloat|cstdint|cinttypes|limits|exception|stdexcept|cassert|system_error|cerrno|cctype|cwctype|cstring|cwchar|cuchar|string|string_view|array|vector|deque|list|forward_list|set|map|unordered_set|unordered_map|stack|queue|algorithm|execution|teratorslibrary|iterator|cmath|complex|valarray|random|numeric|ratio|cfenv|iosfwd|ios|istream|ostream|iostream|fstream|sstream|strstream|iomanip|streambuf|cstdio|locale|clocale|codecvt|regex|atomic|thread|mutex|shared_mutex|future|condition_variable|filesystem|ciso646|ccomplex|ctgmath|cstdalign|cstdbool)(>|")$' + Priority: 3 + - Regex: '^(<|").*(>|")$' + Priority: 1 +IndentWidth: 4 +InsertNewlineAtEOF: true +KeepEmptyLinesAtTheStartOfBlocks: true +QualifierAlignment: Left +CommentPragmas: '^.*A2Lfactory:' +--- +# Make sure language specific settings are below the generic settings to be compatible to all languages. +Language: Cpp +Standard: c++17 +... diff --git a/.gitignore b/.gitignore index d68c542c..0691dfdb 100644 --- a/.gitignore +++ b/.gitignore @@ -69,7 +69,6 @@ tests/**/*.html tests/**/*.xml # IDE Code files -.vscode* *.orig .venv_docs MODULE.lock.bazel diff --git a/.vscode/settings.json b/.vscode/settings.json index c2e7f411..cb47140a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,5 +15,20 @@ "rust-analyzer.check.command": "clippy", "rust-analyzer.rustfmt.overrideCommand": [ "${workspaceFolder}/.vscode/rustfmt.sh" - ] + ], + "clangd.arguments": [ + "--header-insertion=never", + "--compile-commands-dir=${workspaceFolder}/", + "--query-driver=**", + "--clang-tidy", + "--fallback-style=None" + ], + "[cpp]": { + "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd", + "editor.formatOnSave": true + }, + "[c]": { + "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd", + "editor.formatOnSave": true + }, } diff --git a/MODULE.bazel b/MODULE.bazel index b2c05ae4..17814a58 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -24,13 +24,13 @@ bazel_dep(name = "buildifier_prebuilt", version = "8.2.0.2") bazel_dep(name = "platforms", version = "1.0.0") bazel_dep(name = "flatbuffers", version = "25.9.23") bazel_dep(name = "download_utils", version = "1.0.1") +bazel_dep(name = "googletest", version = "1.17.0.bcr.1") # S-CORE process rules bazel_dep(name = "score_bazel_platforms", version = "0.0.3") -bazel_dep(name = "score_docs_as_code", version = "2.2.0") +bazel_dep(name = "score_docs_as_code", version = "2.3.0") bazel_dep(name = "score_tooling", version = "1.0.5") bazel_dep(name = "score_rust_policies", version = "0.0.3") -bazel_dep(name = "score_baselibs", version = "0.2.2") bazel_dep(name = "score_process", version = "1.4.0", dev_dependency = True) bazel_dep(name = "score_platform", version = "0.5.1", dev_dependency = True) @@ -41,8 +41,6 @@ bazel_dep(name = "score_toolchains_qnx", version = "0.0.6", dev_dependency = Tru bazel_dep(name = "rust_qnx8_toolchain", version = "1.2.0", dev_dependency = True) bazel_dep(name = "score_toolchains_rust", version = "0.1.1", dev_dependency = True) -bazel_dep(name = "googletest", version = "1.17.0.bcr.1") - # S-CORE crates bazel_dep(name = "score_crates", version = "0.0.6") @@ -106,3 +104,23 @@ use_repo(toolchains_qnx, "toolchains_qnx_qcc") use_repo(toolchains_qnx, "toolchains_qnx_ifs") bazel_dep(name = "score_baselibs_rust", version = "0.0.3") +bazel_dep(name = "score_baselibs", version = "0.2.2") + +git_override( + module_name = "score_baselibs", + commit = "9925dba1fd2ca7f2d33300cd2c01e6af022024cd", + remote = "https://github.com/eclipse-score/baselibs.git", +) + +# Hedron's Compile Commands Extractor for Bazel +# https://github.com/hedronvision/bazel-compile-commands-extractor +bazel_dep(name = "hedron_compile_commands", dev_dependency = True) +git_override( + module_name = "hedron_compile_commands", + remote = "https://github.com/hedronvision/bazel-compile-commands-extractor.git", + commit = "0e990032f3c5a866e72615cf67e5ce22186dcb97", + # Replace the commit hash (above) with the latest (https://github.com/hedronvision/bazel-compile-commands-extractor/commits/main). + # Even better, set up Renovate and let it do the work for you (see "Suggestion: Updates" in the README). +) + + diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 716ee69b..3166601c 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -727,8 +727,6 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_swift/1.16.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_swift/1.18.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_swift/2.1.1/MODULE.bazel": "not found", - "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_baselibs/0.2.2/MODULE.bazel": "3888c6eda7a326395813d049609e1fccb83e2ca09f945372b705d35e3524971f", - "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_baselibs/0.2.2/source.json": "c2eb71e930456d2f8e5b051455a2afa72110e100ac7eed06dd21920a3500d22c", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_baselibs_rust/0.0.3/MODULE.bazel": "5fc61f1f82b5223f61cdd58105d420c12d254ee4370f878539f94704a15c1e97", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_baselibs_rust/0.0.3/source.json": "3be439e9b23651511e835ec89edbb7d18b5d476ade913b24537111f1bf993cc7", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_bazel_platforms/0.0.3/MODULE.bazel": "14c96e378c08705a46abe0799d6236fe3095c342c34f83f8d1b3f6046ce00651", @@ -736,7 +734,6 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_cr_checker/0.2.2/MODULE.bazel": "dc36d9c35543db918c3fb5b93a8e684431f56c7c784cf2a1b90f35802a373c98", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_cr_checker/0.3.1/MODULE.bazel": "f49e037d7fbc0b2a8b2734fc6b47334e8cc8589ca7a5aa0f3ccca85cc5f79fac", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_cr_checker/0.3.1/source.json": "ad038d99c0e2a59cca3a7fa1aac6d87cd0d752314b65b52a91451ab0bd0f7171", - "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_crates/0.0.5/MODULE.bazel": "ca3d1ec0f80d134c5459c17043de2613e1a30d3018b1eeb402a5dd381769200d", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_crates/0.0.6/MODULE.bazel": "da72d24b2afb4456377f7ee13d0d95fb6bfc70dbfb949c7b8676618e661edf61", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_crates/0.0.6/source.json": "835d9f14e0a1d8e06f3c4c006c36c30c20ba428cffb6ad622cb1fbc62b5a13ef", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_dash_license_checker/0.1.1/MODULE.bazel": "76681dbd2d45b5c540869a2337174086c56c54953aab1d02cd878b59d31d13a5", @@ -752,7 +749,8 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/2.0.2/MODULE.bazel": "eda1324a672604fedee96e29ca3324d585085df54a2e49e30527db410c98ff03", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/2.0.3/MODULE.bazel": "9b945514727190d4c381d8965b972884ba04ce105260ffd2b3c9df51f206ebfe", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/2.2.0/MODULE.bazel": "467d9b7f70f3c4f9ba84b5e9718da0272dcf8e30a737173bf79a48f017927744", - "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/2.2.0/source.json": "176af08bcfa30f5857cc6bcdd7fc2d737857d3cd8bc718c09544dba2cbba7d56", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/2.3.0/MODULE.bazel": "e215b29e2a737316af099d2f1372e303641b0720a67a104a286efeb66c92ff14", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_docs_as_code/2.3.0/source.json": "3dfe1c6593e9acab12c6d7ca62bbaf9abbfe7d1c4a5e722dd8bc72f2b5e8fa4f", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_format_checker/0.1.1/MODULE.bazel": "1acc254faa90e9f97b79ac69af25b6c21c561f8d6079914f6352b9b20d26bd37", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_platform/0.1.0/MODULE.bazel": "cc9eae86e76f2a930510ed6e50ec991bb5661687e24881685b39c322087adf6f", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_platform/0.1.1/MODULE.bazel": "eb086ba99f9319371fbbd0a9252dfd27b0817039b88bd4d691602974b1ada005", diff --git a/README.md b/README.md index 73677732..62e0052b 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,15 @@ bazel build --cxxopt=-DLC_LOG_SCORE_MW_LOG //... You can also use the config `--config=x86_64-linux` to build for linux. +## IDE support + +### C++ +Use visual studio code with `clangd`. Make sure You don't have installed MS C++ Intellisense as this is likely to clash with `clangd`. +Then you need to call `./scripts/generate_cpp_compile_commands.sh` to generate compilation DB for clangd and restart it in Vscode. Indexing shall work. + +### Rust + + ### QNX #### Envionment Setup diff --git a/scripts/generate_cpp_compile_commands.sh b/scripts/generate_cpp_compile_commands.sh new file mode 100755 index 00000000..38959767 --- /dev/null +++ b/scripts/generate_cpp_compile_commands.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +bazel run @hedron_compile_commands//:refresh_all \ No newline at end of file From 3f8531d39249cd897d8e3b893eee35392b819200 Mon Sep 17 00:00:00 2001 From: Pawel Rutka Date: Thu, 22 Jan 2026 14:59:10 +0100 Subject: [PATCH 2/5] Create rust FFI layer --- src/health_monitoring_lib/src/common.rs | 73 ++++++++- .../src/deadline/deadline_monitor.rs | 26 +++- src/health_monitoring_lib/src/deadline/ffi.rs | 143 ++++++++++++++++++ src/health_monitoring_lib/src/deadline/mod.rs | 3 + src/health_monitoring_lib/src/ffi.rs | 85 +++++++++++ src/health_monitoring_lib/src/lib.rs | 43 +++++- 6 files changed, 362 insertions(+), 11 deletions(-) create mode 100644 src/health_monitoring_lib/src/deadline/ffi.rs create mode 100644 src/health_monitoring_lib/src/ffi.rs diff --git a/src/health_monitoring_lib/src/common.rs b/src/health_monitoring_lib/src/common.rs index eef86104..c51bcf66 100644 --- a/src/health_monitoring_lib/src/common.rs +++ b/src/health_monitoring_lib/src/common.rs @@ -11,22 +11,44 @@ // SPDX-License-Identifier: Apache-2.0 // ******************************************************************************* -use crate::log::*; use core::time::Duration; /// Unique identifier for deadlines. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, ScoreDebug)] -pub struct IdentTag(&'static str); // 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. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[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. + +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", &bytes) + .finish() + } +} impl From for IdentTag { fn from(value: String) -> Self { - Self(value.leak()) + let leaked = value.leak(); + + Self { + data: leaked.as_ptr(), + len: leaked.len(), + } } } impl From<&str> for IdentTag { fn from(value: &str) -> Self { - Self(value.to_string().leak()) + let leaked = value.to_string().leak(); + + Self { + data: leaked.as_ptr(), + len: leaked.len(), + } } } @@ -42,3 +64,44 @@ impl TimeRange { Self { min, max } } } + +pub(crate) mod ffi { + use core::mem::ManuallyDrop; + use core::ops::{Deref, DerefMut}; + + pub(crate) type FFIHandle = *mut core::ffi::c_void; + + pub(crate) const HM_OK: i32 = 0; + pub(crate) const HM_NOT_FOUND: i32 = HM_OK + 1; + pub(crate) const HM_ALREADY_EXISTS: i32 = HM_OK + 2; + pub(crate) const _HM_INVALID_ARGS: i32 = HM_OK + 3; + pub(crate) const _HM_WRONG_STATE: i32 = HM_OK + 4; + pub(crate) const HM_FAILED: i32 = HM_OK + 5; + + /// A wrapper to represent borrowed data over FFI boundary without taking ownership. + pub(crate) struct FFIBorrowed { + data: ManuallyDrop, + } + + impl FFIBorrowed { + pub(crate) fn new(data: T) -> Self { + Self { + data: ManuallyDrop::new(data), + } + } + } + + impl Deref for FFIBorrowed { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.data + } + } + + impl DerefMut for FFIBorrowed { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.data + } + } +} diff --git a/src/health_monitoring_lib/src/deadline/deadline_monitor.rs b/src/health_monitoring_lib/src/deadline/deadline_monitor.rs index cada5aff..9d4d2beb 100644 --- a/src/health_monitoring_lib/src/deadline/deadline_monitor.rs +++ b/src/health_monitoring_lib/src/deadline/deadline_monitor.rs @@ -61,14 +61,18 @@ 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.deadlines.insert(*tag, range); + self._add_deadline_internal(tag, range); self } /// Builds the DeadlineMonitor with the configured deadlines. - fn build(self, _allocator: &ProtectedMemoryAllocator) -> DeadlineMonitor { + pub(crate) fn build(self, _allocator: &ProtectedMemoryAllocator) -> DeadlineMonitor { DeadlineMonitor::new(self.deadlines) } + + pub(crate) fn _add_deadline_internal(&mut self, tag: &IdentTag, range: TimeRange) { + self.deadlines.insert(*tag, range); + } } pub struct DeadlineMonitor { @@ -83,7 +87,6 @@ pub(crate) enum DeadlineEvaluationError { impl DeadlineMonitor { fn new(deadlines: HashMap) -> Self { - // let active_deadlines: Arc<[DeadlineState]> = (0..deadlines.len()).map(|_| DeadlineState::new()).collect::>().into(); let mut active_deadlines = vec![]; let deadlines = deadlines @@ -96,6 +99,7 @@ impl DeadlineMonitor { .collect(); Self { + #[allow(clippy::arc_with_non_send_sync)] // This will be fixed once we add background thread inner: Arc::new(DeadlineMonitorInner { deadlines, active_deadlines: active_deadlines.into(), @@ -167,6 +171,18 @@ impl Deadline { /// - Err(DeadlineError::DeadlineAlreadyFailed) - if the deadline was already missed before /// pub fn start(&mut self) -> Result, DeadlineError> { + // Safety: We ensure that the caller upholds the safety contract for FFI usage by using &'a mut self lifetime in DeadlineHandle + unsafe { self.start_internal().map(|_| DeadlineHandle(self)) } + } + + /// Starts the deadline - it will be monitored by health monitoring system. + /// This function is provides for FFI usage only! + /// + /// # Safety + /// - Caller must ensure that + /// - Deadline is not used (no call to any api) until it's stopped. basically this means that after this call You shall assure that there + /// is only single owner of the Deadline instance and it does not try to call start before stopping. + pub(super) unsafe fn start_internal(&mut self) -> Result<(), DeadlineError> { let now = self.monitor.now(); let max_time = now + self.range.max.as_millis() as u32; @@ -187,11 +203,11 @@ impl Deadline { warn!("Trying to start deadline {:?} that already failed", self.tag); Err(DeadlineError::DeadlineAlreadyFailed) } else { - Ok(DeadlineHandle(self)) + Ok(()) } } - fn stop_internal(&mut self) { + pub(super) fn stop_internal(&mut self) { let now = self.monitor.now(); let max = self.range.max.as_millis() as u32; let min = self.range.min.as_millis() as u32; diff --git a/src/health_monitoring_lib/src/deadline/ffi.rs b/src/health_monitoring_lib/src/deadline/ffi.rs new file mode 100644 index 00000000..3f92df1e --- /dev/null +++ b/src/health_monitoring_lib/src/deadline/ffi.rs @@ -0,0 +1,143 @@ +use crate::common::ffi::*; +use crate::deadline::deadline_monitor::Deadline; +use crate::deadline::*; +use crate::*; +use core::time::Duration; +use std::os::raw::c_int; + +pub(crate) struct DeadlineMonitorCpp { + monitor: DeadlineMonitor, + // TODO: Here we will keep allocation storage for Deadlines once we implement memory pool + // For now, Deadlines are kept allocated on heap individually +} + +impl DeadlineMonitorCpp { + pub(crate) fn new(monitor: DeadlineMonitor) -> Self { + Self { monitor } + } + + pub(crate) fn get_deadline(&self, tag: IdentTag) -> Result { + match self.monitor.get_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 + let handle = Box::into_raw(Box::new(deadline)); + Ok(handle as FFIHandle) + }, + Err(DeadlineMonitorError::DeadlineInUse) => Err(HM_ALREADY_EXISTS), + Err(DeadlineMonitorError::DeadlineNotFound) => Err(HM_NOT_FOUND), + } + } +} + +#[no_mangle] +pub extern "C" fn deadline_monitor_builder_create() -> FFIHandle { + let builder = DeadlineMonitorBuilder::new(); + let handle = Box::into_raw(Box::new(builder)); + handle as FFIHandle +} + +#[no_mangle] +pub extern "C" fn deadline_monitor_builder_destroy(handle: FFIHandle) { + assert!(!handle.is_null()); + + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `deadline_monitor_builder_create` + // and this must be assured on other side of FFI. + unsafe { + let _ = Box::from_raw(handle as *mut DeadlineMonitorBuilder); + } +} + +#[no_mangle] +pub extern "C" fn deadline_monitor_builder_add_deadline(handle: FFIHandle, tag: *const IdentTag, min: u32, max: u32) { + assert!(!handle.is_null()); + assert!(!tag.is_null()); + + // Safety: We ensure that the pointer is valid. `tag` ptr must be FFI data compatible with IdentTag in Rust + let tag: IdentTag = unsafe { *tag }; // Copy the IdentTag as this shall be trivially copyable + + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `deadline_monitor_builder_create` + // and this must be assured on other side of FFI. + let mut monitor = FFIBorrowed::new(unsafe { Box::from_raw(handle as *mut DeadlineMonitorBuilder) }); + + monitor._add_deadline_internal( + &tag, + TimeRange::new(Duration::from_millis(min as u64), Duration::from_millis(max as u64)), + ); +} + +#[no_mangle] +pub extern "C" fn deadline_monitor_cpp_destroy(handle: FFIHandle) { + assert!(!handle.is_null()); + + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `deadline_monitor_builder_create` + // and this must be assured on other side of FFI. + unsafe { + let _ = Box::from_raw(handle as *mut DeadlineMonitorCpp); + } +} + +#[no_mangle] +pub extern "C" fn deadline_monitor_cpp_get_deadline( + handle: FFIHandle, + tag: *const IdentTag, + out: *mut FFIHandle, +) -> c_int { + assert!(!handle.is_null()); + assert!(!tag.is_null()); + assert!(!out.is_null()); + + // Safety: We ensure that the pointer is valid. `tag` ptr must be FFI data compatible with IdentTag in Rust + let tag: IdentTag = unsafe { *tag }; // Copy the IdentTag as this shall be trivially copyable + + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `deadline_monitor_builder_create` + // and this must be assured on other side of FFI. + let monitor = FFIBorrowed::new(unsafe { Box::from_raw(handle as *mut DeadlineMonitorCpp) }); + let deadline_handle = monitor.get_deadline(tag); + + deadline_handle.map_or_else( + |err_code| err_code, + |handle| { + unsafe { + *out = handle; + } + HM_OK + }, + ) +} + +#[no_mangle] +pub extern "C" fn deadline_start(handle: FFIHandle) -> c_int { + assert!(!handle.is_null()); + + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `deadline_monitor_cpp_get_deadline` + // and this must be assured on other side of FFI. + let mut deadline = FFIBorrowed::new(unsafe { Box::from_raw(handle as *mut Deadline) }); + + // Safety: We ensure at CPP side that a Deadline has move only semantic to not end up in multiple owners of same deadline. + // We also check during start call that previous start/stop sequence was done correctly. + match unsafe { deadline.start_internal() } { + Ok(()) => HM_OK, + Err(_err) => HM_FAILED, + } +} + +#[no_mangle] +pub extern "C" fn deadline_stop(handle: FFIHandle) { + assert!(!handle.is_null()); + + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `deadline_monitor_cpp_get_deadline` + // and this must be assured on other side of FFI. + let mut deadline = FFIBorrowed::new(unsafe { Box::from_raw(handle as *mut Deadline) }); + deadline.stop_internal(); +} + +#[no_mangle] +pub extern "C" fn deadline_destroy(handle: FFIHandle) { + assert!(!handle.is_null()); + + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `deadline_monitor_cpp_get_deadline` + // and this must be assured on other side of FFI. + unsafe { + let _ = Box::from_raw(handle as *mut Deadline); + } +} diff --git a/src/health_monitoring_lib/src/deadline/mod.rs b/src/health_monitoring_lib/src/deadline/mod.rs index 9517ed60..d903c412 100644 --- a/src/health_monitoring_lib/src/deadline/mod.rs +++ b/src/health_monitoring_lib/src/deadline/mod.rs @@ -18,3 +18,6 @@ mod deadline_state; pub use deadline_monitor::{ DeadlineError, DeadlineHandle, DeadlineMonitor, DeadlineMonitorBuilder, DeadlineMonitorError, }; + +// FFI bindings +pub(super) mod ffi; diff --git a/src/health_monitoring_lib/src/ffi.rs b/src/health_monitoring_lib/src/ffi.rs new file mode 100644 index 00000000..b7fa720b --- /dev/null +++ b/src/health_monitoring_lib/src/ffi.rs @@ -0,0 +1,85 @@ +use crate::common::ffi::*; +use crate::deadline::ffi::DeadlineMonitorCpp; +use crate::*; + +#[no_mangle] +extern "C" fn health_monitor_builder_create() -> FFIHandle { + let builder = HealthMonitorBuilder::new(); + let handle = Box::into_raw(Box::new(builder)); + handle as FFIHandle +} + +#[no_mangle] +extern "C" fn health_monitor_builder_destroy(handle: FFIHandle) { + assert!(!handle.is_null()); + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `health_monitor_builder_create` + // and this must be assured on other side of FFI. + unsafe { + let _ = Box::from_raw(handle as *mut HealthMonitorBuilder); + } +} + +#[no_mangle] +extern "C" fn health_monitor_builder_add_deadline_monitor(handle: FFIHandle, tag: *const IdentTag, monitor: FFIHandle) { + assert!(!handle.is_null()); + assert!(!tag.is_null()); + assert!(!monitor.is_null()); + + // Safety: We ensure that the pointer is valid. `tag` ptr must be FFI data compatible with IdentTag in Rust + let tag: IdentTag = unsafe { *tag }; // Copy the IdentTag as this shall be trivially copyable + + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `deadline_monitor_builder_create` + let monitor = unsafe { Box::from_raw(monitor as *mut deadline::DeadlineMonitorBuilder) }; + + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `health_monitor_builder_create` + // and this must be assured on other side of FFI. + let mut health_monitor_builder = FFIBorrowed::new(unsafe { Box::from_raw(handle as *mut HealthMonitorBuilder) }); + + health_monitor_builder.add_deadline_monitor(tag, *monitor); +} + +#[no_mangle] +extern "C" fn health_monitor_builder_build(handle: FFIHandle) -> FFIHandle { + assert!(!handle.is_null()); + + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `health_monitor_builder_create` + // and this must be assured on other side of FFI. + let health_monitor_builder: Box = + unsafe { Box::from_raw(handle as *mut HealthMonitorBuilder) }; + + let health_monitor = health_monitor_builder.build(); + let health_monitor_handle = Box::into_raw(Box::new(health_monitor)); + health_monitor_handle as FFIHandle +} + +#[no_mangle] +extern "C" fn health_monitor_get_deadline_monitor(handle: FFIHandle, tag: *const IdentTag) -> FFIHandle { + assert!(!handle.is_null()); + assert!(!tag.is_null()); + + // Safety: We ensure that the pointer is valid. `tag` ptr must be FFI data compatible with IdentTag in Rust + let tag: IdentTag = unsafe { *tag }; // Copy the IdentTag as this shall be trivially copyable + + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `health_monitor_builder_create` + // and this must be assured on other side of FFI. + let mut health_monitor = FFIBorrowed::new(unsafe { Box::from_raw(handle as *mut HealthMonitor) }); + + if let Some(deadline_monitor) = health_monitor.get_deadline_monitor(&tag) { + let deadline_monitor_handle = Box::into_raw(Box::new(DeadlineMonitorCpp::new(deadline_monitor))); + + deadline_monitor_handle as FFIHandle + } else { + core::ptr::null_mut() + } +} + +#[no_mangle] +extern "C" fn health_monitor_destroy(handle: FFIHandle) { + assert!(!handle.is_null()); + + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `health_monitor_builder_create` + // and this must be assured on other side of FFI. + unsafe { + let _ = Box::from_raw(handle as *mut HealthMonitor); + } +} diff --git a/src/health_monitoring_lib/src/lib.rs b/src/health_monitoring_lib/src/lib.rs index 792d3cd8..af1bded2 100644 --- a/src/health_monitoring_lib/src/lib.rs +++ b/src/health_monitoring_lib/src/lib.rs @@ -10,11 +10,52 @@ // // SPDX-License-Identifier: Apache-2.0 // ******************************************************************************* - mod common; mod log; mod protected_memory; pub mod deadline; +use std::collections::HashMap; + pub use common::{IdentTag, TimeRange}; + +#[derive(Default)] +pub struct HealthMonitorBuilder { + deadlines: HashMap, +} + +impl HealthMonitorBuilder { + pub fn new() -> Self { + Self { + deadlines: HashMap::new(), + } + } + + pub fn add_deadline_monitor(&mut self, tag: IdentTag, monitor: deadline::DeadlineMonitorBuilder) { + self.deadlines.insert(tag, monitor); + } + + pub fn build(self) -> HealthMonitor { + let allocator = protected_memory::ProtectedMemoryAllocator {}; + let mut monitors = HashMap::new(); + for (tag, builder) in self.deadlines { + monitors.insert(tag, builder.build(&allocator)); + } + HealthMonitor { + deadline_monitors: monitors, + } + } +} + +pub struct HealthMonitor { + deadline_monitors: HashMap, +} + +impl HealthMonitor { + pub fn get_deadline_monitor(&mut self, tag: &IdentTag) -> Option { + self.deadline_monitors.remove(tag) + } +} + +mod ffi; From c14bf3c968973d165eea8f6229c20b4d0ba67ae5 Mon Sep 17 00:00:00 2001 From: Pawel Rutka Date: Thu, 22 Jan 2026 14:59:25 +0100 Subject: [PATCH 3/5] Add CPP DeadlineMonitoring API --- README.md | 4 +- src/health_monitoring_lib/BUILD | 52 +++++++- src/health_monitoring_lib/cpp/common.cpp | 69 ++++++++++ .../cpp/deadline/deadline_monitor.cpp | 118 ++++++++++++++++++ src/health_monitoring_lib/cpp/ffi_helpers.h | 29 +++++ .../cpp/health_monitor.cpp | 87 +++++++++++++ .../cpp/include/score/hm/common.h | 117 +++++++++++++++++ .../score/hm/deadline/deadline_monitor.h | 116 +++++++++++++++++ .../cpp/include/score/hm/health_monitor.h | 65 ++++++++++ .../cpp/tests/health_monitor_test.cpp | 51 ++++++++ src/health_monitoring_lib/src/ffi.rs | 2 +- 11 files changed, 706 insertions(+), 4 deletions(-) create mode 100644 src/health_monitoring_lib/cpp/common.cpp create mode 100644 src/health_monitoring_lib/cpp/deadline/deadline_monitor.cpp create mode 100644 src/health_monitoring_lib/cpp/ffi_helpers.h create mode 100644 src/health_monitoring_lib/cpp/health_monitor.cpp create mode 100644 src/health_monitoring_lib/cpp/include/score/hm/common.h create mode 100644 src/health_monitoring_lib/cpp/include/score/hm/deadline/deadline_monitor.h create mode 100644 src/health_monitoring_lib/cpp/include/score/hm/health_monitor.h create mode 100644 src/health_monitoring_lib/cpp/tests/health_monitor_test.cpp diff --git a/README.md b/README.md index 62e0052b..f0fbc37f 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,8 @@ You can also use the config `--config=x86_64-linux` to build for linux. ## IDE support ### C++ -Use visual studio code with `clangd`. Make sure You don't have installed MS C++ Intellisense as this is likely to clash with `clangd`. -Then you need to call `./scripts/generate_cpp_compile_commands.sh` to generate compilation DB for clangd and restart it in Vscode. Indexing shall work. +Use Visual Studio Code with `clangd`. Make sure you don't have the MS C++ IntelliSense extension installed as this is likely to clash with `clangd`. +Then you need to call `./scripts/generate_cpp_compile_commands.sh` to generate compilation DB for clangd and restart it in VS Code. Indexing shall work. ### Rust diff --git a/src/health_monitoring_lib/BUILD b/src/health_monitoring_lib/BUILD index 0cc8957c..c2b8752f 100644 --- a/src/health_monitoring_lib/BUILD +++ b/src/health_monitoring_lib/BUILD @@ -11,7 +11,8 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* -load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test") +load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test", "rust_static_library") +load("@score_baselibs//:bazel/unit_tests.bzl", "cc_gtest_unit_test", "cc_unit_test_suites_for_host_and_qnx") rust_library( name = "health_monitoring_lib", @@ -26,6 +27,20 @@ rust_library( ], ) + +rust_static_library( + name = "health_monitoring_lib_ffi", + srcs = glob(["src/**/*.rs"]), + crate_name = "health_monitoring_lib", + proc_macro_deps = [ + "@score_baselibs_rust//src/testing_macros:score_testing_macros", + ], + visibility = ["//visibility:public"], + deps = [ + "@score_baselibs_rust//src/log/score_log", + ], +) + rust_test( name = "tests", crate = ":health_monitoring_lib", @@ -33,3 +48,38 @@ rust_test( "@score_baselibs_rust//src/log/stdout_logger", ], ) + +cc_library( + name = "health_monitoring_lib_cc", + srcs = [ + "cpp/deadline/deadline_monitor.cpp", + "cpp/health_monitor.cpp", + "cpp/common.cpp", + "cpp/ffi_helpers.h", + ], + hdrs = [ + "cpp/include/score/hm/deadline/deadline_monitor.h", + "cpp/include/score/hm/common.h", + "cpp/include/score/hm/health_monitor.h" + + ], + visibility = ["//visibility:public"], + strip_include_prefix = "cpp/include", + deps = [ + ":health_monitoring_lib_ffi", + "@score_baselibs//score/result", + ], + copts = [ + "-Isrc/health_monitoring_lib/cpp", # private include path + ], +) + +cc_gtest_unit_test( + name = "cpp_tests", + srcs = [ + "cpp/tests/health_monitor_test.cpp", + ], + deps = [ + ":health_monitoring_lib_cc", + ], +) \ No newline at end of file diff --git a/src/health_monitoring_lib/cpp/common.cpp b/src/health_monitoring_lib/cpp/common.cpp new file mode 100644 index 00000000..07d8cec6 --- /dev/null +++ b/src/health_monitoring_lib/cpp/common.cpp @@ -0,0 +1,69 @@ +#include + +namespace score::hm::internal +{ + +DroppableFFIHandle::DroppableFFIHandle(FFIHandle handle, DropFn drop_fn) : handle_(handle), drop_fn_(drop_fn) {} + +DroppableFFIHandle::DroppableFFIHandle(DroppableFFIHandle&& other) noexcept + : handle_(other.handle_), drop_fn_(other.drop_fn_) +{ + other.handle_ = nullptr; + other.drop_fn_ = nullptr; +} + +DroppableFFIHandle& DroppableFFIHandle::operator=(DroppableFFIHandle&& other) noexcept +{ + if (this != &other) + { + // Clean up existing resources + if (drop_fn_) + { + drop_fn_(handle_); + } + + // Move resources from other + handle_ = other.handle_; + drop_fn_ = other.drop_fn_; + + // Nullify other's resources + other.handle_ = nullptr; + other.drop_fn_ = nullptr; + } + return *this; +} + +::score::cpp::optional DroppableFFIHandle::as_rust_handle() const +{ + if (handle_ == nullptr) + { + return ::score::cpp::nullopt; + } + + return handle_; +} + +::score::cpp::optional DroppableFFIHandle::drop_by_rust() +{ + if (handle_ == nullptr) + { + return ::score::cpp::nullopt; + } + + FFIHandle temp = handle_; + handle_ = nullptr; + drop_fn_ = nullptr; + + return temp; +} + +DroppableFFIHandle::~DroppableFFIHandle() +{ + // Clean up resources associated with the FFI handle + if (drop_fn_) + { + drop_fn_(handle_); + } +} + +} // namespace score::hm::internal diff --git a/src/health_monitoring_lib/cpp/deadline/deadline_monitor.cpp b/src/health_monitoring_lib/cpp/deadline/deadline_monitor.cpp new file mode 100644 index 00000000..6d08b8d0 --- /dev/null +++ b/src/health_monitoring_lib/cpp/deadline/deadline_monitor.cpp @@ -0,0 +1,118 @@ +#include "score/hm/deadline/deadline_monitor.h" +#include "ffi_helpers.h" + +extern "C" { +using namespace score::hm; +using namespace score::hm::internal; +using namespace score::hm::deadline; + +internal::FFIHandle deadline_monitor_builder_create(); +void deadline_monitor_builder_destroy(internal::FFIHandle handle); +void deadline_monitor_builder_add_deadline(internal::FFIHandle handler, + const IdentTag* tag, + uint32_t min, + uint32_t max); +int deadline_monitor_cpp_get_deadline(FFIHandle handler, const IdentTag* tag, FFIHandle* out); +void deadline_monitor_cpp_destroy(FFIHandle handler); +void deadline_destroy(FFIHandle deadline_handle); +int deadline_start(FFIHandle deadline_handle); +void deadline_stop(FFIHandle deadline_handle); +} + +namespace score::hm::deadline +{ +DeadlineMonitorBuilder::DeadlineMonitorBuilder() + : monitor_builder_handler_(deadline_monitor_builder_create(), &deadline_monitor_builder_destroy) +{ +} + +DeadlineMonitorBuilder DeadlineMonitorBuilder::add_deadline(const IdentTag& tag, const TimeRange& range) && +{ + auto handle = monitor_builder_handler_.as_rust_handle(); + SCORE_LANGUAGE_FUTURECPP_PRECONDITION(handle.has_value()); + + deadline_monitor_builder_add_deadline(handle.value(), &tag, range.min_as_u32(), range.max_as_u32()); + + return std::move(*this); +} + +DeadlineMonitor::DeadlineMonitor(FFIHandle handle) : monitor_handle_(handle, &deadline_monitor_cpp_destroy) {} + +score::cpp::expected DeadlineMonitor::get_deadline(const IdentTag& tag) +{ + auto handle = monitor_handle_.as_rust_handle(); + SCORE_LANGUAGE_FUTURECPP_PRECONDITION(handle.has_value()); + + internal::FFIHandle ret = nullptr; + auto result = deadline_monitor_cpp_get_deadline(handle.value(), &tag, &ret); + + if (result != kSuccess) + { + return score::cpp::unexpected(::score::hm::ffi::fromRustError(result)); + } + + return score::cpp::expected(Deadline{ret}); +} + +Deadline::Deadline(internal::FFIHandle handle) : deadline_handle_(handle, &deadline_destroy), has_handle_(false) {} + +Deadline::~Deadline() +{ + SCORE_LANGUAGE_FUTURECPP_PRECONDITION(!has_handle_); +} + +score::cpp::expected Deadline::start() +{ + if (has_handle_) + { + return score::cpp::unexpected(::score::hm::Error::WrongState); + } + + auto handle = deadline_handle_.as_rust_handle(); + SCORE_LANGUAGE_FUTURECPP_PRECONDITION(handle.has_value()); + + auto result = deadline_start(handle.value()); + if (result != kSuccess) + { + return score::cpp::unexpected(::score::hm::ffi::fromRustError(result)); + } + + has_handle_ = true; + return score::cpp::expected(DeadlineHandle{*this}); +} + +DeadlineHandle::DeadlineHandle(Deadline& deadline) : was_stopped_(false), deadline_(deadline) {} + +void DeadlineHandle::stop() +{ + SCORE_LANGUAGE_FUTURECPP_PRECONDITION(deadline_.has_value()); + + if (!was_stopped_) + { + was_stopped_ = true; + auto handle = deadline_.value().get().deadline_handle_.as_rust_handle(); + SCORE_LANGUAGE_FUTURECPP_PRECONDITION(handle.has_value()); + + deadline_stop(handle.value()); + } +} + +DeadlineHandle::DeadlineHandle(DeadlineHandle&& other) + : was_stopped_(other.was_stopped_), deadline_(std::move(other.deadline_)) +{ + other.was_stopped_ = true; + other.deadline_ = ::score::cpp::optional>{}; // None +} + +DeadlineHandle::~DeadlineHandle() +{ + if (!deadline_.has_value()) + { + return; + } + + stop(); + deadline_.value().get().has_handle_ = false; +} + +} // namespace score::hm::deadline diff --git a/src/health_monitoring_lib/cpp/ffi_helpers.h b/src/health_monitoring_lib/cpp/ffi_helpers.h new file mode 100644 index 00000000..a8f78ef8 --- /dev/null +++ b/src/health_monitoring_lib/cpp/ffi_helpers.h @@ -0,0 +1,29 @@ +#ifndef SCORE_HM_FFI_HELPERS_HPP +#define SCORE_HM_FFI_HELPERS_HPP + +namespace score::hm::ffi +{ + +inline Error fromRustError(int ffi_error_code) +{ + switch (ffi_error_code) + { + case 1: + return Error::NotFound; + case 2: + return Error::AlreadyExists; + case 3: + return Error::InvalidArgument; + case 4: + return Error::WrongState; + case 5: + return Error::Failed; + default: + assert(false && "Unknown FFI error code"); + return Error::InvalidArgument; // Fallback + } +} + +} // namespace score::hm::ffi + +#endif // SCORE_HM_FFI_HELPERS_HPP diff --git a/src/health_monitoring_lib/cpp/health_monitor.cpp b/src/health_monitoring_lib/cpp/health_monitor.cpp new file mode 100644 index 00000000..48a03cfc --- /dev/null +++ b/src/health_monitoring_lib/cpp/health_monitor.cpp @@ -0,0 +1,87 @@ +#include "score/hm/health_monitor.h" + +extern "C" { +using namespace score::hm; + +internal::FFIHandle health_monitor_builder_create(); +void health_monitor_builder_destroy(internal::FFIHandle handler); + +internal::FFIHandle health_monitor_builder_build(internal::FFIHandle health_monitor_builder_handle); +void health_monitor_builder_add_deadline_monitor(internal::FFIHandle handle, + const IdentTag* tag, + internal::FFIHandle monitor_handle); + +internal::FFIHandle health_monitor_get_deadline_monitor(internal::FFIHandle health_monitor_handle, const IdentTag* tag); + +void health_monitor_destroy(internal::FFIHandle handler); +} + +namespace score::hm +{ + +HealthMonitorBuilder::HealthMonitorBuilder() + : health_monitor_builder_handle_{health_monitor_builder_create(), &health_monitor_builder_destroy} +{ +} + +HealthMonitorBuilder HealthMonitorBuilder::add_deadline_monitor(const IdentTag& tag, + deadline::DeadlineMonitorBuilder&& monitor) && +{ + auto monitor_handle = monitor.drop_by_rust(); + SCORE_LANGUAGE_FUTURECPP_PRECONDITION(monitor_handle.has_value()); + SCORE_LANGUAGE_FUTURECPP_PRECONDITION(health_monitor_builder_handle_.as_rust_handle().has_value()); + + health_monitor_builder_add_deadline_monitor( + health_monitor_builder_handle_.as_rust_handle().value(), &tag, monitor_handle.value()); + return std::move(*this); +} + +HealthMonitor HealthMonitorBuilder::build() && +{ + auto handle = health_monitor_builder_handle_.drop_by_rust(); + SCORE_LANGUAGE_FUTURECPP_PRECONDITION(handle.has_value()); + + return HealthMonitor(health_monitor_builder_build(handle.value())); +} + +HealthMonitor::HealthMonitor(internal::FFIHandle handle) : health_monitor_(handle) +{ + // Initialize health monitor +} + +score::cpp::expected HealthMonitor::get_deadline_monitor(const IdentTag& tag) +{ + auto maybe_monitor = health_monitor_get_deadline_monitor(health_monitor_, &tag); + + if (maybe_monitor != nullptr) + { + + return score::cpp::expected(deadline::DeadlineMonitor{maybe_monitor}); + } + + return score::cpp::unexpected(Error::NotFound); +} + +HealthMonitor::~HealthMonitor() +{ + if (health_monitor_ != nullptr) + { + health_monitor_destroy(health_monitor_); + } +} + +HealthMonitor& HealthMonitor::operator=(HealthMonitor&& other) +{ + if (this != &other) + { + if (health_monitor_ != nullptr) + { + health_monitor_destroy(health_monitor_); + } + health_monitor_ = std::move(other.health_monitor_); + other.health_monitor_ = nullptr; + } + return *this; +} + +} // namespace score::hm diff --git a/src/health_monitoring_lib/cpp/include/score/hm/common.h b/src/health_monitoring_lib/cpp/include/score/hm/common.h new file mode 100644 index 00000000..5df4a958 --- /dev/null +++ b/src/health_monitoring_lib/cpp/include/score/hm/common.h @@ -0,0 +1,117 @@ +#ifndef SCORE_HM_COMMON_H +#define SCORE_HM_COMMON_H + +#include +#include +#include +#include +#include +#include +namespace score::hm +{ + +constexpr int kSuccess = 0; + +enum class Error +{ + NotFound = kSuccess + 1, + AlreadyExists = kSuccess + 2, + InvalidArgument = kSuccess + 3, + WrongState = kSuccess + 4, + Failed = kSuccess + 5 +}; + +/// +/// 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. +/// +class TimeRange +{ + public: + TimeRange(std::chrono::milliseconds min_ms, std::chrono::milliseconds max_ms) : min_ms(min_ms), max_ms(max_ms) {} + + const uint32_t min_as_u32() const + { + return min_ms.count(); + } + + const uint32_t max_as_u32() const + { + return max_ms.count(); + } + + private: + const std::chrono::milliseconds min_ms; + const std::chrono::milliseconds max_ms; +}; + +/// FFI internal helpers +namespace internal +{ + +/// Opaque handle type for Rust managed object +using FFIHandle = void*; + +/// Droppable wrapper that denotes that the object can be dropped by Rust side +template +class RustDroppable +{ + public: + ~RustDroppable() = default; + + /// Marks object as no longer managed by C++ side, releasing handle to be passed to Rust side for dropping + ::score::cpp::optional drop_by_rust() + { + return static_cast(this)->__drop_by_rust_impl(); + } +}; + +/// Wrapper for FFIHandle that ensures proper dropping via provided drop function +class DroppableFFIHandle +{ + public: + using DropFn = void (*)(FFIHandle); + + DroppableFFIHandle(FFIHandle handle, DropFn drop_fn); + + DroppableFFIHandle(const DroppableFFIHandle&) = delete; + DroppableFFIHandle& operator=(const DroppableFFIHandle&) = delete; + + DroppableFFIHandle(DroppableFFIHandle&& other) noexcept; + DroppableFFIHandle& operator=(DroppableFFIHandle&& other) noexcept; + + /// Get the underlying FFI handle if it was not dropped before + ::score::cpp::optional as_rust_handle() const; + + /// Marks object as no longer managed by C++ side, releasing handle to be passed to Rust side for dropping + ::score::cpp::optional drop_by_rust(); + + ~DroppableFFIHandle(); + + private: + FFIHandle handle_; + DropFn drop_fn_; +}; + +} // namespace internal + +} // namespace score::hm + +#endif // SCORE_HM_COMMON_H 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 new file mode 100644 index 00000000..db8557bb --- /dev/null +++ b/src/health_monitoring_lib/cpp/include/score/hm/deadline/deadline_monitor.h @@ -0,0 +1,116 @@ +#ifndef SCORE_HM_DEADLINE_DEADLINE_MONITOR_H +#define SCORE_HM_DEADLINE_DEADLINE_MONITOR_H + +#include +#include + +namespace score::hm +{ +// Forward declaration +class HealthMonitor; +} // namespace score::hm + +namespace score::hm::deadline +{ + +// Forward declaration +class DeadlineMonitor; +class DeadlineHandle; +class Deadline; + +/// DeadlineMonitorBuilder for constructing DeadlineMonitor instance +class DeadlineMonitorBuilder : public internal::RustDroppable +{ + public: + /// Creates a new DeadlineMonitorBuilder + DeadlineMonitorBuilder(); + + DeadlineMonitorBuilder(const DeadlineMonitorBuilder&) = delete; + DeadlineMonitorBuilder& operator=(const DeadlineMonitorBuilder&) = delete; + + DeadlineMonitorBuilder(DeadlineMonitorBuilder&&) = default; + DeadlineMonitorBuilder& operator=(DeadlineMonitorBuilder&&) = delete; + + /// Adds a deadline with the given tag and duration range to the monitor. + DeadlineMonitorBuilder add_deadline(const IdentTag& tag, const TimeRange& range) &&; + + ::score::cpp::optional __drop_by_rust_impl() + { + return monitor_builder_handler_.drop_by_rust(); + } + + private: + internal::DroppableFFIHandle monitor_builder_handler_; +}; + +class DeadlineMonitor +{ + public: + // Delete copy, allow move + DeadlineMonitor(const DeadlineMonitor&) = delete; + DeadlineMonitor& operator=(const DeadlineMonitor&) = delete; + + DeadlineMonitor(DeadlineMonitor&& other) noexcept = default; + DeadlineMonitor& operator=(DeadlineMonitor&& other) noexcept = default; + + ::score::cpp::expected get_deadline(const IdentTag& tag); + + private: + explicit DeadlineMonitor(internal::FFIHandle handle); + + friend class score::hm::HealthMonitor; + internal::DroppableFFIHandle monitor_handle_; +}; + +/// Deadline instance representing a specific deadline to be monitored. +class Deadline +{ + public: + ~Deadline(); + + Deadline(const Deadline&) = delete; + Deadline& operator=(const Deadline&) = delete; + + Deadline(Deadline&& other) noexcept = default; + Deadline& operator=(Deadline&& other) noexcept = delete; + + /// Starts the deadline monitoring. Returns a DeadlineHandle to manage the deadline. + // After this call the Deadline instance cannot be used until connected DeadlineHandle is destroyed + ::score::cpp::expected start(); + + private: + explicit Deadline(internal::FFIHandle handle); + + friend class DeadlineMonitor; + friend class DeadlineHandle; + internal::DroppableFFIHandle deadline_handle_; + bool has_handle_; +}; + +/// Deadline guard to manage the lifetime of a started deadline. +class DeadlineHandle +{ + public: + /// Stops the deadline monitoring. + void stop(); + + /// Destructor that ensures the deadline is stopped if not already done. + ~DeadlineHandle(); + + DeadlineHandle(const DeadlineHandle&) = delete; + DeadlineHandle& operator=(const DeadlineHandle&) = delete; + + DeadlineHandle(DeadlineHandle&& other); + DeadlineHandle& operator=(DeadlineHandle&& other) = delete; + + private: + DeadlineHandle(Deadline& deadline); + + friend class Deadline; + bool was_stopped_; + ::score::cpp::optional> deadline_; +}; + +} // namespace score::hm::deadline + +#endif // SCORE_HM_DEADLINE_DEADLINE_MONITOR_H 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 new file mode 100644 index 00000000..d27d0a44 --- /dev/null +++ b/src/health_monitoring_lib/cpp/include/score/hm/health_monitor.h @@ -0,0 +1,65 @@ +#ifndef SCORE_HM_HEALTH_MONITOR_H +#define SCORE_HM_HEALTH_MONITOR_H + +#include +#include + +namespace score::hm +{ + +class HealthMonitor; + +/// +/// Builder for HealthMonitor instances. +/// +class HealthMonitorBuilder +{ + public: + /// Creates a new HealthMonitorBuilder + HealthMonitorBuilder(); + + ~HealthMonitorBuilder() = default; + HealthMonitorBuilder(const HealthMonitorBuilder&) = delete; + HealthMonitorBuilder& operator=(const HealthMonitorBuilder&) = delete; + + HealthMonitorBuilder(HealthMonitorBuilder&&) = default; + 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) &&; + + /// Builds and returns the HealthMonitor instance. + HealthMonitor build() &&; + + private: + internal::DroppableFFIHandle health_monitor_builder_handle_; +}; + +class HealthMonitor +{ + public: + HealthMonitor(const HealthMonitor&) = delete; + HealthMonitor& operator=(const HealthMonitor&) = delete; + HealthMonitor(HealthMonitor&& other) + { + health_monitor_ = std::move(other.health_monitor_); + other.health_monitor_ = nullptr; + } + + HealthMonitor& operator=(HealthMonitor&&); + + ~HealthMonitor(); + + score::cpp::expected get_deadline_monitor(const IdentTag& tag); + + private: + friend class HealthMonitorBuilder; + + HealthMonitor(internal::FFIHandle handle); + + internal::FFIHandle health_monitor_; +}; + +} // namespace score::hm + +#endif // SCORE_HM_HEALTH_MONITOR_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 new file mode 100644 index 00000000..3e3420df --- /dev/null +++ b/src/health_monitoring_lib/cpp/tests/health_monitor_test.cpp @@ -0,0 +1,51 @@ +#include "score/hm/health_monitor.h" +#include "score/hm/common.h" + +#include +#include + +using namespace score::hm; +using ::testing::_; + +class HealthMonitorTest : public ::testing::Test +{ +}; + +// For first review round, only single test case to show up API +TEST_F(HealthMonitorTest, TestName) +{ + ::testing::GTEST_FLAG(catch_exceptions) = false; + ::testing::GTEST_FLAG(print_time) = true; + + 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"); + + auto hm = HealthMonitorBuilder().add_deadline_monitor(ident, std::move(builder_mon)).build(); + + auto deadline_monitor_res = hm.get_deadline_monitor(ident); + EXPECT_TRUE(deadline_monitor_res.has_value()); + + { + // Try again to get the same monitor + auto deadline_monitor_res = hm.get_deadline_monitor(ident); + EXPECT_FALSE(deadline_monitor_res.has_value()); + } + + auto deadline_mon = std::move(*deadline_monitor_res); + + // std::cout << "Getting deadline" << std::endl; + + auto deadline_res = deadline_mon.get_deadline(IdentTag("deadline_1")); + + { + auto deadline_guard = deadline_res.value().start().value(); + + EXPECT_EQ(deadline_res.value().start().error(), ::score::hm::Error::WrongState); + deadline_guard.stop(); + } +} diff --git a/src/health_monitoring_lib/src/ffi.rs b/src/health_monitoring_lib/src/ffi.rs index b7fa720b..cbeea9c0 100644 --- a/src/health_monitoring_lib/src/ffi.rs +++ b/src/health_monitoring_lib/src/ffi.rs @@ -77,7 +77,7 @@ extern "C" fn health_monitor_get_deadline_monitor(handle: FFIHandle, tag: *const extern "C" fn health_monitor_destroy(handle: FFIHandle) { assert!(!handle.is_null()); - // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `health_monitor_builder_create` + // Safety: We ensure that the pointer is valid. We assume that pointer was created by call to `health_monitor_builder_build` // and this must be assured on other side of FFI. unsafe { let _ = Box::from_raw(handle as *mut HealthMonitor); From b9c92b8445bcccbc91f2a23284be82f2b8fe8704 Mon Sep 17 00:00:00 2001 From: Pawel Rutka Date: Thu, 22 Jan 2026 15:12:25 +0100 Subject: [PATCH 4/5] Fix formatting, copyrights --- .clang-format | 2 -- MODULE.bazel | 15 +++++------- MODULE.bazel.lock | 3 +++ src/health_monitoring_lib/BUILD | 24 +++++++++---------- src/health_monitoring_lib/cpp/common.cpp | 12 ++++++++++ .../cpp/deadline/deadline_monitor.cpp | 12 ++++++++++ src/health_monitoring_lib/cpp/ffi_helpers.h | 12 ++++++++++ .../cpp/health_monitor.cpp | 12 ++++++++++ .../cpp/include/score/hm/common.h | 12 ++++++++++ .../score/hm/deadline/deadline_monitor.h | 12 ++++++++++ .../cpp/include/score/hm/health_monitor.h | 12 ++++++++++ .../cpp/tests/health_monitor_test.cpp | 12 ++++++++++ src/health_monitoring_lib/src/common.rs | 20 ++++++++++++++-- src/health_monitoring_lib/src/deadline/ffi.rs | 12 ++++++++++ src/health_monitoring_lib/src/ffi.rs | 12 ++++++++++ 15 files changed, 158 insertions(+), 26 deletions(-) diff --git a/.clang-format b/.clang-format index 4656b8ce..900517a2 100644 --- a/.clang-format +++ b/.clang-format @@ -1,4 +1,3 @@ ---- BasedOnStyle: Google AccessModifierOffset: -2 AllowAllParametersOfDeclarationOnNextLine: false @@ -47,4 +46,3 @@ CommentPragmas: '^.*A2Lfactory:' # Make sure language specific settings are below the generic settings to be compatible to all languages. Language: Cpp Standard: c++17 -... diff --git a/MODULE.bazel b/MODULE.bazel index 17814a58..6a2de25d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -105,22 +105,19 @@ use_repo(toolchains_qnx, "toolchains_qnx_ifs") bazel_dep(name = "score_baselibs_rust", version = "0.0.3") bazel_dep(name = "score_baselibs", version = "0.2.2") - -git_override( - module_name = "score_baselibs", - commit = "9925dba1fd2ca7f2d33300cd2c01e6af022024cd", - remote = "https://github.com/eclipse-score/baselibs.git", -) +# git_override( +# module_name = "score_baselibs", +# commit = "9925dba1fd2ca7f2d33300cd2c01e6af022024cd", +# remote = "https://github.com/eclipse-score/baselibs.git", +# ) # Hedron's Compile Commands Extractor for Bazel # https://github.com/hedronvision/bazel-compile-commands-extractor bazel_dep(name = "hedron_compile_commands", dev_dependency = True) git_override( module_name = "hedron_compile_commands", - remote = "https://github.com/hedronvision/bazel-compile-commands-extractor.git", commit = "0e990032f3c5a866e72615cf67e5ce22186dcb97", + remote = "https://github.com/hedronvision/bazel-compile-commands-extractor.git", # Replace the commit hash (above) with the latest (https://github.com/hedronvision/bazel-compile-commands-extractor/commits/main). # Even better, set up Renovate and let it do the work for you (see "Suggestion: Updates" in the README). ) - - diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 3166601c..3e1a468b 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -727,6 +727,8 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_swift/1.16.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_swift/1.18.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/rules_swift/2.1.1/MODULE.bazel": "not found", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_baselibs/0.2.2/MODULE.bazel": "3888c6eda7a326395813d049609e1fccb83e2ca09f945372b705d35e3524971f", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_baselibs/0.2.2/source.json": "c2eb71e930456d2f8e5b051455a2afa72110e100ac7eed06dd21920a3500d22c", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_baselibs_rust/0.0.3/MODULE.bazel": "5fc61f1f82b5223f61cdd58105d420c12d254ee4370f878539f94704a15c1e97", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_baselibs_rust/0.0.3/source.json": "3be439e9b23651511e835ec89edbb7d18b5d476ade913b24537111f1bf993cc7", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_bazel_platforms/0.0.3/MODULE.bazel": "14c96e378c08705a46abe0799d6236fe3095c342c34f83f8d1b3f6046ce00651", @@ -734,6 +736,7 @@ "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_cr_checker/0.2.2/MODULE.bazel": "dc36d9c35543db918c3fb5b93a8e684431f56c7c784cf2a1b90f35802a373c98", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_cr_checker/0.3.1/MODULE.bazel": "f49e037d7fbc0b2a8b2734fc6b47334e8cc8589ca7a5aa0f3ccca85cc5f79fac", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_cr_checker/0.3.1/source.json": "ad038d99c0e2a59cca3a7fa1aac6d87cd0d752314b65b52a91451ab0bd0f7171", + "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_crates/0.0.5/MODULE.bazel": "ca3d1ec0f80d134c5459c17043de2613e1a30d3018b1eeb402a5dd381769200d", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_crates/0.0.6/MODULE.bazel": "da72d24b2afb4456377f7ee13d0d95fb6bfc70dbfb949c7b8676618e661edf61", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_crates/0.0.6/source.json": "835d9f14e0a1d8e06f3c4c006c36c30c20ba428cffb6ad622cb1fbc62b5a13ef", "https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/modules/score_dash_license_checker/0.1.1/MODULE.bazel": "76681dbd2d45b5c540869a2337174086c56c54953aab1d02cd878b59d31d13a5", diff --git a/src/health_monitoring_lib/BUILD b/src/health_monitoring_lib/BUILD index c2b8752f..8e113d66 100644 --- a/src/health_monitoring_lib/BUILD +++ b/src/health_monitoring_lib/BUILD @@ -11,7 +11,7 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* -load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test", "rust_static_library") +load("@rules_rust//rust:defs.bzl", "rust_library", "rust_static_library", "rust_test") load("@score_baselibs//:bazel/unit_tests.bzl", "cc_gtest_unit_test", "cc_unit_test_suites_for_host_and_qnx") rust_library( @@ -27,7 +27,6 @@ rust_library( ], ) - rust_static_library( name = "health_monitoring_lib_ffi", srcs = glob(["src/**/*.rs"]), @@ -52,26 +51,25 @@ rust_test( cc_library( name = "health_monitoring_lib_cc", srcs = [ - "cpp/deadline/deadline_monitor.cpp", - "cpp/health_monitor.cpp", "cpp/common.cpp", + "cpp/deadline/deadline_monitor.cpp", "cpp/ffi_helpers.h", - ], + "cpp/health_monitor.cpp", + ], hdrs = [ - "cpp/include/score/hm/deadline/deadline_monitor.h", "cpp/include/score/hm/common.h", - "cpp/include/score/hm/health_monitor.h" - + "cpp/include/score/hm/deadline/deadline_monitor.h", + "cpp/include/score/hm/health_monitor.h", + ], + copts = [ + "-Isrc/health_monitoring_lib/cpp", # private include path ], - visibility = ["//visibility:public"], strip_include_prefix = "cpp/include", + visibility = ["//visibility:public"], deps = [ ":health_monitoring_lib_ffi", "@score_baselibs//score/result", ], - copts = [ - "-Isrc/health_monitoring_lib/cpp", # private include path - ], ) cc_gtest_unit_test( @@ -82,4 +80,4 @@ cc_gtest_unit_test( deps = [ ":health_monitoring_lib_cc", ], -) \ No newline at end of file +) diff --git a/src/health_monitoring_lib/cpp/common.cpp b/src/health_monitoring_lib/cpp/common.cpp index 07d8cec6..d85cfbec 100644 --- a/src/health_monitoring_lib/cpp/common.cpp +++ b/src/health_monitoring_lib/cpp/common.cpp @@ -1,3 +1,15 @@ +/******************************************************************************** + * 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 namespace score::hm::internal diff --git a/src/health_monitoring_lib/cpp/deadline/deadline_monitor.cpp b/src/health_monitoring_lib/cpp/deadline/deadline_monitor.cpp index 6d08b8d0..b126ca5b 100644 --- a/src/health_monitoring_lib/cpp/deadline/deadline_monitor.cpp +++ b/src/health_monitoring_lib/cpp/deadline/deadline_monitor.cpp @@ -1,3 +1,15 @@ +/******************************************************************************** + * 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 "score/hm/deadline/deadline_monitor.h" #include "ffi_helpers.h" diff --git a/src/health_monitoring_lib/cpp/ffi_helpers.h b/src/health_monitoring_lib/cpp/ffi_helpers.h index a8f78ef8..96bf54c4 100644 --- a/src/health_monitoring_lib/cpp/ffi_helpers.h +++ b/src/health_monitoring_lib/cpp/ffi_helpers.h @@ -1,3 +1,15 @@ +/******************************************************************************** + * 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_FFI_HELPERS_HPP #define SCORE_HM_FFI_HELPERS_HPP diff --git a/src/health_monitoring_lib/cpp/health_monitor.cpp b/src/health_monitoring_lib/cpp/health_monitor.cpp index 48a03cfc..abefd17c 100644 --- a/src/health_monitoring_lib/cpp/health_monitor.cpp +++ b/src/health_monitoring_lib/cpp/health_monitor.cpp @@ -1,3 +1,15 @@ +/******************************************************************************** + * 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 "score/hm/health_monitor.h" extern "C" { 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 5df4a958..a45d5e42 100644 --- a/src/health_monitoring_lib/cpp/include/score/hm/common.h +++ b/src/health_monitoring_lib/cpp/include/score/hm/common.h @@ -1,3 +1,15 @@ +/******************************************************************************** + * 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_COMMON_H #define SCORE_HM_COMMON_H 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 db8557bb..220d6956 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 @@ -1,3 +1,15 @@ +/******************************************************************************** + * 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_DEADLINE_DEADLINE_MONITOR_H #define SCORE_HM_DEADLINE_DEADLINE_MONITOR_H 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 d27d0a44..abe2e227 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 @@ -1,3 +1,15 @@ +/******************************************************************************** + * 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_HEALTH_MONITOR_H #define SCORE_HM_HEALTH_MONITOR_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 3e3420df..4699eafa 100644 --- a/src/health_monitoring_lib/cpp/tests/health_monitor_test.cpp +++ b/src/health_monitoring_lib/cpp/tests/health_monitor_test.cpp @@ -1,3 +1,15 @@ +/******************************************************************************** + * 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 "score/hm/health_monitor.h" #include "score/hm/common.h" diff --git a/src/health_monitoring_lib/src/common.rs b/src/health_monitoring_lib/src/common.rs index c51bcf66..882bfea2 100644 --- a/src/health_monitoring_lib/src/common.rs +++ b/src/health_monitoring_lib/src/common.rs @@ -11,21 +11,37 @@ // SPDX-License-Identifier: Apache-2.0 // ******************************************************************************* +use core::hash::Hash; use core::time::Duration; /// Unique identifier for deadlines. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, 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. +// 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", &bytes) + .field("data", unsafe { &core::str::from_utf8_unchecked(bytes) }) // Safety: The underlying data was created out of valid str .finish() } } diff --git a/src/health_monitoring_lib/src/deadline/ffi.rs b/src/health_monitoring_lib/src/deadline/ffi.rs index 3f92df1e..f0e151a3 100644 --- a/src/health_monitoring_lib/src/deadline/ffi.rs +++ b/src/health_monitoring_lib/src/deadline/ffi.rs @@ -1,3 +1,15 @@ +// ******************************************************************************* +// 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::common::ffi::*; use crate::deadline::deadline_monitor::Deadline; use crate::deadline::*; diff --git a/src/health_monitoring_lib/src/ffi.rs b/src/health_monitoring_lib/src/ffi.rs index cbeea9c0..36c90828 100644 --- a/src/health_monitoring_lib/src/ffi.rs +++ b/src/health_monitoring_lib/src/ffi.rs @@ -1,3 +1,15 @@ +// ******************************************************************************* +// 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::common::ffi::*; use crate::deadline::ffi::DeadlineMonitorCpp; use crate::*; From 85ecdb7ca7a74df37e8b951c71527c8c9dfd547c Mon Sep 17 00:00:00 2001 From: Pawel Rutka Date: Fri, 23 Jan 2026 08:54:01 +0100 Subject: [PATCH 5/5] Fix QNX8 build --- MODULE.bazel.lock | 47 +++++++++++++++++++++++++++++++++ src/health_monitoring_lib/BUILD | 4 +++ 2 files changed, 51 insertions(+) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 3e1a468b..6babb4e0 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -6619,6 +6619,53 @@ ] ] } + }, + "@@score_toolchains_qnx+//:extensions.bzl%toolchains_qnx": { + "general": { + "bzlTransitiveDigest": "F6y2fAJJUfV3b6FNSGJSyi+Pa7AqT9NG+AhWCIySUwA=", + "usagesDigest": "57vskEtnheV4LMUX6fJDRfsaRXNH2xz9eQ0xsOMu6y8=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "toolchains_qnx_sdp": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://www.qnx.com/download/download/79858/installation.tgz" + ], + "build_file": "@@score_toolchains_qnx+//toolchains:sdp.BUILD", + "sha256": "f2e0cb21c6baddbcb65f6a70610ce498e7685de8ea2e0f1648f01b327f6bac63", + "strip_prefix": "installation" + } + }, + "toolchains_qnx_qcc": { + "repoRuleId": "@@score_toolchains_qnx+//toolchains:rules.bzl%qcc_toolchain", + "attributes": { + "sdp_repo": "toolchains_qnx_sdp", + "qcc_version": "12.2.0", + "sdp_version": "8.0.0", + "qnx_version_constraint": "@@score_bazel_platforms+//:qnx8_0", + "default_license_server": "" + } + }, + "toolchains_qnx_ifs": { + "repoRuleId": "@@score_toolchains_qnx+//toolchains:rules.bzl%ifs_toolchain", + "attributes": { + "sdp_repo": "toolchains_qnx_sdp", + "qnx_version_constraint": "@@score_bazel_platforms+//:qnx8_0", + "default_license_server": "" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "score_toolchains_qnx+", + "bazel_tools", + "bazel_tools" + ] + ] + } } } } diff --git a/src/health_monitoring_lib/BUILD b/src/health_monitoring_lib/BUILD index 8e113d66..82909df8 100644 --- a/src/health_monitoring_lib/BUILD +++ b/src/health_monitoring_lib/BUILD @@ -77,6 +77,10 @@ cc_gtest_unit_test( srcs = [ "cpp/tests/health_monitor_test.cpp", ], + linkopts = select({ + "@platforms//os:qnx": ["-lsocket"], + "//conditions:default": [], + }), deps = [ ":health_monitoring_lib_cc", ],