strat9_kernel/process/sched_classes/
mod.rs1pub mod fair;
6pub mod idle;
7pub mod nice;
8pub mod real_time;
9
10use crate::process::task::Task;
11use alloc::sync::Arc;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum SchedPolicy {
16 Fair(nice::Nice),
18 RealTimeRR { prio: real_time::RealTimePriority },
20 RealTimeFifo { prio: real_time::RealTimePriority },
22 Idle,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum SchedPolicyKind {
28 Fair,
29 RealTime,
30 Idle,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum SchedClassId {
35 RealTime,
36 Fair,
37 Idle,
38}
39
40impl SchedClassId {
41 pub const ALL: [Self; 3] = [Self::RealTime, Self::Fair, Self::Idle];
42
43 pub const fn as_str(self) -> &'static str {
45 match self {
46 Self::RealTime => "rt",
47 Self::Fair => "fair",
48 Self::Idle => "idle",
49 }
50 }
51
52 pub fn parse(s: &str) -> Option<Self> {
54 if s.eq_ignore_ascii_case("rt")
55 || s.eq_ignore_ascii_case("real-time")
56 || s.eq_ignore_ascii_case("realtime")
57 {
58 Some(Self::RealTime)
59 } else if s.eq_ignore_ascii_case("fair") {
60 Some(Self::Fair)
61 } else if s.eq_ignore_ascii_case("idle") {
62 Some(Self::Idle)
63 } else {
64 None
65 }
66 }
67}
68
69#[derive(Debug, Clone, Copy)]
70pub struct SchedClassEntry {
71 pub id: SchedClassId,
72 pub name: &'static str,
73 pub rank: u8,
74}
75
76#[derive(Debug, Clone, Copy)]
77pub struct SchedClassTable {
78 entries: [SchedClassEntry; 3],
79 pick_order: [SchedClassId; 3],
80 steal_order: [SchedClassId; 2],
81 policy_map: [SchedClassId; 3], }
83
84impl Default for SchedClassTable {
85 fn default() -> Self {
87 Self {
88 entries: [
89 SchedClassEntry {
90 id: SchedClassId::RealTime,
91 name: "real-time",
92 rank: 0,
93 },
94 SchedClassEntry {
95 id: SchedClassId::Fair,
96 name: "fair",
97 rank: 1,
98 },
99 SchedClassEntry {
100 id: SchedClassId::Idle,
101 name: "idle",
102 rank: 2,
103 },
104 ],
105 pick_order: [
106 SchedClassId::RealTime,
107 SchedClassId::Fair,
108 SchedClassId::Idle,
109 ],
110 steal_order: [SchedClassId::Fair, SchedClassId::RealTime],
111 policy_map: [
112 SchedClassId::Fair,
113 SchedClassId::RealTime,
114 SchedClassId::Idle,
115 ],
116 }
117 }
118}
119
120impl SchedClassTable {
121 pub fn new(pick_order: [SchedClassId; 3], steal_order: [SchedClassId; 2]) -> Self {
123 let mut out = Self::default();
124 let _ = out.set_pick_order(pick_order);
125 let _ = out.set_steal_order(steal_order);
126 out
127 }
128
129 fn kind_index(kind: SchedPolicyKind) -> usize {
131 match kind {
132 SchedPolicyKind::Fair => 0,
133 SchedPolicyKind::RealTime => 1,
134 SchedPolicyKind::Idle => 2,
135 }
136 }
137
138 fn class_index(class: SchedClassId) -> usize {
140 match class {
141 SchedClassId::RealTime => 0,
142 SchedClassId::Fair => 1,
143 SchedClassId::Idle => 2,
144 }
145 }
146
147 fn refresh_ranks(&mut self) {
149 for entry in self.entries.iter_mut() {
150 entry.rank = match entry.id {
151 SchedClassId::RealTime => 255,
152 SchedClassId::Fair => 255,
153 SchedClassId::Idle => 255,
154 };
155 }
156 for (idx, class) in self.pick_order.iter().copied().enumerate() {
157 for entry in self.entries.iter_mut() {
158 if entry.id == class {
159 entry.rank = idx as u8;
160 break;
161 }
162 }
163 }
164 }
165
166 pub fn validate(&self) -> bool {
168 let mut seen = [false; 3];
169 for class in self.pick_order.iter().copied() {
170 seen[Self::class_index(class)] = true;
171 }
172 for class in SchedClassId::ALL.iter().copied() {
173 if !seen[Self::class_index(class)] {
174 return false;
175 }
176 }
177
178 if self.steal_order[0] == self.steal_order[1] {
179 return false;
180 }
181 if self.steal_order.iter().any(|c| *c == SchedClassId::Idle) {
182 return false;
183 }
184
185 if self.policy_map[Self::kind_index(SchedPolicyKind::Idle)] != SchedClassId::Idle {
186 return false;
187 }
188 if self.policy_map[Self::kind_index(SchedPolicyKind::Fair)] == SchedClassId::Idle {
189 return false;
190 }
191 if self.policy_map[Self::kind_index(SchedPolicyKind::RealTime)] == SchedClassId::Idle {
192 return false;
193 }
194 true
195 }
196
197 pub fn entries(&self) -> &[SchedClassEntry; 3] {
199 &self.entries
200 }
201
202 pub fn pick_order(&self) -> &[SchedClassId; 3] {
204 &self.pick_order
205 }
206
207 pub fn steal_order(&self) -> &[SchedClassId; 2] {
209 &self.steal_order
210 }
211
212 pub fn policy_class(&self, kind: SchedPolicyKind) -> SchedClassId {
214 self.policy_map[Self::kind_index(kind)]
215 }
216
217 pub fn policy_map(&self) -> &[SchedClassId; 3] {
219 &self.policy_map
220 }
221
222 pub fn set_pick_order(&mut self, pick_order: [SchedClassId; 3]) -> bool {
224 let prev = self.pick_order;
225 self.pick_order = pick_order;
226 if !self.validate() {
227 self.pick_order = prev;
228 return false;
229 }
230 self.refresh_ranks();
231 true
232 }
233
234 pub fn set_steal_order(&mut self, steal_order: [SchedClassId; 2]) -> bool {
236 let prev = self.steal_order;
237 self.steal_order = steal_order;
238 if !self.validate() {
239 self.steal_order = prev;
240 return false;
241 }
242 true
243 }
244
245 pub fn set_policy_class(&mut self, kind: SchedPolicyKind, class: SchedClassId) -> bool {
247 let idx = Self::kind_index(kind);
248 let prev = self.policy_map[idx];
249 self.policy_map[idx] = class;
250 if !self.validate() {
251 self.policy_map[idx] = prev;
252 return false;
253 }
254 true
255 }
256
257 pub fn class_for_policy(&self, policy: SchedPolicy) -> SchedClassId {
259 self.policy_class(policy.kind())
260 }
261
262 pub fn class_for_task(&self, task: &Task) -> SchedClassId {
264 self.class_for_policy(task.sched_policy())
265 }
266}
267
268impl SchedPolicy {
269 pub fn kind(&self) -> SchedPolicyKind {
271 match self {
272 Self::Fair(_) => SchedPolicyKind::Fair,
273 Self::RealTimeRR { .. } | Self::RealTimeFifo { .. } => SchedPolicyKind::RealTime,
274 Self::Idle => SchedPolicyKind::Idle,
275 }
276 }
277}
278
279impl SchedPolicyKind {
280 pub fn as_str(self) -> &'static str {
282 match self {
283 Self::Fair => "fair",
284 Self::RealTime => "rt",
285 Self::Idle => "idle",
286 }
287 }
288
289 pub fn parse(s: &str) -> Option<Self> {
291 if s.eq_ignore_ascii_case("fair") {
292 Some(Self::Fair)
293 } else if s.eq_ignore_ascii_case("rt")
294 || s.eq_ignore_ascii_case("realtime")
295 || s.eq_ignore_ascii_case("real-time")
296 {
297 Some(Self::RealTime)
298 } else if s.eq_ignore_ascii_case("idle") {
299 Some(Self::Idle)
300 } else {
301 None
302 }
303 }
304}
305
306pub struct CurrentRuntime {
307 pub start_ticks: u64,
308 pub delta_ticks: u64,
309 pub period_delta_ticks: u64,
310}
311
312impl CurrentRuntime {
313 pub fn new() -> Self {
315 Self {
316 start_ticks: crate::process::scheduler::ticks(),
317 delta_ticks: 0,
318 period_delta_ticks: 0,
319 }
320 }
321
322 pub fn update(&mut self) {
324 let now = crate::process::scheduler::ticks();
325 self.delta_ticks = now.saturating_sub(core::mem::replace(&mut self.start_ticks, now));
326 self.period_delta_ticks += self.delta_ticks;
327 }
328}
329
330pub trait SchedClassRq {
331 fn enqueue(&mut self, task: Arc<Task>);
333 fn len(&self) -> usize;
335 fn is_empty(&self) -> bool {
337 self.len() == 0
338 }
339 fn pick_next(&mut self) -> Option<Arc<Task>>;
341 fn update_current(&mut self, rt: &CurrentRuntime, task: &Task, is_yield: bool) -> bool;
343 fn remove(&mut self, task_id: crate::process::TaskId) -> bool;
345}