Skip to content

Conversation

@pawelrutkaq
Copy link
Contributor

@pawelrutkaq pawelrutkaq commented Jan 20, 2026

  • No protected memory implementation yet, but a small infrastructure has been prepared
  • #![allow(dead_code)] needed until there is no consumer of API

Closes #12

@github-actions
Copy link

github-actions bot commented Jan 20, 2026

License Check Results

🚀 The license check job ran with the Bazel command:

bazel run //:license-check

Status: ⚠️ Needs Review

Click to expand output
[License Check Output]
2026/01/22 12:42:08 Downloading https://releases.bazel.build/8.4.2/release/bazel-8.4.2-linux-x86_64...
Extracting Bazel installation...
Starting local Bazel server (8.4.2) and connecting to it...
INFO: Invocation ID: 6b93d569-9b2c-43c4-811f-15dc5afff256
Computing main repo mapping: 
Computing main repo mapping: 
Computing main repo mapping: 
Computing main repo mapping: 
DEBUG: Rule 'rust_qnx8_toolchain+' indicated that a canonical reproducible form can be obtained by modifying arguments integrity = "sha256-eQOopREOYCL5vtTb6c1cwZrql4GVrJ1FqgxarQRe1xs="
DEBUG: Repository rust_qnx8_toolchain+ instantiated at:
  <builtin>: in <toplevel>
Repository rule http_archive defined at:
  /home/runner/.bazel/external/bazel_tools/tools/build_defs/repo/http.bzl:431:31: in <toplevel>
Computing main repo mapping: 
Computing main repo mapping: 
Loading: 
Loading: 2 packages loaded
Loading: 2 packages loaded
    currently loading: 
Loading: 2 packages loaded
    currently loading: 
Loading: 2 packages loaded
    currently loading: 
Analyzing: target //:license-check (3 packages loaded, 0 targets configured)
Analyzing: target //:license-check (3 packages loaded, 0 targets configured)

Analyzing: target //:license-check (33 packages loaded, 10 targets configured)

Analyzing: target //:license-check (89 packages loaded, 10 targets configured)

Analyzing: target //:license-check (139 packages loaded, 2489 targets configured)

Analyzing: target //:license-check (148 packages loaded, 4389 targets configured)

Analyzing: target //:license-check (152 packages loaded, 7396 targets configured)

Analyzing: target //:license-check (152 packages loaded, 7396 targets configured)

Analyzing: target //:license-check (152 packages loaded, 7396 targets configured)

Analyzing: target //:license-check (162 packages loaded, 13688 targets configured)

INFO: Analyzed target //:license-check (162 packages loaded, 13697 targets configured).
INFO: Found 1 target...
Target //:license.check.license_check up-to-date:
  bazel-bin/license.check.license_check
  bazel-bin/license.check.license_check.jar
INFO: Elapsed time: 25.623s, Critical Path: 0.37s
INFO: 13 processes: 4 disk cache hit, 9 internal.
INFO: Build completed successfully, 13 total actions
INFO: Running command line: bazel-bin/license.check.license_check ./formatted.txt <args omitted>
usage: org.eclipse.dash.licenses.cli.Main [-batch <int>] [-cd <url>]
       [-confidence <int>] [-ef <url>] [-excludeSources <sources>] [-help] [-lic
       <url>] [-project <shortname>] [-repo <url>] [-review] [-summary <file>]
       [-timeout <seconds>] [-token <token>]

@github-actions
Copy link

The created documentation from the pull request is available at: docu-html

