ax_task/sched/algorithm/
clock.rs1use core::cmp::Ordering;
10
11use crate::time::{MonotonicDeadline, MonotonicInstant};
12
13pub(crate) const SCHEDULER_TIME_HALF_RANGE: u64 = 1_u64 << 63;
14
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17#[repr(transparent)]
18pub struct SchedulerTimestamp(u64);
19
20#[derive(Clone, Copy, Debug, Eq, PartialEq)]
22pub(crate) enum SchedulerClockEvent {
23 Due,
25 Future(MonotonicDeadline),
27}
28
29impl SchedulerTimestamp {
30 pub const fn from_nanos(nanos: u64) -> Self {
32 Self(nanos)
33 }
34
35 pub const fn as_nanos(self) -> u64 {
37 self.0
38 }
39
40 pub(crate) const fn advance(self, delta_ns: u64) -> Self {
42 assert!(delta_ns < SCHEDULER_TIME_HALF_RANGE);
43 Self(self.0.wrapping_add(delta_ns))
44 }
45
46 pub(crate) const fn retreat(self, delta_ns: u64) -> Self {
48 assert!(delta_ns < SCHEDULER_TIME_HALF_RANGE);
49 Self(self.0.wrapping_sub(delta_ns))
50 }
51
52 pub(crate) const fn since(self, earlier: Self) -> u64 {
54 let delta = self.0.wrapping_sub(earlier.0);
55 assert!(delta < SCHEDULER_TIME_HALF_RANGE);
56 delta
57 }
58
59 pub(crate) const fn is_before(self, other: Self) -> bool {
60 (self.0.wrapping_sub(other.0) as i64) < 0
61 }
62
63 pub(crate) const fn is_reached_by(self, now: Self) -> bool {
64 !now.is_before(self)
65 }
66}
67
68impl Ord for SchedulerTimestamp {
69 fn cmp(&self, other: &Self) -> Ordering {
70 scheduler_time_cmp(self.0, other.0)
71 }
72}
73
74impl PartialOrd for SchedulerTimestamp {
75 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
76 Some(self.cmp(other))
77 }
78}
79
80pub(crate) fn scheduler_time_cmp(left: u64, right: u64) -> Ordering {
81 if left == right {
82 Ordering::Equal
83 } else if SchedulerTimestamp::from_nanos(left).is_before(SchedulerTimestamp::from_nanos(right))
84 {
85 Ordering::Less
86 } else {
87 Ordering::Greater
88 }
89}
90
91pub(crate) const fn scheduler_time_reached(now_ns: u64, deadline_ns: u64) -> bool {
92 SchedulerTimestamp::from_nanos(deadline_ns)
93 .is_reached_by(SchedulerTimestamp::from_nanos(now_ns))
94}
95
96pub(crate) fn scheduler_clock_event(
103 scheduler_now_ns: u64,
104 monotonic_now: MonotonicInstant,
105 scheduler_deadline_ns: u64,
106) -> SchedulerClockEvent {
107 let scheduler_now = SchedulerTimestamp::from_nanos(scheduler_now_ns);
108 let scheduler_deadline = SchedulerTimestamp::from_nanos(scheduler_deadline_ns);
109 if scheduler_deadline.is_reached_by(scheduler_now) {
110 return SchedulerClockEvent::Due;
111 }
112 let deadline = monotonic_now.deadline_after(core::time::Duration::from_nanos(
113 scheduler_deadline.since(scheduler_now),
114 ));
115 if monotonic_now.reached(deadline) {
116 SchedulerClockEvent::Due
117 } else {
118 SchedulerClockEvent::Future(deadline)
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn scheduler_deadline_mapping_handles_wrap_and_elapsed_events() {
128 let monotonic_now = MonotonicInstant::from_nanos(100).unwrap();
129 assert_eq!(
130 scheduler_clock_event(u64::MAX - 2, monotonic_now, 2),
131 SchedulerClockEvent::Future(MonotonicDeadline::from_nanos(105).unwrap())
132 );
133 assert_eq!(
134 scheduler_clock_event(10, monotonic_now, 9),
135 SchedulerClockEvent::Due
136 );
137 }
138}