1use core::fmt::Display;
4use core::{borrow::Borrow, ffi::c_void};
5
6use hal::stack::{FinFn, Stacklike};
7use hal::{Stack, stack::EntryFn};
8use proc_macros::TaggedLinks;
9
10use crate::error::Result;
11use crate::sched::task::{self, KERNEL_TASK};
12use crate::types::list;
13use crate::types::{
14 rbtree::{self, Compare},
15 traits::{Project, ToIndex},
16};
17use crate::uapi;
18
19pub const IDLE_THREAD: UId = UId {
20 uid: 0,
21 tid: Id {
22 id: 0,
23 owner: KERNEL_TASK,
24 },
25};
26
27#[proc_macros::fmt]
29#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
30pub struct Id {
31 id: usize,
32 owner: task::UId,
33}
34
35#[allow(dead_code)]
36impl Id {
37 pub fn new(id: usize, owner: task::UId) -> Self {
38 Self { id, owner }
39 }
40
41 pub fn as_usize(&self) -> usize {
42 self.id
43 }
44
45 pub fn owner(&self) -> task::UId {
46 self.owner
47 }
48
49 pub fn get_uid(&self, uid: usize) -> UId {
50 UId { uid, tid: *self }
51 }
52}
53
54#[proc_macros::fmt]
56#[derive(Clone, Copy)]
57#[allow(dead_code)]
58pub struct UId {
59 uid: usize,
61 tid: Id,
63}
64
65#[allow(dead_code)]
66impl UId {
67 pub fn new(uid: usize, tid: Id) -> Self {
68 Self { uid, tid }
69 }
70
71 pub fn tid(&self) -> Id {
72 self.tid
73 }
74
75 pub fn as_usize(&self) -> usize {
76 self.uid
77 }
78
79 pub fn owner(&self) -> task::UId {
80 self.tid.owner()
81 }
82}
83
84impl PartialEq for UId {
85 fn eq(&self, other: &Self) -> bool {
86 self.uid == other.uid
87 }
88}
89
90impl Eq for UId {}
91
92impl Into<usize> for UId {
93 fn into(self) -> usize {
94 self.uid
95 }
96}
97
98impl PartialOrd for UId {
99 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
100 Some(self.cmp(other))
101 }
102}
103
104impl Ord for UId {
105 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
106 self.uid.cmp(&other.uid)
107 }
108}
109
110impl ToIndex for UId {
111 fn to_index<Q: Borrow<Self>>(idx: Option<Q>) -> usize {
112 idx.as_ref().map_or(0, |k| k.borrow().uid)
113 }
114}
115
116impl Display for UId {
117 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
118 write!(f, "{}-{}", self.tid.owner(), self.tid.as_usize())
119 }
120}
121
122#[proc_macros::fmt]
126#[derive(Clone, Copy, PartialEq, Eq)]
127#[allow(dead_code)]
128pub enum RunState {
129 Runs,
131 Ready,
133 Waits,
135}
136
137#[proc_macros::fmt]
138#[derive(Clone, Copy)]
139pub struct State {
140 run_state: RunState,
141 stack: Stack,
142}
143
144#[proc_macros::fmt]
145#[derive(Clone, Copy, TaggedLinks)]
146pub struct RtServer {
147 budget: u32,
148 budget_left: u32,
149 period: u32,
150 deadline: u64,
151
152 uid: UId,
154
155 #[rbtree(tag = RtTree, idx = UId)]
157 _rt_links: rbtree::Links<RtTree, UId>,
158}
159
160impl RtServer {
161 pub fn new(budget: u32, period: u32, deadline: u64, uid: UId) -> Self {
162 Self {
163 budget,
164 budget_left: budget,
165 period,
166 deadline,
167 uid,
168 _rt_links: rbtree::Links::new(),
169 }
170 }
171
172 #[allow(dead_code)]
173 pub fn budget_left(&self) -> u32 {
174 self.budget_left
175 }
176
177 pub fn budget(&self) -> u32 {
178 self.budget
179 }
180
181 fn violates_sched(&self, now: u64) -> bool {
182 self.budget_left as u64 * self.period as u64
183 > self.budget as u64 * (self.deadline.saturating_sub(now))
184 }
185
186 pub fn on_wakeup(&mut self, now: u64) {
187 if self.deadline <= now || self.violates_sched(now) {
188 self.deadline = now + self.period as u64;
189 self.budget_left = self.budget;
190 }
191 }
192
193 #[allow(dead_code)]
194 pub fn replenish(&mut self) {
195 self.deadline = self.deadline + self.period as u64;
196 self.budget_left += self.budget;
197 }
198
199 pub fn consume(&mut self, dt: u64) -> Option<u64> {
200 self.budget_left = self.budget_left.saturating_sub(dt as u32);
201
202 if self.budget_left == 0 {
203 return Some(self.deadline);
204 }
205
206 None
207 }
208
209 #[allow(dead_code)]
210 pub fn deadline(&self) -> u64 {
211 self.deadline
212 }
213
214 #[allow(dead_code)]
215 pub fn uid(&self) -> UId {
216 self.uid
217 }
218}
219
220impl Compare<RtTree, UId> for RtServer {
221 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
222 let ord = self.deadline.cmp(&other.deadline);
223
224 if ord == core::cmp::Ordering::Equal {
225 self.uid.cmp(&other.uid)
226 } else {
227 ord
228 }
229 }
230}
231
232#[proc_macros::fmt]
233#[derive(Clone, Copy, TaggedLinks)]
234pub struct Waiter {
235 until: u64,
237
238 uid: UId,
240 #[rbtree(tag = WakupTree, idx = UId)]
242 _wakeup_links: rbtree::Links<WakupTree, UId>,
243}
244
245impl Waiter {
246 pub fn new(until: u64, uid: UId) -> Self {
247 Self {
248 until,
249 uid,
250 _wakeup_links: rbtree::Links::new(),
251 }
252 }
253
254 pub fn until(&self) -> u64 {
255 self.until
256 }
257
258 #[allow(dead_code)]
259 pub fn set_until(&mut self, until: u64) {
260 self.until = until;
261 }
262}
263
264impl Compare<WakupTree, UId> for Waiter {
265 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
266 match self.until.cmp(&other.until) {
267 core::cmp::Ordering::Equal => self.uid.cmp(&other.uid),
268 ord => ord,
269 }
270 }
271}
272
273#[proc_macros::fmt]
274#[derive(Clone, Copy)]
275pub struct WakupTree;
276#[proc_macros::fmt]
277#[derive(Clone, Copy)]
278pub struct RtTree;
279
280#[proc_macros::fmt]
281#[derive(Clone, Copy)]
282pub struct RRList;
283
284#[proc_macros::fmt]
285#[derive(Clone, Copy)]
286pub struct ThreadList;
287
288pub struct Attributes {
289 pub entry: EntryFn,
290 pub fin: Option<FinFn>,
291 pub attrs: Option<uapi::sched::RtAttrs>,
292}
293
294#[proc_macros::fmt]
296#[derive(Clone, Copy, TaggedLinks)]
297pub struct Thread {
298 state: State,
300 uid: UId,
302 rt_server: Option<RtServer>,
304
305 waiter: Option<Waiter>,
306
307 #[list(tag = RRList, idx = UId)]
308 rr_links: list::Links<RRList, UId>,
309
310 #[list(tag = ThreadList, idx = UId)]
311 thread_links: list::Links<ThreadList, UId>,
312}
313
314#[allow(dead_code)]
315impl Thread {
316 pub fn new(uid: UId, stack: Stack, rtattrs: Option<uapi::sched::RtAttrs>) -> Self {
322 let server =
323 rtattrs.map(|attrs| RtServer::new(attrs.budget, attrs.period, attrs.deadline, uid));
324 Self {
325 state: State {
326 run_state: RunState::Ready,
327 stack,
328 },
329 uid,
330 rt_server: server,
331 waiter: None,
332 rr_links: list::Links::new(),
333 thread_links: list::Links::new(),
334 }
335 }
336
337 pub fn set_waiter(&mut self, waiter: Option<Waiter>) {
338 self.waiter = waiter;
339 }
340
341 pub fn waiter(&self) -> Option<&Waiter> {
342 self.waiter.as_ref()
343 }
344
345 pub fn save_ctx(&mut self, ctx: *mut c_void) -> Result<()> {
346 let sp = self.state.stack.create_sp(ctx)?;
347 self.state.stack.set_sp(sp);
348 Ok(())
349 }
350
351 pub fn set_run_state(&mut self, state: RunState) {
352 self.state.run_state = state;
353 }
354
355 pub fn rt_server(&self) -> Option<&RtServer> {
356 self.rt_server.as_ref()
357 }
358
359 pub fn ctx(&self) -> *mut c_void {
360 self.state.stack.sp()
361 }
362
363 pub fn uid(&self) -> UId {
364 self.uid
365 }
366
367 pub fn task_id(&self) -> task::UId {
368 self.uid.tid().owner()
369 }
370}
371
372impl PartialEq for Thread {
373 fn eq(&self, other: &Self) -> bool {
374 self.uid == other.uid
375 }
376}
377
378impl Project<RtServer> for Thread {
379 fn project(&self) -> Option<&RtServer> {
380 self.rt_server.as_ref()
381 }
382
383 fn project_mut(&mut self) -> Option<&mut RtServer> {
384 self.rt_server.as_mut()
385 }
386}
387
388impl Project<Waiter> for Thread {
389 fn project(&self) -> Option<&Waiter> {
390 self.waiter.as_ref()
391 }
392
393 fn project_mut(&mut self) -> Option<&mut Waiter> {
394 self.waiter.as_mut()
395 }
396}