@pawelrutkaq pawelrutkaq force-pushed the pawelrutkaq_deadline_monitor branch from 5027d80 to 9d36a69 Compare January 20, 2026 10:03
@pawelrutkaq pawelrutkaq force-pushed the pawelrutkaq_deadline_monitor branch from 9d36a69 to d48a7c6 Compare January 20, 2026 10:07
@pawelrutkaq pawelrutkaq force-pushed the pawelrutkaq_deadline_monitor branch from d48a7c6 to c10992a Compare January 20, 2026 11:28
match possible_err {
PossibleError::None => {},
PossibleError::TooEarly => {
error!("Deadline {:?} stopped too early", self.tag);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be helpful if we can also log here by who much the deadline was missed.
Something like:

Deadline xy stopped 5ms too early
Deadline xy stopped 5ms too late

This would be very useful when investigating why supervision failed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

(self.0 & DEADLINE_STATE_FINISHED_TOO_EARLY) != 0
}

pub(super) fn timestamp(&self) -> u32 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be helpful to include somewhere the unit of this timestamp. Either in documentation or in naming of the variable/method itself (e.g. timestamp_ms or similar).
Reading the code I am not really sure is this a timestamp in ms or ns.

Similarly, only from other code I can infer that this is actually the absolute timestamp of the max deadline. But from the naming this does not become clear to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

const DEADLINE_STATE_RUNNING: u64 = 0b0000_0010;
const DEADLINE_STATE_STOPPED: u64 = 0b0000_0001;
const DEADLINE_STATE_FINISHED_TOO_EARLY: u64 = 0b0000_1000;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, what is the motivation for these bitmasks compared to using for example regular attributes for timestamp and state (e.g. running, stopped, etc)?
Is it about concurrency to only need to update single value or about saving a few bytes?

I was also wondering what is the motivation for constraining the timestamp to u32

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make a simple algorithm lock-free, we have to fit into 64bits. Then value and state are consistent, and doing it with spsc fashion is simple. Can also be done differently, but this pattern normally works well, and the whole code uses abstraction on top of it so you don't see all this nesty bit manipulation at the end.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For timestamp being u32 as written in code, it will cover ~~49days (we use offsetting and not real unix timestamp). I don't expect we need to support longer power cycles. The motivation is the same, you need to make room in 64bit value. However, we can always increase since there are still a few bits left.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose 49days would be enough, but it might be worth validating that with the other members of the group. Maybe there could be some use case were the system is only going into a low-power mode but never really shut off completely.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to use u128 for the state instead, so we could use u64 for the timestamp? That should be enough for all use cases

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be used, but i woud still tend to keep it 64 and just instead 32 bytes use 50 bytes which would till end of the world (35k years?). I would say we can check this in CFT and i can update i follow ups if its okey.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#46

u32::try_from(duration.as_millis()).expect("Monitor running for too long")
}

fn evaluate(&self, mut on_failed: impl FnMut(&IdentTag, bool)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if code readability would be improved by encoding the failure modes too early / too late as an enum or similar instead of encoding this as true/false when calling on_failed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Contributor

@NicolasFussberger NicolasFussberger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a first review. Though it might be better to get another review from someone with deeper Rust experience.

//
// SPDX-License-Identifier: Apache-2.0
//
#![allow(dead_code)]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move allow to ProtectedMemoryAllocator? I mean - make it struct-wide, not module-wide.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will leave it, soon there will be examples and i will remove it

pub(crate) use {debug, error, fatal, info, trace, warning as warn};

// Re-export symbols from `score_log`.
pub(crate) use score_log::fmt::Error;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird formatting:

pub(crate) use score_log::fmt::{Error, FormatSpec, ScoreDebug, Writer, DebugStruct};
pub(crate) use score_log::ScoreDebug;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auto formatted but fixed


/// Errors that can occur when working with Deadline instances
#[derive(Debug, PartialEq, ScoreDebug, Eq, Clone, Copy, Hash)]
pub enum DeadlineErrors {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consistency -> DeadlineError.
BTW I'd merge all errors of this component into shared type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that then you have to match cases that do not exist. In this particular usecase I tihnk its better to have them separate.

@pawelrutkaq pawelrutkaq force-pushed the pawelrutkaq_deadline_monitor branch from 912137d to 6868928 Compare January 21, 2026 12:49
@pawelrutkaq pawelrutkaq force-pushed the pawelrutkaq_deadline_monitor branch from 6868928 to f1c0de9 Compare January 21, 2026 12:58
@pawelrutkaq
Copy link
Contributor Author

@NicolasFussberger @arkjedrz done

PhmDaemon::PhmDaemon(score::lcm::saf::timers::OsClockInterface& f_osClock, logging::PhmLogger& f_logger_r,
std::unique_ptr<watchdog::IWatchdogIf> f_watchdog, std::unique_ptr<score::lcm::IProcessStateReceiver> f_process_state_receiver) :
osClock{f_osClock}, cycleTimer{&osClock}, logger_r{f_logger_r}, swClusterHandlers{}, watchdog(std::move(f_watchdog)), processStateReader{std::move(f_process_state_receiver)}
osClock{f_osClock}, cycleTimer{&osClock}, logger_r{f_logger_r}, swClusterHandlers{}, processStateReader{std::move(f_process_state_receiver)}, watchdog(std::move(f_watchdog))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rebase leftover?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, fixes issues introduced on master ;]

/// The closure receives the current state snapshot and should return
/// an Option with the new state snapshot. If None is returned, the state
/// is not updated.
pub(super) fn update<F: FnMut(DeadlineStateSnapshot) -> Option<DeadlineStateSnapshot>>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a test for this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

const DEADLINE_STATE_RUNNING: u64 = 0b0000_0010;
const DEADLINE_STATE_STOPPED: u64 = 0b0000_0001;
const DEADLINE_STATE_FINISHED_TOO_EARLY: u64 = 0b0000_1000;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to use u128 for the state instead, so we could use u64 for the timestamp? That should be enough for all use cases

@pawelrutkaq pawelrutkaq merged commit 8a7b418 into eclipse-score:main Jan 22, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[HmLib] Rust Deadline Monitor API

5 participants