mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-23 00:16:17 +04:00
Impl RRScheduler
This commit is contained in:
parent
dc74d37697
commit
9418d5de70
@ -1,5 +1,6 @@
|
||||
#![allow(dead_code)]
|
||||
pub const MAX_CPU_NUM: usize = 8;
|
||||
pub const MAX_PROCESS_NUM: usize = 32;
|
||||
|
||||
// Copy from Redox consts.rs:
|
||||
|
||||
|
@ -8,6 +8,7 @@ pub use self::processor::*;
|
||||
|
||||
mod process;
|
||||
mod processor;
|
||||
mod scheduler;
|
||||
|
||||
|
||||
pub fn init(mut mc: MemoryController) {
|
||||
|
@ -21,7 +21,7 @@ pub struct Process {
|
||||
pub type Pid = usize;
|
||||
pub type ErrorCode = usize;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum Status {
|
||||
Ready,
|
||||
Running,
|
||||
|
@ -1,6 +1,7 @@
|
||||
use alloc::BTreeMap;
|
||||
use memory::{ActivePageTable, InactivePageTable};
|
||||
use super::process::*;
|
||||
use super::scheduler::*;
|
||||
use core::cell::RefCell;
|
||||
use core::fmt::{Debug, Formatter, Error};
|
||||
use util::{EventHub, GetMut2};
|
||||
@ -15,6 +16,8 @@ pub struct Processor {
|
||||
kernel_page_table: Option<InactivePageTable>,
|
||||
/// Choose what on next schedule ?
|
||||
next: Option<Pid>,
|
||||
// WARNING: if MAX_PROCESS_NUM is too large, will cause stack overflow
|
||||
scheduler: RRScheduler,
|
||||
}
|
||||
|
||||
impl Processor {
|
||||
@ -22,19 +25,16 @@ impl Processor {
|
||||
Processor {
|
||||
procs: BTreeMap::<Pid, Process>::new(),
|
||||
current_pid: 0,
|
||||
event_hub: {
|
||||
let mut e = EventHub::new();
|
||||
e.push(10, Event::Schedule);
|
||||
e
|
||||
},
|
||||
event_hub: EventHub::new(),
|
||||
kernel_page_table: None,
|
||||
next: None,
|
||||
scheduler: RRScheduler::new(100),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_reschedule(&mut self) {
|
||||
let pid = self.current_pid;
|
||||
self.get_mut(pid).status = Status::Ready;
|
||||
self.set_status(pid, Status::Ready);
|
||||
}
|
||||
|
||||
fn alloc_pid(&self) -> Pid {
|
||||
@ -49,9 +49,25 @@ impl Processor {
|
||||
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.
|
||||
/// Handle events.
|
||||
pub fn tick(&mut self) {
|
||||
let current_pid = self.current_pid;
|
||||
if self.scheduler.tick(current_pid) {
|
||||
self.set_reschedule();
|
||||
}
|
||||
self.event_hub.tick();
|
||||
while let Some(event) = self.event_hub.pop() {
|
||||
debug!("Processor: event {:?}", event);
|
||||
@ -61,7 +77,7 @@ impl Processor {
|
||||
self.set_reschedule();
|
||||
},
|
||||
Event::Wakeup(pid) => {
|
||||
self.get_mut(pid).status = Status::Ready;
|
||||
self.set_status(pid, Status::Ready);
|
||||
self.set_reschedule();
|
||||
self.next = Some(pid);
|
||||
},
|
||||
@ -76,6 +92,9 @@ impl Processor {
|
||||
pub fn add(&mut self, mut process: Process) -> Pid {
|
||||
let pid = self.alloc_pid();
|
||||
process.pid = pid;
|
||||
if process.status == Status::Ready {
|
||||
self.scheduler.insert(pid);
|
||||
}
|
||||
self.procs.insert(pid, process);
|
||||
pid
|
||||
}
|
||||
@ -86,17 +105,10 @@ impl Processor {
|
||||
if self.current().status == Status::Running {
|
||||
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);
|
||||
}
|
||||
|
||||
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.
|
||||
/// Store `rsp` and point it to target kernel stack.
|
||||
/// The current status must be set before, and not be `Running`.
|
||||
@ -105,6 +117,9 @@ impl Processor {
|
||||
let pid0 = self.current_pid;
|
||||
|
||||
if pid == self.current_pid {
|
||||
if self.current().status != Status::Running {
|
||||
self.set_status(pid, Status::Running);
|
||||
}
|
||||
return;
|
||||
}
|
||||
self.current_pid = pid;
|
||||
@ -114,6 +129,7 @@ impl Processor {
|
||||
assert_ne!(from.status, Status::Running);
|
||||
assert_eq!(to.status, Status::Ready);
|
||||
to.status = Status::Running;
|
||||
self.scheduler.remove(pid);
|
||||
|
||||
// switch page table
|
||||
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);
|
||||
unsafe {
|
||||
use core::mem::forget;
|
||||
super::PROCESSOR.try().unwrap().force_unlock();
|
||||
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) {
|
||||
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) {
|
||||
info!(" then wakeup {}", waiter);
|
||||
self.get_mut(waiter).status = Status::Ready;
|
||||
self.set_status(waiter, Status::Ready);
|
||||
self.switch_to(waiter); // yield
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@ -178,7 +196,7 @@ impl Processor {
|
||||
let pid = self.try_wait(pid).unwrap_or_else(|| {
|
||||
info!("Processor: {} wait for {}", self.current_pid, 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.try_wait(pid).unwrap()
|
||||
});
|
||||
|
93
src/process/scheduler.rs
Normal file
93
src/process/scheduler.rs
Normal file
@ -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…
Reference in New Issue
Block a user