parent
e678186b3d
commit
a224e85c8d
@ -1,242 +0,0 @@
|
|||||||
use alloc::{collections::BinaryHeap, vec::Vec};
|
|
||||||
use log::*;
|
|
||||||
|
|
||||||
type Pid = usize;
|
|
||||||
|
|
||||||
///
|
|
||||||
pub trait Scheduler {
|
|
||||||
fn insert(&mut self, pid: Pid);
|
|
||||||
fn remove(&mut self, pid: Pid);
|
|
||||||
fn select(&mut self) -> Option<Pid>;
|
|
||||||
fn tick(&mut self, current: Pid) -> bool; // need reschedule?
|
|
||||||
fn set_priority(&mut self, pid: Pid, priority: u8);
|
|
||||||
fn move_to_head(&mut self, pid: Pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use self::rr::RRScheduler;
|
|
||||||
pub use self::stride::StrideScheduler;
|
|
||||||
|
|
||||||
mod rr {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub struct RRScheduler {
|
|
||||||
max_time_slice: usize,
|
|
||||||
infos: Vec<RRProcInfo>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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;
|
|
||||||
expand(&mut self.infos, 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._list_add_before(pid, 0);
|
|
||||||
trace!("rr 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);
|
|
||||||
trace!("rr remove {}", pid - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn select(&mut self) -> Option<Pid> {
|
|
||||||
let ret = match self.infos[0].next {
|
|
||||||
0 => None,
|
|
||||||
i => Some(i - 1),
|
|
||||||
};
|
|
||||||
trace!("rr select {:?}", ret);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tick(&mut self, current: Pid) -> bool {
|
|
||||||
let current = current + 1;
|
|
||||||
expand(&mut self.infos, current);
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_priority(&mut self, _pid: usize, _priority: u8) {
|
|
||||||
}
|
|
||||||
|
|
||||||
fn move_to_head(&mut self, pid: usize) {
|
|
||||||
let pid = pid + 1;
|
|
||||||
assert!(self.infos[pid].present);
|
|
||||||
self._list_remove(pid);
|
|
||||||
self._list_add_after(pid, 0);
|
|
||||||
trace!("rr move_to_head {}", pid - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RRScheduler {
|
|
||||||
pub fn new(max_time_slice: usize) -> Self {
|
|
||||||
RRScheduler {
|
|
||||||
max_time_slice,
|
|
||||||
infos: Vec::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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_add_after(&mut self, i: Pid, at: Pid) {
|
|
||||||
let next = self.infos[at].next;
|
|
||||||
self._list_add_before(i, next);
|
|
||||||
}
|
|
||||||
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: Vec<StrideProcInfo>,
|
|
||||||
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) {
|
|
||||||
expand(&mut self.infos, 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));
|
|
||||||
trace!("stride insert {}", pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove(&mut self, pid: Pid) {
|
|
||||||
let info = &mut self.infos[pid];
|
|
||||||
assert!(info.present);
|
|
||||||
info.present = false;
|
|
||||||
if self.queue.peek().is_some() && self.queue.peek().unwrap().1 == pid {
|
|
||||||
self.queue.pop();
|
|
||||||
} else {
|
|
||||||
// BinaryHeap only support pop the top.
|
|
||||||
// So in order to remove an arbitrary element,
|
|
||||||
// we have to take all elements into a Vec,
|
|
||||||
// then push the rest back.
|
|
||||||
let rest: Vec<_> = self.queue.drain().filter(|&p| p.1 != pid).collect();
|
|
||||||
use core::iter::FromIterator;
|
|
||||||
self.queue = BinaryHeap::from_iter(rest.into_iter());
|
|
||||||
}
|
|
||||||
trace!("stride remove {}", pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn select(&mut self) -> Option<Pid> {
|
|
||||||
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;
|
|
||||||
trace!("stride {} {:#x} -> {:#x}", pid, old_stride, stride);
|
|
||||||
}
|
|
||||||
trace!("stride select {:?}", ret);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tick(&mut self, current: Pid) -> bool {
|
|
||||||
expand(&mut self.infos, current);
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_priority(&mut self, pid: Pid, priority: u8) {
|
|
||||||
self.infos[pid].priority = priority;
|
|
||||||
trace!("stride {} priority = {}", pid, priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn move_to_head(&mut self, pid: Pid) {
|
|
||||||
if self.queue.peek().is_some() {
|
|
||||||
let stride = -self.queue.peek().unwrap().0;
|
|
||||||
self.remove(pid);
|
|
||||||
self.infos[pid].stride = stride;
|
|
||||||
self.insert(pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StrideScheduler {
|
|
||||||
pub fn new(max_time_slice: usize) -> Self {
|
|
||||||
StrideScheduler {
|
|
||||||
max_time_slice,
|
|
||||||
infos: Vec::default(),
|
|
||||||
queue: BinaryHeap::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expand<T: Default + Clone>(vec: &mut Vec<T>, id: usize) {
|
|
||||||
let len = vec.len();
|
|
||||||
vec.resize(len.max(id + 1), T::default());
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
|||||||
|
use alloc::{collections::BinaryHeap, vec::Vec};
|
||||||
|
|
||||||
|
use log::*;
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
pub use self::rr::RRScheduler;
|
||||||
|
pub use self::stride::StrideScheduler;
|
||||||
|
|
||||||
|
mod rr;
|
||||||
|
mod stride;
|
||||||
|
|
||||||
|
type Pid = usize;
|
||||||
|
|
||||||
|
/// The scheduler for a ThreadPool
|
||||||
|
pub trait Scheduler: Sync + 'static {
|
||||||
|
/// Push a thread to the back of ready queue.
|
||||||
|
fn push(&self, pid: Pid);
|
||||||
|
/// Remove a thread from the ready queue.
|
||||||
|
fn remove(&self, pid: Pid);
|
||||||
|
/// Select a thread to run, pop it from the queue.
|
||||||
|
fn pop(&self) -> Option<Pid>;
|
||||||
|
/// Got a tick from CPU.
|
||||||
|
/// Return true if need reschedule.
|
||||||
|
fn tick(&self, current_pid: Pid) -> bool;
|
||||||
|
/// Set priority of a thread.
|
||||||
|
fn set_priority(&self, pid: Pid, priority: u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expand<T: Default + Clone>(vec: &mut Vec<T>, id: usize) {
|
||||||
|
let len = vec.len();
|
||||||
|
vec.resize(len.max(id + 1), T::default());
|
||||||
|
}
|
@ -0,0 +1,118 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct RRScheduler {
|
||||||
|
inner: Mutex<RRSchedulerInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RRSchedulerInner {
|
||||||
|
max_time_slice: usize,
|
||||||
|
infos: Vec<RRProcInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Copy, Clone)]
|
||||||
|
struct RRProcInfo {
|
||||||
|
present: bool,
|
||||||
|
rest_slice: usize,
|
||||||
|
prev: Pid,
|
||||||
|
next: Pid,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scheduler for RRScheduler {
|
||||||
|
fn push(&self, pid: usize) {
|
||||||
|
self.inner.lock().push(pid);
|
||||||
|
}
|
||||||
|
fn remove(&self, pid: usize) {
|
||||||
|
self.inner.lock().remove(pid);
|
||||||
|
}
|
||||||
|
fn pop(&self) -> Option<usize> {
|
||||||
|
self.inner.lock().pop()
|
||||||
|
}
|
||||||
|
fn tick(&self, current_pid: usize) -> bool {
|
||||||
|
self.inner.lock().tick(current_pid)
|
||||||
|
}
|
||||||
|
fn set_priority(&self, _pid: usize, _priority: u8) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RRScheduler {
|
||||||
|
pub fn new(max_time_slice: usize) -> Self {
|
||||||
|
let inner = RRSchedulerInner {
|
||||||
|
max_time_slice,
|
||||||
|
infos: Vec::default(),
|
||||||
|
};
|
||||||
|
RRScheduler { inner: Mutex::new(inner) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RRSchedulerInner {
|
||||||
|
fn push(&mut self, pid: Pid) {
|
||||||
|
let pid = pid + 1;
|
||||||
|
expand(&mut self.infos, 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._list_add_before(pid, 0);
|
||||||
|
trace!("rr push {}", 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);
|
||||||
|
trace!("rr remove {}", pid - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop(&mut self) -> Option<Pid> {
|
||||||
|
let ret = match self.infos[0].next {
|
||||||
|
0 => None,
|
||||||
|
pid => {
|
||||||
|
self.infos[pid].present = false;
|
||||||
|
self._list_remove(pid);
|
||||||
|
Some(pid - 1)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
trace!("rr pop {:?}", ret);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick(&mut self, current: Pid) -> bool {
|
||||||
|
let current = current + 1;
|
||||||
|
expand(&mut self.infos, current);
|
||||||
|
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 RRSchedulerInner {
|
||||||
|
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_add_after(&mut self, i: Pid, at: Pid) {
|
||||||
|
let next = self.infos[at].next;
|
||||||
|
self._list_add_before(i, next);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct StrideScheduler {
|
||||||
|
inner: Mutex<StrideSchedulerInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StrideSchedulerInner {
|
||||||
|
max_time_slice: usize,
|
||||||
|
infos: Vec<StrideProcInfo>,
|
||||||
|
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 push(&self, pid: usize) {
|
||||||
|
self.inner.lock().push(pid);
|
||||||
|
}
|
||||||
|
fn remove(&self, pid: usize) {
|
||||||
|
self.inner.lock().remove(pid);
|
||||||
|
}
|
||||||
|
fn pop(&self) -> Option<usize> {
|
||||||
|
self.inner.lock().pop()
|
||||||
|
}
|
||||||
|
fn tick(&self, current_pid: usize) -> bool {
|
||||||
|
self.inner.lock().tick(current_pid)
|
||||||
|
}
|
||||||
|
fn set_priority(&self, pid: usize, priority: u8) {
|
||||||
|
self.inner.lock().set_priority(pid, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StrideScheduler {
|
||||||
|
pub fn new(max_time_slice: usize) -> Self {
|
||||||
|
let inner = StrideSchedulerInner {
|
||||||
|
max_time_slice,
|
||||||
|
infos: Vec::default(),
|
||||||
|
queue: BinaryHeap::default(),
|
||||||
|
};
|
||||||
|
StrideScheduler { inner: Mutex::new(inner) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StrideSchedulerInner {
|
||||||
|
fn push(&mut self, pid: Pid) {
|
||||||
|
expand(&mut self.infos, 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));
|
||||||
|
trace!("stride push {}", pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&mut self, pid: Pid) {
|
||||||
|
let info = &mut self.infos[pid];
|
||||||
|
assert!(info.present);
|
||||||
|
info.present = false;
|
||||||
|
if self.queue.peek().is_some() && self.queue.peek().unwrap().1 == pid {
|
||||||
|
self.queue.pop();
|
||||||
|
} else {
|
||||||
|
// BinaryHeap only support pop the top.
|
||||||
|
// So in order to remove an arbitrary element,
|
||||||
|
// we have to take all elements into a Vec,
|
||||||
|
// then push the rest back.
|
||||||
|
let rest: Vec<_> = self.queue.drain().filter(|&p| p.1 != pid).collect();
|
||||||
|
use core::iter::FromIterator;
|
||||||
|
self.queue = BinaryHeap::from_iter(rest.into_iter());
|
||||||
|
}
|
||||||
|
trace!("stride remove {}", pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop(&mut self) -> Option<Pid> {
|
||||||
|
let ret = self.queue.pop().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;
|
||||||
|
trace!("stride {} {:#x} -> {:#x}", pid, old_stride, stride);
|
||||||
|
}
|
||||||
|
trace!("stride pop {:?}", ret);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick(&mut self, current: Pid) -> bool {
|
||||||
|
expand(&mut self.infos, current);
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_priority(&mut self, pid: Pid, priority: u8) {
|
||||||
|
self.infos[pid].priority = priority;
|
||||||
|
trace!("stride {} priority = {}", pid, priority);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue