split scheduler mod, make Scheduler Sync

biscuit: fix argc, argv
master
WangRunji 6 years ago
parent e678186b3d
commit a224e85c8d

@ -2,7 +2,6 @@
#![feature(alloc)]
#![feature(const_fn)]
#![feature(linkage)]
#![feature(nll)]
#![feature(vec_resize_default)]
#![feature(asm)]
#![feature(exact_size_is_empty)]

@ -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);
}
}

@ -37,15 +37,15 @@ pub trait Context {
pub struct ThreadPool {
threads: Vec<Mutex<Option<Thread>>>,
scheduler: Mutex<Box<Scheduler>>,
scheduler: Box<Scheduler>,
timer: Mutex<Timer<Event>>,
}
impl ThreadPool {
pub fn new(scheduler: Box<Scheduler>, max_proc_num: usize) -> Self {
pub fn new(scheduler: impl Scheduler, max_proc_num: usize) -> Self {
ThreadPool {
threads: new_vec_default(max_proc_num),
scheduler: Mutex::new(scheduler),
scheduler: Box::new(scheduler),
timer: Mutex::new(Timer::new()),
}
}
@ -69,7 +69,7 @@ impl ThreadPool {
parent,
children: Vec::new(),
});
self.scheduler.lock().insert(tid);
self.scheduler.push(tid);
self.threads[parent].lock().as_mut().expect("invalid parent proc")
.children.push(tid);
tid
@ -89,24 +89,22 @@ impl ThreadPool {
}
}
match tid {
Some(tid) => self.scheduler.lock().tick(tid),
Some(tid) => self.scheduler.tick(tid),
None => false,
}
}
/// Set the priority of process `tid`
pub fn set_priority(&self, tid: Tid, priority: u8) {
self.scheduler.lock().set_priority(tid, priority);
self.scheduler.set_priority(tid, priority);
}
/// Called by Processor to get a process to run.
/// The manager first mark it `Running`,
/// then take out and return its Context.
pub(crate) fn run(&self, cpu_id: usize) -> Option<(Tid, Box<Context>)> {
let mut scheduler = self.scheduler.lock();
scheduler.select()
self.scheduler.pop()
.map(|tid| {
scheduler.remove(tid);
let mut proc_lock = self.threads[tid].lock();
let mut proc = proc_lock.as_mut().expect("process not exist");
proc.status = Status::Running(cpu_id);
@ -123,7 +121,7 @@ impl ThreadPool {
proc.status_after_stop = Status::Ready;
proc.context = Some(context);
match proc.status {
Status::Ready => self.scheduler.lock().insert(tid),
Status::Ready => self.scheduler.push(tid),
Status::Exited(_) => self.exit_handler(tid, proc),
_ => {}
}
@ -137,10 +135,10 @@ impl ThreadPool {
trace!("process {} {:?} -> {:?}", tid, proc.status, status);
match (&proc.status, &status) {
(Status::Ready, Status::Ready) => return,
(Status::Ready, _) => self.scheduler.lock().remove(tid),
(Status::Ready, _) => self.scheduler.remove(tid),
(Status::Exited(_), _) => panic!("can not set status for a exited process"),
(Status::Sleeping, Status::Exited(_)) => self.timer.lock().stop(Event::Wakeup(tid)),
(_, Status::Ready) => self.scheduler.lock().insert(tid),
(_, Status::Ready) => self.scheduler.push(tid),
_ => {}
}
match proc.status {

@ -11,7 +11,7 @@ mod abi;
pub fn init() {
// NOTE: max_time_slice <= 5 to ensure 'priority' test pass
let scheduler = Box::new(scheduler::RRScheduler::new(5));
let scheduler = scheduler::RRScheduler::new(5);
let manager = Arc::new(ThreadPool::new(scheduler, MAX_PROCESS_NUM));
unsafe {

Loading…
Cancel
Save