1111// SPDX-License-Identifier: Apache-2.0
1212// *******************************************************************************
1313use super :: common:: DeadlineTemplate ;
14- use crate :: common:: { IdentTag , MonitorEvalHandle , MonitorEvaluationError , MonitorEvaluator , TimeRange } ;
14+ use crate :: common:: {
15+ duration_to_u32, IdentTag , MonitorEvalHandle , MonitorEvaluationError , MonitorEvaluator , TimeRange ,
16+ } ;
1517use crate :: {
1618 deadline:: {
1719 common:: StateIndex ,
@@ -96,7 +98,7 @@ impl DeadlineMonitor {
9698 inner : Arc :: new ( DeadlineMonitorInner {
9799 deadlines,
98100 active_deadlines : active_deadlines. into ( ) ,
99- start_time : Instant :: now ( ) ,
101+ monitor_starting_point : Instant :: now ( ) ,
100102 } ) ,
101103 }
102104 }
@@ -176,7 +178,7 @@ impl Deadline {
176178 /// Caller must ensure that deadline is not used until it's stopped.
177179 /// After this call You shall assure there's only a single owner of the `Deadline` instance and it does not call start before stopping.
178180 pub ( super ) unsafe fn start_internal ( & mut self ) -> Result < ( ) , DeadlineError > {
179- let now = self . monitor . now ( ) ;
181+ let now = duration_to_u32 ( self . monitor . monitor_starting_point . elapsed ( ) ) ;
180182 let max_time = now + self . range . max . as_millis ( ) as u32 ;
181183
182184 let mut is_broken = false ;
@@ -201,7 +203,7 @@ impl Deadline {
201203 }
202204
203205 pub ( super ) fn stop_internal ( & mut self ) {
204- let now = self . monitor . now ( ) ;
206+ let now = duration_to_u32 ( self . monitor . monitor_starting_point . elapsed ( ) ) ;
205207 let max = self . range . max . as_millis ( ) as u32 ;
206208 let min = self . range . min . as_millis ( ) as u32 ;
207209
@@ -243,6 +245,7 @@ impl Deadline {
243245 ( Some ( MonitorEvaluationError :: TooLate ) , val) => {
244246 error ! ( "Deadline {:?} stopped too late by {} ms" , self . tag, val) ;
245247 } ,
248+ ( Some ( MonitorEvaluationError :: HeartbeatSpecific ( _) ) , _) => unreachable ! ( ) ,
246249 ( None , _) => { } ,
247250 }
248251 }
@@ -267,8 +270,9 @@ impl Drop for Deadline {
267270}
268271
269272struct DeadlineMonitorInner {
270- // Start time of the monitor creation to calculate relative timestamps
271- start_time : Instant ,
273+ /// Monitor starting point.
274+ /// Offset is calculated during evaluation in relation to provided health monitor starting point.
275+ monitor_starting_point : Instant ,
272276
273277 // Templates for deadlines registered in the monitor to create `Deadline` instances.
274278 deadlines : HashMap < IdentTag , DeadlineTemplate > ,
@@ -280,8 +284,8 @@ struct DeadlineMonitorInner {
280284}
281285
282286impl MonitorEvaluator for DeadlineMonitorInner {
283- fn evaluate ( & self , on_error : & mut dyn FnMut ( & IdentTag , MonitorEvaluationError ) ) {
284- self . evaluate ( on_error) ;
287+ fn evaluate ( & self , hmon_starting_point : Instant , on_error : & mut dyn FnMut ( & IdentTag , MonitorEvaluationError ) ) {
288+ self . evaluate ( hmon_starting_point , on_error) ;
285289 }
286290}
287291
@@ -294,14 +298,7 @@ impl DeadlineMonitorInner {
294298 }
295299 }
296300
297- fn now ( & self ) -> u32 {
298- let duration = self . start_time . elapsed ( ) ;
299- // As u32 can hold up to ~49 days in milliseconds, this should be sufficient for our use case
300- // We still have a room up to 60bits timestamp if needed in future
301- u32:: try_from ( duration. as_millis ( ) ) . expect ( "Monitor running for too long" )
302- }
303-
304- fn evaluate ( & self , mut on_failed : impl FnMut ( & IdentTag , MonitorEvaluationError ) ) {
301+ fn evaluate ( & self , hmon_starting_point : Instant , mut on_failed : impl FnMut ( & IdentTag , MonitorEvaluationError ) ) {
305302 for ( tag, deadline) in self . active_deadlines . iter ( ) {
306303 let snapshot = deadline. snapshot ( ) ;
307304 if snapshot. is_underrun ( ) {
@@ -316,7 +313,9 @@ impl DeadlineMonitorInner {
316313 "Deadline snapshot cannot be both running and stopped"
317314 ) ;
318315
319- let now = self . now ( ) ;
316+ // Get current timestamp, with offset to HMON time.
317+ let offset = hmon_starting_point. duration_since ( self . monitor_starting_point ) ;
318+ let now = duration_to_u32 ( self . monitor_starting_point . elapsed ( ) - offset) ;
320319 let expected = snapshot. timestamp_ms ( ) ;
321320 if now > expected {
322321 // Deadline missed, report
@@ -395,12 +394,13 @@ mod tests {
395394 let monitor = create_monitor_with_deadlines ( ) ;
396395 let mut deadline = monitor. get_deadline ( & IdentTag :: from ( "deadline_long" ) ) . unwrap ( ) ;
397396 let handle = deadline. start ( ) . unwrap ( ) ;
397+ let hmon_starting_point = Instant :: now ( ) ;
398398
399399 std:: thread:: sleep ( core:: time:: Duration :: from_millis ( 1001 ) ) ; // Sleep to simulate work within the deadline range
400400
401401 drop ( handle) ; // stop the deadline
402402
403- monitor. inner . evaluate ( |tag, deadline_failure| {
403+ monitor. inner . evaluate ( hmon_starting_point , |tag, deadline_failure| {
404404 panic ! (
405405 "Deadline {:?} should not have failed or underrun({:?})" ,
406406 tag, deadline_failure
@@ -413,10 +413,11 @@ mod tests {
413413 let monitor = create_monitor_with_deadlines ( ) ;
414414 let mut deadline = monitor. get_deadline ( & IdentTag :: from ( "deadline_long" ) ) . unwrap ( ) ;
415415 let handle = deadline. start ( ) . unwrap ( ) ;
416+ let hmon_starting_point = Instant :: now ( ) ;
416417
417418 drop ( handle) ; // stop the deadline
418419
419- monitor. inner . evaluate ( |tag, deadline_failure| {
420+ monitor. inner . evaluate ( hmon_starting_point , |tag, deadline_failure| {
420421 assert_eq ! (
421422 deadline_failure,
422423 MonitorEvaluationError :: TooEarly ,
@@ -431,10 +432,11 @@ mod tests {
431432 let monitor = create_monitor_with_deadlines ( ) ;
432433 let mut deadline = monitor. get_deadline ( & IdentTag :: from ( "deadline_long" ) ) . unwrap ( ) ;
433434 let handle = deadline. start ( ) . unwrap ( ) ;
435+ let hmon_starting_point = Instant :: now ( ) ;
434436
435437 // So deadline stop happens after evaluate, still it should be reported as failed
436438
437- monitor. inner . evaluate ( |tag, deadline_failure| {
439+ monitor. inner . evaluate ( hmon_starting_point , |tag, deadline_failure| {
438440 assert_eq ! (
439441 deadline_failure,
440442 MonitorEvaluationError :: TooEarly ,
@@ -452,6 +454,7 @@ mod tests {
452454 let monitor = create_monitor_with_deadlines ( ) ;
453455 let mut deadline = monitor. get_deadline ( & IdentTag :: from ( "deadline_long" ) ) . unwrap ( ) ;
454456 let handle = deadline. start ( ) . unwrap ( ) ;
457+ let hmon_starting_point = Instant :: now ( ) ;
455458
456459 // So deadline failed, then we start it again so it shall be already expired and also evaluation shall work
457460 drop ( handle) ; // stop the deadline
@@ -460,7 +463,7 @@ mod tests {
460463 let handle = deadline. start ( ) ;
461464 assert_eq ! ( handle. err( ) , Some ( DeadlineError :: DeadlineAlreadyFailed ) ) ;
462465
463- monitor. inner . evaluate ( |tag, deadline_failure| {
466+ monitor. inner . evaluate ( hmon_starting_point , |tag, deadline_failure| {
464467 assert_eq ! (
465468 deadline_failure,
466469 MonitorEvaluationError :: TooEarly ,
@@ -476,10 +479,11 @@ mod tests {
476479 let monitor = create_monitor_with_deadlines ( ) ;
477480 let mut deadline = monitor. get_deadline ( & IdentTag :: from ( "deadline_fast" ) ) . unwrap ( ) ;
478481 let handle = deadline. start ( ) . unwrap ( ) ;
482+ let hmon_starting_point = Instant :: now ( ) ;
479483
480484 drop ( handle) ; // stop the deadline
481485
482- monitor. inner . evaluate ( |tag, deadline_failure| {
486+ monitor. inner . evaluate ( hmon_starting_point , |tag, deadline_failure| {
483487 assert_eq ! (
484488 deadline_failure,
485489 MonitorEvaluationError :: TooLate ,
@@ -493,6 +497,7 @@ mod tests {
493497 #[ test]
494498 fn monitor_with_multiple_running_deadlines ( ) {
495499 let monitor = create_monitor_with_multiple_running_deadlines ( ) ;
500+ let hmon_starting_point = Instant :: now ( ) ;
496501
497502 let mut deadline = monitor. get_deadline ( & IdentTag :: from ( "deadline_fast1" ) ) . unwrap ( ) ;
498503 let _handle1 = deadline. start ( ) . unwrap ( ) ;
@@ -507,7 +512,7 @@ mod tests {
507512
508513 let mut cnt = 0 ;
509514
510- monitor. inner . evaluate ( |tag, deadline_failure| {
515+ monitor. inner . evaluate ( hmon_starting_point , |tag, deadline_failure| {
511516 cnt += 1 ;
512517 assert_eq ! (
513518 deadline_failure,
0 commit comments