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