1use 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 {
85 (self.tv_sec as u64)
86 .saturating_mul(1_000_000_000)
87 .saturating_add((self.tv_usec as u64).saturating_mul(1_000))
88 }
89
90 pub fn from_nanos(nanos: u64) -> Self {
92 let tv_sec = (nanos / 1_000_000_000) as i64;
93 let tv_usec = ((nanos % 1_000_000_000) / 1_000) as i64;
94 Self { tv_sec, tv_usec }
95 }
96}
97
98pub struct ITimerState {
100 next_expiration: AtomicU64,
102 interval_ns: AtomicU64,
104 armed: AtomicBool,
106}
107
108impl ITimerState {
109 pub const fn new() -> Self {
111 Self {
112 next_expiration: AtomicU64::new(0),
113 interval_ns: AtomicU64::new(0),
114 armed: AtomicBool::new(false),
115 }
116 }
117
118 pub fn get(&self, current_time_ns: u64) -> ITimerVal {
120 let next = self.next_expiration.load(Ordering::Relaxed);
121 let interval = self.interval_ns.load(Ordering::Relaxed);
122
123 let value_ns = if next > current_time_ns {
124 next - current_time_ns
125 } else {
126 0
127 };
128
129 ITimerVal {
130 it_interval: TimeVal::from_nanos(interval),
131 it_value: TimeVal::from_nanos(value_ns),
132 }
133 }
134
135 pub fn set(&self, value: &ITimerVal, current_time_ns: u64) {
137 let (interval_ns, value_ns) = value.to_nanos();
138
139 if value_ns == 0 {
140 self.armed.store(false, Ordering::Release);
141 self.next_expiration.store(0, Ordering::Relaxed);
142 self.interval_ns.store(interval_ns, Ordering::Relaxed);
143 } else {
144 self.interval_ns.store(interval_ns, Ordering::Relaxed);
145 let next = current_time_ns.saturating_add(value_ns);
146 self.next_expiration.store(next, Ordering::Relaxed);
147 self.armed.store(true, Ordering::Release);
148 }
149 }
150
151 pub fn check_expired(&self, current_time_ns: u64) -> bool {
153 if !self.armed.load(Ordering::Acquire) {
154 return false;
155 }
156
157 let next = self.next_expiration.load(Ordering::Relaxed);
158 if current_time_ns >= next && next != 0 {
159 let interval = self.interval_ns.load(Ordering::Relaxed);
160 if interval == 0 {
161 self.armed.store(false, Ordering::Release);
162 self.next_expiration.store(0, Ordering::Relaxed);
163 } else {
164 let new_next = next.saturating_add(interval);
166 let new_next = if new_next <= current_time_ns {
167 current_time_ns.saturating_add(interval)
168 } else {
169 new_next
170 };
171 self.next_expiration.store(new_next, Ordering::Relaxed);
172 }
173 true
174 } else {
175 false
176 }
177 }
178
179 pub fn disarm(&self) {
181 self.armed.store(false, Ordering::Release);
182 self.next_expiration.store(0, Ordering::Relaxed);
183 self.interval_ns.store(0, Ordering::Relaxed);
184 }
185}
186
187pub struct ITimers {
189 pub real: ITimerState,
190 pub virtual_timer: ITimerState,
191 pub prof: ITimerState,
192}
193
194impl ITimers {
195 pub const fn new() -> Self {
197 Self {
198 real: ITimerState::new(),
199 virtual_timer: ITimerState::new(),
200 prof: ITimerState::new(),
201 }
202 }
203
204 pub fn get(&self, which: ITimerWhich) -> &ITimerState {
206 match which {
207 ITimerWhich::Real => &self.real,
208 ITimerWhich::Virtual => &self.virtual_timer,
209 ITimerWhich::Prof => &self.prof,
210 }
211 }
212
213 pub fn check_all(&self, current_time_ns: u64) -> alloc::vec::Vec<(ITimerWhich, u32)> {
216 use alloc::vec::Vec;
217 let mut expired = Vec::new();
218
219 if self.real.check_expired(current_time_ns) {
220 expired.push((ITimerWhich::Real, ITimerWhich::Real.signal()));
221 }
222 if self.virtual_timer.check_expired(current_time_ns) {
223 expired.push((ITimerWhich::Virtual, ITimerWhich::Virtual.signal()));
224 }
225 if self.prof.check_expired(current_time_ns) {
226 expired.push((ITimerWhich::Prof, ITimerWhich::Prof.signal()));
227 }
228
229 expired
230 }
231}
232
233pub fn tick_all_timers(current_time_ns: u64) {
240 use crate::process::{scheduler::GLOBAL_SCHED_STATE, signal::Signal};
241
242 unsafe { core::arch::asm!("mov al, '1'; out 0xe9, al", out("al") _) };
243 let mut scheduler = match GLOBAL_SCHED_STATE.try_lock_no_irqsave() {
246 Some(guard) => {
247 unsafe { core::arch::asm!("mov al, '2'; out 0xe9, al", out("al") _) };
248 guard
249 }
250 None => {
251 unsafe { core::arch::asm!("mov al, 'C'; out 0xe9, al", out("al") _) };
252 return;
253 }
254 };
255 unsafe { core::arch::asm!("mov al, '3'; out 0xe9, al", out("al") _) };
256 scheduler.with_mut_and_token(|slot, _token| {
257 unsafe { core::arch::asm!("mov al, 'w'; out 0xe9, al", out("al") _) };
258 let Some(sched) = slot.as_ref() else {
259 unsafe { core::arch::asm!("mov al, 'N'; out 0xe9, al", out("al") _) };
260 return;
261 };
262 unsafe { core::arch::asm!("mov al, '4'; out 0xe9, al", out("al") _) };
263 let n_tasks = sched.all_tasks_scan.len();
264 if n_tasks == 0 {
265 unsafe { core::arch::asm!("mov al, '0'; out 0xe9, al", out("al") _) };
266 return;
267 }
268 let mut task_n: usize = 0;
269 for task in sched.all_tasks_scan.iter() {
270 unsafe {
271 core::arch::asm!("mov al, '5'; out 0xe9, al", out("al") _);
272 }
273 for which in [ITimerWhich::Real, ITimerWhich::Virtual, ITimerWhich::Prof] {
274 if task.itimers.get(which).check_expired(current_time_ns) {
275 if let Some(sig) = Signal::from_u32(which.signal()) {
276 task.pending_signals.add(sig);
277 }
278 }
279 }
280 task_n += 1;
281 if task_n > n_tasks.saturating_add(1) {
284 unsafe {
285 core::arch::asm!("mov al, 'X'; out 0xe9, al", out("al") _);
286 }
287 break;
288 }
289 }
290 unsafe { core::arch::asm!("mov al, '6'; out 0xe9, al", out("al") _) };
291 });
292 unsafe { core::arch::asm!("mov al, '7'; out 0xe9, al", out("al") _) };
293}