Impl RRScheduler

master
WangRunji 7 years ago
parent dc74d37697
commit 9418d5de70

@ -1,5 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
pub const MAX_CPU_NUM: usize = 8; pub const MAX_CPU_NUM: usize = 8;
pub const MAX_PROCESS_NUM: usize = 32;
// Copy from Redox consts.rs: // Copy from Redox consts.rs:

@ -8,6 +8,7 @@ pub use self::processor::*;
mod process; mod process;
mod processor; mod processor;
mod scheduler;
pub fn init(mut mc: MemoryController) { pub fn init(mut mc: MemoryController) {

@ -21,7 +21,7 @@ pub struct Process {
pub type Pid = usize; pub type Pid = usize;
pub type ErrorCode = usize; pub type ErrorCode = usize;
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub enum Status { pub enum Status {
Ready, Ready,
Running, Running,

@ -1,6 +1,7 @@
use alloc::BTreeMap; use alloc::BTreeMap;
use memory::{ActivePageTable, InactivePageTable}; use memory::{ActivePageTable, InactivePageTable};
use super::process::*; use super::process::*;
use super::scheduler::*;
use core::cell::RefCell; use core::cell::RefCell;
use core::fmt::{Debug, Formatter, Error}; use core::fmt::{Debug, Formatter, Error};
use util::{EventHub, GetMut2}; use util::{EventHub, GetMut2};
@ -15,6 +16,8 @@ pub struct Processor {
kernel_page_table: Option<InactivePageTable>, kernel_page_table: Option<InactivePageTable>,
/// Choose what on next schedule ? /// Choose what on next schedule ?
next: Option<Pid>, next: Option<Pid>,
// WARNING: if MAX_PROCESS_NUM is too large, will cause stack overflow
scheduler: RRScheduler,
} }
impl Processor { impl Processor {
@ -22,19 +25,16 @@ impl Processor {
Processor { Processor {
procs: BTreeMap::<Pid, Process>::new(), procs: BTreeMap::<Pid, Process>::new(),
current_pid: 0, current_pid: 0,
event_hub: { event_hub: EventHub::new(),
let mut e = EventHub::new();
e.push(10, Event::Schedule);
e
},
kernel_page_table: None, kernel_page_table: None,
next: None, next: None,
scheduler: RRScheduler::new(100),
} }
} }
pub fn set_reschedule(&mut self) { pub fn set_reschedule(&mut self) {
let pid = self.current_pid; let pid = self.current_pid;
self.get_mut(pid).status = Status::Ready; self.set_status(pid, Status::Ready);
} }
fn alloc_pid(&self) -> Pid { fn alloc_pid(&self) -> Pid {
@ -49,9 +49,25 @@ impl Processor {
return next; return next;
} }
fn set_status(&mut self, pid: Pid, status: Status) {
let status0 = self.get(pid).status.clone();
match (&status0, &status) {
(&Status::Ready, &Status::Ready) => return,
(&Status::Ready, _) => self.scheduler.remove(pid),
(_, &Status::Ready) => self.scheduler.insert(pid),
_ => {}
}
trace!("Processor: process {} {:?} -> {:?}", pid, status0, status);
self.get_mut(pid).status = status;
}
/// Called by timer. /// Called by timer.
/// Handle events. /// Handle events.
pub fn tick(&mut self) { pub fn tick(&mut self) {
let current_pid = self.current_pid;
if self.scheduler.tick(current_pid) {
self.set_reschedule();
}
self.event_hub.tick(); self.event_hub.tick();
while let Some(event) = self.event_hub.pop() { while let Some(event) = self.event_hub.pop() {
debug!("Processor: event {:?}", event); debug!("Processor: event {:?}", event);
@ -61,7 +77,7 @@ impl Processor {
self.set_reschedule(); self.set_reschedule();
}, },
Event::Wakeup(pid) => { Event::Wakeup(pid) => {
self.get_mut(pid).status = Status::Ready; self.set_status(pid, Status::Ready);
self.set_reschedule(); self.set_reschedule();
self.next = Some(pid); self.next = Some(pid);
}, },
@ -76,6 +92,9 @@ impl Processor {
pub fn add(&mut self, mut process: Process) -> Pid { pub fn add(&mut self, mut process: Process) -> Pid {
let pid = self.alloc_pid(); let pid = self.alloc_pid();
process.pid = pid; process.pid = pid;
if process.status == Status::Ready {
self.scheduler.insert(pid);
}
self.procs.insert(pid, process); self.procs.insert(pid, process);
pid pid
} }
@ -86,17 +105,10 @@ impl Processor {
if self.current().status == Status::Running { if self.current().status == Status::Running {
return; return;
} }
let pid = self.next.take().unwrap_or_else(|| self.find_next()); let pid = self.next.take().unwrap_or_else(|| self.scheduler.select().unwrap());
self.switch_to(pid); self.switch_to(pid);
} }
fn find_next(&self) -> Pid {
*self.procs.keys()
.find(|&&i| i > self.current_pid
&& self.get(i).status == Status::Ready)
.unwrap_or(self.procs.keys().next().unwrap())
}
/// Switch process to `pid`, switch page table if necessary. /// Switch process to `pid`, switch page table if necessary.
/// Store `rsp` and point it to target kernel stack. /// Store `rsp` and point it to target kernel stack.
/// The current status must be set before, and not be `Running`. /// The current status must be set before, and not be `Running`.
@ -105,6 +117,9 @@ impl Processor {
let pid0 = self.current_pid; let pid0 = self.current_pid;
if pid == self.current_pid { if pid == self.current_pid {
if self.current().status != Status::Running {
self.set_status(pid, Status::Running);
}
return; return;
} }
self.current_pid = pid; self.current_pid = pid;
@ -114,6 +129,7 @@ impl Processor {
assert_ne!(from.status, Status::Running); assert_ne!(from.status, Status::Running);
assert_eq!(to.status, Status::Ready); assert_eq!(to.status, Status::Ready);
to.status = Status::Running; to.status = Status::Running;
self.scheduler.remove(pid);
// switch page table // switch page table
if from.is_user || to.is_user { if from.is_user || to.is_user {
@ -132,8 +148,10 @@ impl Processor {
info!("Processor: switch from {} to {}\n rsp: ??? -> {:#x}", pid0, pid, to.rsp); info!("Processor: switch from {} to {}\n rsp: ??? -> {:#x}", pid0, pid, to.rsp);
unsafe { unsafe {
use core::mem::forget;
super::PROCESSOR.try().unwrap().force_unlock(); super::PROCESSOR.try().unwrap().force_unlock();
switch(&mut from.rsp, to.rsp); switch(&mut from.rsp, to.rsp);
forget(super::PROCESSOR.try().unwrap().lock());
} }
} }
@ -156,16 +174,16 @@ impl Processor {
pub fn exit(&mut self, pid: Pid, error_code: ErrorCode) { pub fn exit(&mut self, pid: Pid, error_code: ErrorCode) {
info!("Processor: {} exit, code: {}", pid, error_code); info!("Processor: {} exit, code: {}", pid, error_code);
self.get_mut(pid).status = Status::Exited(error_code); self.set_status(pid, Status::Exited(error_code));
if let Some(waiter) = self.find_waiter(pid) { if let Some(waiter) = self.find_waiter(pid) {
info!(" then wakeup {}", waiter); info!(" then wakeup {}", waiter);
self.get_mut(waiter).status = Status::Ready; self.set_status(waiter, Status::Ready);
self.switch_to(waiter); // yield self.switch_to(waiter); // yield
} }
} }
pub fn sleep(&mut self, pid: Pid, time: usize) { pub fn sleep(&mut self, pid: Pid, time: usize) {
self.get_mut(pid).status = Status::Sleeping; self.set_status(pid, Status::Sleeping);
self.event_hub.push(time, Event::Wakeup(pid)); self.event_hub.push(time, Event::Wakeup(pid));
} }
@ -178,7 +196,7 @@ impl Processor {
let pid = self.try_wait(pid).unwrap_or_else(|| { let pid = self.try_wait(pid).unwrap_or_else(|| {
info!("Processor: {} wait for {}", self.current_pid, pid); info!("Processor: {} wait for {}", self.current_pid, pid);
let current_pid = self.current_pid; let current_pid = self.current_pid;
self.get_mut(current_pid).status = Status::Waiting(pid); self.set_status(current_pid, Status::Waiting(pid));
self.schedule(); // yield self.schedule(); // yield
self.try_wait(pid).unwrap() self.try_wait(pid).unwrap()
}); });

@ -0,0 +1,93 @@
use super::*;
use consts::MAX_PROCESS_NUM;
///
pub trait Scheduler {
fn insert(&mut self, pid: Pid);
fn remove(&mut self, pid: Pid);
fn select(&self) -> Option<Pid>;
fn tick(&mut self, current: Pid) -> bool; // need reschedule?
}
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);
trace!("RRScheduler: 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!("RRScheduler: remove {}", pid - 1);
}
fn select(&self) -> Option<Pid> {
let ret = match self.infos[0].next {
0 => None,
i => Some(i - 1),
};
trace!("RRScheduler: 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;
}
}
Loading…
Cancel
Save