use super::*; use consts::MAX_PROCESS_NUM; use alloc::BinaryHeap; /// pub trait Scheduler { fn insert(&mut self, pid: Pid); fn remove(&mut self, pid: Pid); fn select(&mut self) -> Option; fn tick(&mut self, current: Pid) -> bool; // need reschedule? } pub use self::rr::RRScheduler; pub use self::stride::StrideScheduler; mod rr { use super::*; pub struct RRScheduler { max_time_slice: usize, infos: [RRProcInfo; MAX_PROCESS_NUM], } #[derive(Debug, Default, Copy, Clone)] struct RRProcInfo { present: bool, rest_slice: usize, prev: Pid, next: Pid, } impl Scheduler for RRScheduler { fn insert(&mut self, pid: Pid) { let pid = pid + 1; { let info = &mut self.infos[pid]; assert!(!info.present); info.present = true; if info.rest_slice == 0 { info.rest_slice = self.max_time_slice; } } self._list_add_before(pid, 0); debug!("insert {}", pid - 1); } fn remove(&mut self, pid: Pid) { let pid = pid + 1; assert!(self.infos[pid].present); self.infos[pid].present = false; self._list_remove(pid); debug!("remove {}", pid - 1); } fn select(&mut self) -> Option { let ret = match self.infos[0].next { 0 => None, i => Some(i - 1), }; debug!("select {:?}", ret); ret } fn tick(&mut self, current: Pid) -> bool { let current = current + 1; assert!(!self.infos[current].present); let rest = &mut self.infos[current].rest_slice; if *rest > 0 { *rest -= 1; } else { warn!("current process rest_slice = 0, need reschedule") } *rest == 0 } } impl RRScheduler { pub fn new(max_time_slice: usize) -> Self { RRScheduler { max_time_slice, infos: [RRProcInfo::default(); MAX_PROCESS_NUM], } } fn _list_add_before(&mut self, i: Pid, at: Pid) { let prev = self.infos[at].prev; self.infos[i].next = at; self.infos[i].prev = prev; self.infos[prev].next = i; self.infos[at].prev = i; } fn _list_remove(&mut self, i: Pid) { let next = self.infos[i].next; let prev = self.infos[i].prev; self.infos[next].prev = prev; self.infos[prev].next = next; self.infos[i].next = 0; self.infos[i].prev = 0; } } } mod stride { use super::*; pub struct StrideScheduler { max_time_slice: usize, infos: [StrideProcInfo; MAX_PROCESS_NUM], queue: BinaryHeap<(Stride, Pid)>, // It's max heap, so pass < 0 } #[derive(Debug, Default, Copy, Clone)] struct StrideProcInfo { present: bool, rest_slice: usize, stride: Stride, priority: u8, } impl StrideProcInfo { fn pass(&mut self) { const BIG_STRIDE: Stride = 1 << 20; let pass = if self.priority == 0 { BIG_STRIDE } else { BIG_STRIDE / self.priority as Stride }; // FIXME: overflowing_add is not working ??? // self.stride.overflowing_add(pass); self.stride += pass; } } type Stride = i32; impl Scheduler for StrideScheduler { fn insert(&mut self, pid: Pid) { let info = &mut self.infos[pid]; assert!(!info.present); info.present = true; if info.rest_slice == 0 { info.rest_slice = self.max_time_slice; } self.queue.push((-info.stride, pid)); debug!("insert {}", pid); } fn remove(&mut self, pid: Pid) { let info = &mut self.infos[pid]; assert!(info.present); info.present = false; // FIXME: Support removing any element assert_eq!(self.queue.pop().unwrap().1, pid, "Can only remove the top"); debug!("remove {}", pid); } fn select(&mut self) -> Option { let ret = self.queue.peek().map(|&(_, pid)| pid); if let Some(pid) = ret { let old_stride = self.infos[pid].stride; self.infos[pid].pass(); let stride = self.infos[pid].stride; debug!("{} stride {:#x} -> {:#x}", pid, old_stride, stride); } debug!("select {:?}", ret); ret } fn tick(&mut self, current: Pid) -> bool { assert!(!self.infos[current].present); let rest = &mut self.infos[current].rest_slice; if *rest > 0 { *rest -= 1; } else { warn!("current process rest_slice = 0, need reschedule") } *rest == 0 } } impl StrideScheduler { pub fn new(max_time_slice: usize) -> Self { StrideScheduler { max_time_slice, infos: [StrideProcInfo::default(); MAX_PROCESS_NUM], queue: BinaryHeap::new(), } } pub fn set_priority(&mut self, pid: Pid, priority: u8) { self.infos[pid].priority = priority; debug!("{} priority = {}", pid, priority); } } }