strat9_kernel/process/
timer.rs1use core::sync::atomic::{AtomicBool, AtomicU64, Ordering};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13#[repr(u32)]
14pub enum ITimerWhich {
15 Real = 0,
16 Virtual = 1,
17 Prof = 2,
18}
19
20impl ITimerWhich {
21 pub fn from_u32(value: u32) -> Option<Self> {
23 match value {
24 0 => Some(ITimerWhich::Real),
25 1 => Some(ITimerWhich::Virtual),
26 2 => Some(ITimerWhich::Prof),
27 _ => None,
28 }
29 }
30
31 pub fn signal(self) -> u32 {
33 match self {
34 ITimerWhich::Real => 14, ITimerWhich::Virtual => 26, ITimerWhich::Prof => 27, }
38 }
39}
40
41#[repr(C)]
43#[derive(Debug, Clone, Copy)]
44pub struct ITimerVal {
45 pub it_interval: TimeVal,
47 pub it_value: TimeVal,
49}
50
51impl ITimerVal {
52 pub const fn zero() -> Self {
54 Self {
55 it_interval: TimeVal::zero(),
56 it_value: TimeVal::zero(),
57 }
58 }
59
60 pub fn to_nanos(&self) -> (u64, u64) {
62 (self.it_interval.to_nanos(), self.it_value.to_nanos())
63 }
64}
65
66#[repr(C)]
68#[derive(Debug, Clone, Copy)]
69pub struct TimeVal {
70 pub tv_sec: i64,
71 pub tv_usec: i64,
72}
73
74impl TimeVal {
75 pub const fn zero() -> Self {
77 Self {
78 tv_sec: 0,
79 tv_usec: 0,
80 }
81 }
82
83 pub fn to_nanos(&self) -> u64 {
90 if self.tv_sec < 0 || self.tv_usec < 0 {
91 return 0;
92 }
93 (self.tv_sec as u64)
94 .saturating_mul(1_000_000_000)
95 .saturating_add((self.tv_usec as u64).saturating_mul(1_000))
96 }
97
98 pub fn from_nanos(nanos: u64) -> Self {
100 let tv_sec = (nanos / 1_000_000_000) as i64;
101 let tv_usec = ((nanos % 1_000_000_000) / 1_000) as i64;
102 Self { tv_sec, tv_usec }
103 }
104}
105
106pub struct ITimerState {
108 next_expiration: AtomicU64,
110 interval_ns: AtomicU64,
112 armed: AtomicBool,
114}
115
116impl ITimerState {
117 pub const fn new() -> Self {
119 Self {
120 next_expiration: AtomicU64::new(0),
121 interval_ns: AtomicU64::new(0),
122 armed: AtomicBool::new(false),
123 }
124 }
125
126 pub fn get(&self, current_time_ns: u64) -> ITimerVal {
128 let next = self.next_expiration.load(Ordering::Relaxed);
129 let interval = self.interval_ns.load(Ordering::Relaxed);
130
131 let value_ns = if next > current_time_ns {
132 next - current_time_ns
133 } else {
134 0
135 };
136
137 ITimerVal {
138 it_interval: TimeVal::from_nanos(interval),
139 it_value: TimeVal::from_nanos(value_ns),
140 }
141 }
142
143 pub fn set(&self, value: &ITimerVal, current_time_ns: u64) {
145 let (interval_ns, value_ns) = value.to_nanos();
146
147 if value_ns == 0 {
148 self.armed.store(false, Ordering::Release);
149 self.next_expiration.store(0, Ordering::Relaxed);
150 self.interval_ns.store(interval_ns, Ordering::Relaxed);
151 } else {
152 self.interval_ns.store(interval_ns, Ordering::Relaxed);
153 let next = current_time_ns.saturating_add(value_ns);
154 self.next_expiration.store(next, Ordering::Relaxed);
155 self.armed.store(true, Ordering::Release);
156 }
157 }
158
159 pub fn check_expired(&self, current_time_ns: u64) -> bool {
161 if !self.armed.load(Ordering::Acquire) {
162 return false;
163 }
164
165 let next = self.next_expiration.load(Ordering::Relaxed);
166 if current_time_ns >= next && next != 0 {
167 let interval = self.interval_ns.load(Ordering::Relaxed);
168 if interval == 0 {
169 self.armed.store(false, Ordering::Release);
170 self.next_expiration.store(0, Ordering::Relaxed);
171 } else {
172 let new_next = next.saturating_add(interval);
174 let new_next = if new_next <= current_time_ns {
175 current_time_ns.saturating_add(interval)
176 } else {
177 new_next
178 };
179 self.next_expiration.store(new_next, Ordering::Relaxed);
180 }
181 true
182 } else {
183 false
184 }
185 }
186
187 pub fn disarm(&self) {
189 self.armed.store(false, Ordering::Release);
190 self.next_expiration.store(0, Ordering::Relaxed);
191 self.interval_ns.store(0, Ordering::Relaxed);
192 }
193}
194
195pub struct ITimers {
197 pub real: ITimerState,
198 pub virtual_timer: ITimerState,
199 pub prof: ITimerState,
200}
201
202impl ITimers {
203 pub const fn new() -> Self {
205 Self {
206 real: ITimerState::new(),
207 virtual_timer: ITimerState::new(),
208 prof: ITimerState::new(),
209 }
210 }
211
212 pub fn get(&self, which: ITimerWhich) -> &ITimerState {
214 match which {
215 ITimerWhich::Real => &self.real,
216 ITimerWhich::Virtual => &self.virtual_timer,
217 ITimerWhich::Prof => &self.prof,
218 }
219 }
220
221 pub fn check_all(&self, current_time_ns: u64) -> alloc::vec::Vec<(ITimerWhich, u32)> {
224 use alloc::vec::Vec;
225 let mut expired = Vec::new();
226
227 if self.real.check_expired(current_time_ns) {
228 expired.push((ITimerWhich::Real, ITimerWhich::Real.signal()));
229 }
230 if self.virtual_timer.check_expired(current_time_ns) {
231 expired.push((ITimerWhich::Virtual, ITimerWhich::Virtual.signal()));
232 }
233 if self.prof.check_expired(current_time_ns) {
234 expired.push((ITimerWhich::Prof, ITimerWhich::Prof.signal()));
235 }
236
237 expired
238 }
239}
240
241pub fn tick_all_timers(current_time_ns: u64) {
248 use crate::process::{scheduler::GLOBAL_SCHED_STATE, signal::Signal};
249
250 let mut scheduler = match GLOBAL_SCHED_STATE.try_lock_no_irqsave() {
253 Some(guard) => guard,
254 None => {
255 return;
256 }
257 };
258 scheduler.with_mut_and_token(|slot, _token| {
259 let Some(sched) = slot.as_ref() else {
260 return;
261 };
262 let n_tasks = sched.all_tasks.len();
263 if n_tasks == 0 {
264 return;
265 }
266 let mut task_n: usize = 0;
267 for task in sched.all_tasks.values() {
268 unsafe {}
269 for which in [ITimerWhich::Real, ITimerWhich::Virtual, ITimerWhich::Prof] {
270 if task.itimers.get(which).check_expired(current_time_ns) {
271 if let Some(sig) = Signal::from_u32(which.signal()) {
272 task.pending_signals.add(sig);
273 }
274 }
275 }
276 task_n += 1;
277 if task_n > n_tasks.saturating_add(1) {
280 unsafe {}
281 break;
282 }
283 }
284 });
285}