hermit/scheduler/
timer_interrupts.rs1use core::mem;
2
3use crate::arch::kernel::core_local::core_scheduler;
4use crate::arch::kernel::set_oneshot_timer;
5#[cfg(feature = "net")]
6use crate::executor::network::wake_network_waker;
7
8#[derive(Debug, PartialEq, Eq)]
11pub enum Source {
12 Network,
13 Scheduler,
14 #[cfg(feature = "preemptive")]
18 Preemption,
19}
20
21#[derive(Debug)]
24pub struct Slot {
25 source: Source,
27 wakeup_time: u64,
31}
32
33#[cfg(feature = "preemptive")]
34const NUMBER_OF_SLOTS: usize = 3;
35
36#[cfg(not(feature = "preemptive"))]
37const NUMBER_OF_SLOTS: usize = 2;
38
39#[derive(Debug)]
41pub struct TimerList([Slot; NUMBER_OF_SLOTS]);
42
43impl TimerList {
44 pub fn new() -> Self {
45 Self([
46 Slot {
47 source: Source::Network,
48 wakeup_time: u64::MAX,
49 },
50 Slot {
51 source: Source::Scheduler,
52 wakeup_time: u64::MAX,
53 },
54 #[cfg(feature = "preemptive")]
55 Slot {
56 source: Source::Preemption,
57 wakeup_time: u64::MAX,
58 },
59 ])
60 }
61
62 pub fn slot_by_source_mut(&mut self, source: Source) -> &mut Slot {
64 self.0
66 .iter_mut()
67 .find(|slot| slot.source == source)
68 .unwrap()
69 }
70
71 pub fn next_timer(&self) -> &Slot {
73 self.0
75 .iter()
76 .min_by(|a, b| a.wakeup_time.cmp(&b.wakeup_time))
77 .unwrap()
78 }
79
80 pub fn next_timer_mut(&mut self) -> &mut Slot {
82 self.0
84 .iter_mut()
85 .min_by(|a, b| a.wakeup_time.cmp(&b.wakeup_time))
86 .unwrap()
87 }
88
89 pub fn adjust_by(&mut self, offset: u64) {
91 for timer in self.0.iter_mut() {
92 if timer.wakeup_time != u64::MAX {
93 timer.wakeup_time -= offset;
94 }
95 }
96 }
97}
98
99impl Default for TimerList {
100 fn default() -> Self {
101 Self::new()
102 }
103}
104
105#[cfg(feature = "net")]
107#[inline]
108pub fn create_timer(source: Source, wakeup_micros: u64) {
109 create_timer_abs(
110 source,
111 crate::arch::kernel::processor::get_timer_ticks() + wakeup_micros,
113 );
114}
115
116pub fn create_timer_abs(source: Source, wakeup_time: u64) {
118 let timers = &mut core_scheduler().timers;
119
120 let previous_entry = timers.slot_by_source_mut(source);
122
123 previous_entry.wakeup_time = previous_entry.wakeup_time.min(wakeup_time);
125
126 if timers.next_timer().wakeup_time == wakeup_time {
128 set_oneshot_timer(Some(wakeup_time));
129 }
130}
131
132pub fn clear_active_and_set_next() {
134 let timers = &mut core_scheduler().timers;
135
136 let lowest_timer = timers.next_timer_mut();
137 assert!(lowest_timer.wakeup_time != u64::MAX);
138
139 match lowest_timer.source {
141 #[cfg(feature = "net")]
142 Source::Network => wake_network_waker(),
143 _ => {} }
145
146 trace!("Cleared active timer {lowest_timer:?}");
147
148 let prev_wakeup_time = mem::replace(&mut lowest_timer.wakeup_time, u64::MAX);
149
150 let timer_ticks = crate::arch::kernel::processor::get_timer_ticks();
157 if prev_wakeup_time > timer_ticks {
158 let offset = prev_wakeup_time - timer_ticks;
159 timers.adjust_by(offset);
160 }
161
162 let new_lowest_timer = timers.next_timer().wakeup_time;
163
164 if new_lowest_timer == u64::MAX {
165 set_oneshot_timer(None);
166 } else {
167 set_oneshot_timer(Some(new_lowest_timer));
168 }
169}