strat9_kernel/process/sched_classes/
real_time.rs1use super::{CurrentRuntime, SchedClassRq};
4use crate::{arch::x86_64::timer::TIMER_HZ, process::task::Task};
5use alloc::sync::Arc;
6use intrusive_collections::{intrusive_adapter, LinkedList, LinkedListLink};
7
8const RT_RR_QUANTUM_TICKS: u64 = TIMER_HZ / 10;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
16pub struct RealTimePriority(u8);
17
18impl RealTimePriority {
19 pub const MIN: Self = Self(0);
20 pub const MAX: Self = Self(99);
21
22 pub fn new(prio: u8) -> Self {
24 Self(prio.clamp(Self::MIN.0, Self::MAX.0))
25 }
26
27 pub fn get(self) -> u8 {
29 self.0
30 }
31}
32
33intrusive_adapter!(pub RtTaskAdapter = Arc<Task>: Task { rt_link: LinkedListLink });
37
38struct RtPrioQueue {
40 list: LinkedList<RtTaskAdapter>,
41 len: usize,
42}
43
44impl RtPrioQueue {
45 fn new() -> Self {
46 Self {
47 list: LinkedList::new(RtTaskAdapter::new()),
48 len: 0,
49 }
50 }
51
52 fn push_back(&mut self, task: Arc<Task>) {
53 self.list.push_back(task);
54 self.len += 1;
55 }
56
57 fn pop_front(&mut self) -> Option<Arc<Task>> {
58 let task = self.list.pop_front()?;
59 self.len -= 1;
60 Some(task)
61 }
62
63 fn is_empty(&self) -> bool {
64 self.len == 0
65 }
66
67 fn remove_by_id(&mut self, task_id: crate::process::TaskId) -> bool {
72 let mut cursor = self.list.front_mut();
73 loop {
74 match cursor.get() {
75 None => return false,
76 Some(task) if task.id == task_id => {
77 let _ = cursor.remove();
80 self.len -= 1;
81 return true;
82 }
83 Some(_) => cursor.move_next(),
84 }
85 }
86 }
87}
88
89pub struct RealTimeClassRq {
90 queues: [RtPrioQueue; 100],
91 bitmap: u128, }
93
94impl RealTimeClassRq {
95 pub fn new() -> Self {
97 Self {
98 queues: core::array::from_fn(|_| RtPrioQueue::new()),
99 bitmap: 0,
100 }
101 }
102
103 fn set_bit(&mut self, prio: u8) {
105 self.bitmap |= 1u128 << prio;
106 }
107
108 fn clear_bit(&mut self, prio: u8) {
110 self.bitmap &= !(1u128 << prio);
111 }
112}
113
114impl SchedClassRq for RealTimeClassRq {
115 fn enqueue(&mut self, task: Arc<Task>) {
117 let prio = match task.sched_policy() {
118 super::SchedPolicy::RealTimeRR { prio } => prio.get(),
119 super::SchedPolicy::RealTimeFifo { prio } => prio.get(),
120 _ => return, };
122 self.queues[prio as usize].push_back(task);
123 self.set_bit(prio);
124 }
125
126 fn len(&self) -> usize {
128 self.queues.iter().map(|q| q.len).sum()
129 }
130
131 fn pick_next(&mut self) -> Option<Arc<Task>> {
133 if self.bitmap == 0 {
134 return None;
135 }
136 let highest = 127 - self.bitmap.leading_zeros() as u8;
138 let q = &mut self.queues[highest as usize];
139 let task = q.pop_front()?;
140 if q.is_empty() {
141 self.clear_bit(highest);
142 }
143 Some(task)
144 }
145
146 fn update_current(&mut self, rt: &CurrentRuntime, task: &Task, is_yield: bool) -> bool {
148 if is_yield {
149 return true;
150 }
151 match task.sched_policy() {
152 super::SchedPolicy::RealTimeRR { .. } => {
153 rt.period_delta_ticks >= RT_RR_QUANTUM_TICKS
155 }
156 super::SchedPolicy::RealTimeFifo { .. } => {
157 false
159 }
160 _ => false,
161 }
162 }
163
164 fn remove(&mut self, task_id: crate::process::TaskId) -> bool {
166 let mut bits = self.bitmap;
167 while bits != 0 {
168 let i = bits.trailing_zeros() as usize;
169 if self.queues[i].remove_by_id(task_id) {
170 if self.queues[i].is_empty() {
171 self.clear_bit(i as u8);
172 }
173 return true;
175 }
176 bits &= !(1u128 << i);
177 }
178 false
179 }
180}