osiris/sched/
rt.rs

1use crate::{
2    error::Result,
3    sched::{
4        ThreadMap,
5        thread::{self},
6    },
7    types::{
8        rbtree::RbTree,
9        traits::{Get, GetMut},
10        view::ViewMut,
11    },
12};
13
14pub struct Scheduler<const N: usize> {
15    edf: RbTree<thread::RtTree, thread::UId>,
16}
17
18pub type ServerView<'a, const N: usize> = ViewMut<'a, thread::UId, thread::RtServer, ThreadMap<N>>;
19
20impl<const N: usize> Scheduler<N> {
21    pub const fn new() -> Self {
22        Self { edf: RbTree::new() }
23    }
24
25    pub fn enqueue(
26        &mut self,
27        uid: thread::UId,
28        now: u64,
29        storage: &mut ServerView<N>,
30    ) -> Result<()> {
31        if let Some(server) = storage.get_mut(uid) {
32            // Threads are only enqueued when they are runnable.
33            server.on_wakeup(now);
34            self.edf.insert(uid, storage)?;
35        }
36        Ok(())
37    }
38
39    /// This should be called on each do_schedule call, to update the internal scheduler state.
40    /// If this function returns Some(u64) it means the current thread has exhausted its budget and should be throttled until the returned timestamp.
41    pub fn put(&mut self, uid: thread::UId, dt: u64, storage: &mut ServerView<N>) -> Option<u64> {
42        if Some(uid) == self.edf.min() {
43            if let Some(server) = storage.get_mut(uid) {
44                return server.consume(dt);
45            } else {
46                bug!("thread {} not found in storage", uid);
47            }
48        }
49
50        None
51    }
52
53    pub fn pick(&mut self, storage: &mut ServerView<N>) -> Option<(thread::UId, u32)> {
54        self.edf
55            .min()
56            .and_then(|id| storage.get(id).map(|s| (id, s.budget())))
57    }
58
59    pub fn dequeue(&mut self, uid: thread::UId, storage: &mut ServerView<N>) -> Result<()> {
60        self.edf.remove(uid, storage)
61    }
62}