osiris/sched/
rr.rs

1use crate::{
2    error::Result,
3    sched::thread::{self},
4    types::list::List,
5};
6
7pub struct Scheduler<const N: usize> {
8    queue: List<thread::RRList, thread::UId>,
9
10    current: Option<thread::UId>,
11    current_left: u32,
12    quantum: u32,
13}
14
15impl<const N: usize> Scheduler<N> {
16    pub const fn new() -> Self {
17        // TODO: Make quantum configurable.
18        Self {
19            queue: List::new(),
20            current: None,
21            current_left: 0,
22            quantum: 1000,
23        }
24    }
25
26    pub fn enqueue(&mut self, uid: thread::UId, storage: &mut super::ThreadMap<N>) -> Result<()> {
27        self.queue
28            .push_back(uid, storage)
29            .map_err(|_| kerr!(InvalidArgument))
30    }
31
32    pub fn put(&mut self, uid: thread::UId, dt: u32) {
33        if let Some(current) = self.current {
34            if current == uid {
35                self.current_left = self.current_left.saturating_sub(dt);
36            }
37        }
38    }
39
40    pub fn pick(&mut self, storage: &mut super::ThreadMap<N>) -> Option<(thread::UId, u32)> {
41        match self.current {
42            Some(current) if self.current_left > 0 => return Some((current, self.current_left)),
43            Some(current) => {
44                if self.queue.pop_front(storage).is_err() {
45                    // If this happens, it means the internal state was corrupted.
46                    // We cannot meaningfully continue, so we panic.
47                    bug!("current thread not found in queue");
48                }
49                if self.queue.push_back(current, storage).is_err() {
50                    // We popped the current thread from the queue, so it must be able to be pushed back.
51                    // The scheduler is run exclusively so the space cannot be taken by another thread.
52                    bug!("cannot push current thread back to queue");
53                }
54
55                self.current = self.queue.head();
56                self.current_left = self.quantum;
57            }
58            None => {
59                self.current = self.queue.head();
60                self.current_left = self.quantum;
61            }
62        }
63
64        self.current.map(|id| (id, self.current_left))
65    }
66
67    pub fn dequeue(&mut self, uid: thread::UId, storage: &mut super::ThreadMap<N>) -> Result<()> {
68        self.queue.remove(uid, storage)?;
69
70        if self.current == Some(uid) {
71            self.current = None;
72        }
73
74        Ok(())
75    }
76}