use arraydeque::ArrayDeque;
use crate::interrupts::TIMER_MS;
use super::Scheduler;
use super::APPS;
pub struct BellRinger {
bells: ArrayDeque<Bell, APPS>,
}
#[derive(Debug, Clone)]
struct Bell {
thread: usize,
offset: usize,
}
impl Bell {
fn new(thread: usize, offset: usize) -> Self {
Self { thread, offset }
}
}
impl BellRinger {
pub const fn new() -> Self {
Self {
bells: ArrayDeque::new(),
}
}
pub fn sleep(&mut self, scheduler: &mut Scheduler, ms: usize) {
let tid = scheduler.active().expect("No running thread!");
let ticks = ms * TIMER_MS;
let mut total = 0;
let larger = self.bells.iter().position(|bell| {
if (total + bell.offset) > ticks {
true
} else {
total += bell.offset;
false
}
});
let offset = ticks - total;
if let Some(larger) = larger {
self.bells.get_mut(larger).unwrap().offset -= offset;
self.bells.insert(larger, Bell::new(tid, offset)).unwrap();
} else {
self.bells.push_back(Bell::new(tid, ticks)).unwrap();
}
scheduler.resume(false);
}
pub fn check(&mut self, scheduler: &mut Scheduler) {
let mut ticks = 1;
while let Some(bell) = self.bells.pop_front() {
if bell.offset <= ticks {
ticks -= bell.offset;
scheduler.ready(bell.thread);
} else {
self.bells
.push_front(Bell::new(bell.thread, bell.offset - 1))
.unwrap();
break;
}
}
}
pub fn is_empty(&self) -> bool {
self.bells.is_empty()
}
}