1010//
1111// SPDX-License-Identifier: Apache-2.0
1212// *******************************************************************************
13- use super :: common:: DeadlineTemplate ;
14- use crate :: common:: { MonitorEvalHandle , MonitorEvaluationError , MonitorEvaluator , TimeRange } ;
13+ use crate :: common:: { Monitor , MonitorEvalHandle , MonitorEvaluationError , MonitorEvaluator } ;
14+ use crate :: deadline:: common:: { DeadlineTemplate , StateIndex } ;
15+ use crate :: deadline:: deadline_state:: { DeadlineState , DeadlineStateSnapshot } ;
16+ use crate :: log:: { error, warn, ScoreDebug } ;
17+ use crate :: protected_memory:: ProtectedMemoryAllocator ;
1518use crate :: tag:: { DeadlineTag , MonitorTag } ;
16- use crate :: {
17- deadline:: {
18- common:: StateIndex ,
19- deadline_state:: { DeadlineState , DeadlineStateSnapshot } ,
20- } ,
21- protected_memory:: ProtectedMemoryAllocator ,
22- } ;
19+ use crate :: TimeRange ;
2320use core:: hash:: Hash ;
24- use std:: { collections:: HashMap , sync:: Arc , time:: Instant } ;
25-
26- use crate :: log:: * ;
21+ use std:: collections:: HashMap ;
22+ use std:: sync:: Arc ;
23+ use std:: time:: Instant ;
24+
25+ /// Deadline evaluation errors.
26+ #[ derive( Debug , PartialEq , Eq , Clone , Copy , Hash , ScoreDebug ) ]
27+ pub ( crate ) enum DeadlineEvaluationError {
28+ /// Finished too early.
29+ TooEarly ,
30+ /// Finished too late.
31+ TooLate ,
32+ }
2733
2834///
2935/// Errors that can occur when working with DeadlineMonitor
@@ -65,7 +71,8 @@ impl DeadlineMonitorBuilder {
6571
6672 /// Builds the DeadlineMonitor with the configured deadlines.
6773 pub ( crate ) fn build ( self , monitor_tag : MonitorTag , _allocator : & ProtectedMemoryAllocator ) -> DeadlineMonitor {
68- DeadlineMonitor :: new ( monitor_tag, self . deadlines )
74+ let inner = Arc :: new ( DeadlineMonitorInner :: new ( monitor_tag, self . deadlines ) ) ;
75+ DeadlineMonitor :: new ( inner)
6976 }
7077
7178 // Used by FFI and config parsing code which prefer not to move builder instance
@@ -80,27 +87,9 @@ pub struct DeadlineMonitor {
8087}
8188
8289impl DeadlineMonitor {
83- fn new ( monitor_tag : MonitorTag , deadlines : HashMap < DeadlineTag , TimeRange > ) -> Self {
84- let mut active_deadlines = vec ! [ ] ;
85-
86- let deadlines = deadlines
87- . into_iter ( )
88- . enumerate ( )
89- . map ( |( index, ( deadline_tag, range) ) | {
90- active_deadlines. push ( ( deadline_tag, DeadlineState :: new ( ) ) ) ;
91- ( deadline_tag, DeadlineTemplate :: new ( range, StateIndex :: new ( index) ) )
92- } )
93- . collect ( ) ;
94-
95- Self {
96- #[ allow( clippy:: arc_with_non_send_sync) ] // This will be fixed once we add background thread
97- inner : Arc :: new ( DeadlineMonitorInner {
98- monitor_tag,
99- deadlines,
100- active_deadlines : active_deadlines. into ( ) ,
101- monitor_starting_point : Instant :: now ( ) ,
102- } ) ,
103- }
90+ /// Create a new [`DeadlineMonitor`] instance.
91+ fn new ( inner : Arc < DeadlineMonitorInner > ) -> Self {
92+ Self { inner }
10493 }
10594
10695 /// Acquires a deadline instance for the given tag.
@@ -109,26 +98,12 @@ impl DeadlineMonitor {
10998 /// - Err(DeadlineMonitorError::DeadlineInUse) - if the deadline is already in use
11099 /// - Err(DeadlineMonitorError::DeadlineNotFound) - if the deadline tag is not registered
111100 pub fn get_deadline ( & self , deadline_tag : DeadlineTag ) -> Result < Deadline , DeadlineMonitorError > {
112- if let Some ( template) = self . inner . deadlines . get ( & deadline_tag) {
113- match template. acquire_deadline ( ) {
114- Some ( range) => Ok ( Deadline {
115- range,
116- deadline_tag,
117- monitor : Arc :: clone ( & self . inner ) ,
118- state_index : template. assigned_state_index ,
119- } ) ,
120- None => Err ( DeadlineMonitorError :: DeadlineInUse ) ,
121- }
122- } else {
123- Err ( DeadlineMonitorError :: DeadlineNotFound )
124- }
101+ self . inner . get_deadline ( deadline_tag)
125102 }
103+ }
126104
127- /// Handle for evaluation of all active deadlines and reporting any missed deadlines or underruns.
128- ///
129- /// # NOTE
130- /// This function is intended to be called from a background thread periodically.
131- pub ( crate ) fn get_eval_handle ( & self ) -> MonitorEvalHandle {
105+ impl Monitor for DeadlineMonitor {
106+ fn get_eval_handle ( & self ) -> MonitorEvalHandle {
132107 MonitorEvalHandle :: new ( Arc :: clone ( & self . inner ) )
133108 }
134109}
@@ -220,7 +195,7 @@ impl Deadline {
220195
221196 let expected = current. timestamp_ms ( ) ;
222197 if expected < now {
223- possible_err = ( Some ( MonitorEvaluationError :: TooLate ) , now - expected) ;
198+ possible_err = ( Some ( DeadlineEvaluationError :: TooLate ) , now - expected) ;
224199 return None ; // Deadline missed, let state as is for BG thread to report
225200 }
226201
@@ -231,18 +206,18 @@ impl Deadline {
231206 // Finished too early, leave it for reporting by BG thread
232207
233208 current. set_underrun ( ) ;
234- possible_err = ( Some ( MonitorEvaluationError :: TooEarly ) , earliest_time - now) ;
209+ possible_err = ( Some ( DeadlineEvaluationError :: TooEarly ) , earliest_time - now) ;
235210 return Some ( current) ;
236211 }
237212
238213 Some ( DeadlineStateSnapshot :: default ( ) ) // Reset to stopped state as all fine
239214 } ) ;
240215
241216 match possible_err {
242- ( Some ( MonitorEvaluationError :: TooEarly ) , val) => {
217+ ( Some ( DeadlineEvaluationError :: TooEarly ) , val) => {
243218 error ! ( "Deadline {:?} stopped too early by {} ms" , self . deadline_tag, val) ;
244219 } ,
245- ( Some ( MonitorEvaluationError :: TooLate ) , val) => {
220+ ( Some ( DeadlineEvaluationError :: TooLate ) , val) => {
246221 error ! ( "Deadline {:?} stopped too late by {} ms" , self . deadline_tag, val) ;
247222 } ,
248223 ( None , _) => { } ,
@@ -286,35 +261,14 @@ struct DeadlineMonitorInner {
286261
287262impl MonitorEvaluator for DeadlineMonitorInner {
288263 fn evaluate ( & self , on_error : & mut dyn FnMut ( & MonitorTag , MonitorEvaluationError ) ) {
289- self . evaluate ( on_error) ;
290- }
291- }
292-
293- impl DeadlineMonitorInner {
294- fn release_deadline ( & self , deadline_tag : DeadlineTag ) {
295- if let Some ( template) = self . deadlines . get ( & deadline_tag) {
296- template. release_deadline ( ) ;
297- } else {
298- unreachable ! ( "Releasing unknown deadline tag: {:?}" , deadline_tag) ;
299- }
300- }
301-
302- fn now ( & self ) -> u32 {
303- let duration = self . monitor_starting_point . elapsed ( ) ;
304- // As u32 can hold up to ~49 days in milliseconds, this should be sufficient for our use case
305- // We still have a room up to 60bits timestamp if needed in future
306- u32:: try_from ( duration. as_millis ( ) ) . expect ( "Monitor running for too long" )
307- }
308-
309- fn evaluate ( & self , mut on_failed : impl FnMut ( & MonitorTag , MonitorEvaluationError ) ) {
310264 for ( deadline_tag, deadline) in self . active_deadlines . iter ( ) {
311265 let snapshot = deadline. snapshot ( ) ;
312266 if snapshot. is_underrun ( ) {
313267 // Deadline finished too early, report
314268 warn ! ( "Deadline ({:?}) finished too early!" , deadline_tag) ;
315269
316270 // Here we would normally report the underrun to the monitoring system
317- on_failed ( & self . monitor_tag , MonitorEvaluationError :: TooEarly ) ;
271+ on_error ( & self . monitor_tag , DeadlineEvaluationError :: TooEarly . into ( ) ) ;
318272 } else if snapshot. is_running ( ) {
319273 debug_assert ! (
320274 snapshot. is_stopped( ) ,
@@ -331,13 +285,66 @@ impl DeadlineMonitorInner {
331285 ) ;
332286
333287 // Here we would normally report the missed deadline to the monitoring system
334- on_failed ( & self . monitor_tag , MonitorEvaluationError :: TooLate ) ;
288+ on_error ( & self . monitor_tag , DeadlineEvaluationError :: TooLate . into ( ) ) ;
335289 }
336290 }
337291 }
338292 }
339293}
340294
295+ impl DeadlineMonitorInner {
296+ fn new ( monitor_tag : MonitorTag , deadlines : HashMap < DeadlineTag , TimeRange > ) -> Self {
297+ let mut active_deadlines = vec ! [ ] ;
298+
299+ let deadlines = deadlines
300+ . into_iter ( )
301+ . enumerate ( )
302+ . map ( |( index, ( deadline_tag, range) ) | {
303+ active_deadlines. push ( ( deadline_tag, DeadlineState :: new ( ) ) ) ;
304+ ( deadline_tag, DeadlineTemplate :: new ( range, StateIndex :: new ( index) ) )
305+ } )
306+ . collect ( ) ;
307+
308+ Self {
309+ monitor_tag,
310+ deadlines,
311+ active_deadlines : active_deadlines. into ( ) ,
312+ monitor_starting_point : Instant :: now ( ) ,
313+ }
314+ }
315+
316+ fn release_deadline ( & self , deadline_tag : DeadlineTag ) {
317+ if let Some ( template) = self . deadlines . get ( & deadline_tag) {
318+ template. release_deadline ( ) ;
319+ } else {
320+ unreachable ! ( "Releasing unknown deadline tag: {:?}" , deadline_tag) ;
321+ }
322+ }
323+
324+ pub ( crate ) fn get_deadline ( self : & Arc < Self > , deadline_tag : DeadlineTag ) -> Result < Deadline , DeadlineMonitorError > {
325+ if let Some ( template) = self . deadlines . get ( & deadline_tag) {
326+ match template. acquire_deadline ( ) {
327+ Some ( range) => Ok ( Deadline {
328+ range,
329+ deadline_tag,
330+ monitor : self . clone ( ) ,
331+ state_index : template. assigned_state_index ,
332+ } ) ,
333+ None => Err ( DeadlineMonitorError :: DeadlineInUse ) ,
334+ }
335+ } else {
336+ Err ( DeadlineMonitorError :: DeadlineNotFound )
337+ }
338+ }
339+
340+ fn now ( & self ) -> u32 {
341+ let duration = self . monitor_starting_point . elapsed ( ) ;
342+ // As u32 can hold up to ~49 days in milliseconds, this should be sufficient for our use case
343+ // We still have a room up to 60bits timestamp if needed in future
344+ u32:: try_from ( duration. as_millis ( ) ) . expect ( "Monitor running for too long" )
345+ }
346+ }
347+
341348#[ score_testing_macros:: test_mod_with_log]
342349#[ cfg( test) ]
343350mod tests {
@@ -410,7 +417,7 @@ mod tests {
410417
411418 drop ( handle) ; // stop the deadline
412419
413- monitor. inner . evaluate ( |monitor_tag, deadline_failure| {
420+ monitor. inner . evaluate ( & mut |monitor_tag, deadline_failure| {
414421 panic ! (
415422 "Deadline {:?} should not have failed or underrun({:?})" ,
416423 monitor_tag, deadline_failure
@@ -426,10 +433,10 @@ mod tests {
426433
427434 drop ( handle) ; // stop the deadline
428435
429- monitor. inner . evaluate ( |monitor_tag, deadline_failure| {
436+ monitor. inner . evaluate ( & mut |monitor_tag, deadline_failure| {
430437 assert_eq ! (
431438 deadline_failure,
432- MonitorEvaluationError :: TooEarly ,
439+ DeadlineEvaluationError :: TooEarly . into ( ) ,
433440 "Deadline {:?} should not have failed({:?})" ,
434441 monitor_tag,
435442 deadline_failure
@@ -444,10 +451,10 @@ mod tests {
444451
445452 // So deadline stop happens after evaluate, still it should be reported as failed
446453
447- monitor. inner . evaluate ( |monitor_tag, deadline_failure| {
454+ monitor. inner . evaluate ( & mut |monitor_tag, deadline_failure| {
448455 assert_eq ! (
449456 deadline_failure,
450- MonitorEvaluationError :: TooEarly ,
457+ DeadlineEvaluationError :: TooEarly . into ( ) ,
451458 "Deadline {:?} should not have failed({:?})" ,
452459 monitor_tag,
453460 deadline_failure
@@ -470,10 +477,10 @@ mod tests {
470477 let handle = deadline. start ( ) ;
471478 assert_eq ! ( handle. err( ) , Some ( DeadlineError :: DeadlineAlreadyFailed ) ) ;
472479
473- monitor. inner . evaluate ( |monitor_tag, deadline_failure| {
480+ monitor. inner . evaluate ( & mut |monitor_tag, deadline_failure| {
474481 assert_eq ! (
475482 deadline_failure,
476- MonitorEvaluationError :: TooEarly ,
483+ DeadlineEvaluationError :: TooEarly . into ( ) ,
477484 "Deadline {:?} should not have failed ({:?})" ,
478485 monitor_tag,
479486 deadline_failure
@@ -489,10 +496,10 @@ mod tests {
489496
490497 drop ( handle) ; // stop the deadline
491498
492- monitor. inner . evaluate ( |monitor_tag, deadline_failure| {
499+ monitor. inner . evaluate ( & mut |monitor_tag, deadline_failure| {
493500 assert_eq ! (
494501 deadline_failure,
495- MonitorEvaluationError :: TooLate ,
502+ DeadlineEvaluationError :: TooLate . into ( ) ,
496503 "Deadline {:?} should not have failed({:?})" ,
497504 monitor_tag,
498505 deadline_failure
@@ -517,11 +524,11 @@ mod tests {
517524
518525 let mut cnt = 0 ;
519526
520- monitor. inner . evaluate ( |monitor_tag, deadline_failure| {
527+ monitor. inner . evaluate ( & mut |monitor_tag, deadline_failure| {
521528 cnt += 1 ;
522529 assert_eq ! (
523530 deadline_failure,
524- MonitorEvaluationError :: TooLate ,
531+ DeadlineEvaluationError :: TooLate . into ( ) ,
525532 "Deadline {:?} should not have failed({:?})" ,
526533 monitor_tag,
527534 deadline_failure
0 commit comments