parent
f7eb09e856
commit
5db908b1c5
@ -0,0 +1,120 @@
|
|||||||
|
use alloc::boxed::Box;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
use spin::Mutex;
|
||||||
|
use scheduler::Scheduler;
|
||||||
|
use core::cell::UnsafeCell;
|
||||||
|
|
||||||
|
struct Process {
|
||||||
|
id: Pid,
|
||||||
|
status: Status,
|
||||||
|
status_after_stop: Status,
|
||||||
|
context: Option<Box<Context>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Pid = usize;
|
||||||
|
type ExitCode = usize;
|
||||||
|
const MAX_PROC_NUM: usize = 32;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub enum Status {
|
||||||
|
Ready,
|
||||||
|
Running(usize),
|
||||||
|
Waiting(Pid),
|
||||||
|
Sleeping,
|
||||||
|
Exited(ExitCode),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Context {
|
||||||
|
unsafe fn switch_to(&mut self, target: &mut Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProcessManager {
|
||||||
|
procs: [Mutex<Option<Process>>; MAX_PROC_NUM],
|
||||||
|
scheduler: Mutex<Box<Scheduler>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProcessManager {
|
||||||
|
pub fn new(scheduler: Box<Scheduler>) -> Self {
|
||||||
|
ProcessManager {
|
||||||
|
procs: Default::default(),
|
||||||
|
scheduler: Mutex::new(scheduler),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alloc_pid(&self) -> Pid {
|
||||||
|
for i in 0..MAX_PROC_NUM {
|
||||||
|
if self.procs[i].lock().is_none() {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("Process number exceeded");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a new process
|
||||||
|
pub fn add(&self, context: Box<Context>) -> Pid {
|
||||||
|
let pid = self.alloc_pid();
|
||||||
|
// TODO: check parent
|
||||||
|
*self.procs[pid].lock() = Some(Process {
|
||||||
|
id: pid,
|
||||||
|
status: Status::Ready,
|
||||||
|
status_after_stop: Status::Ready,
|
||||||
|
context: Some(context),
|
||||||
|
});
|
||||||
|
self.scheduler.lock().insert(pid);
|
||||||
|
pid
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make process `pid` time slice -= 1.
|
||||||
|
/// Return true if time slice == 0.
|
||||||
|
/// Called by timer interrupt handler.
|
||||||
|
pub fn tick(&self, pid: Pid) -> bool {
|
||||||
|
self.scheduler.lock().tick(pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called by Processor to get a process to run.
|
||||||
|
/// The manager first mark it `Running`,
|
||||||
|
/// then take out and return its Context.
|
||||||
|
pub fn run(&self, cpu_id: usize) -> (Pid, Box<Context>) {
|
||||||
|
let mut scheduler = self.scheduler.lock();
|
||||||
|
let pid = scheduler.select()
|
||||||
|
.expect("failed to select a runnable process");
|
||||||
|
scheduler.remove(pid);
|
||||||
|
let mut proc_lock = self.procs[pid].lock();
|
||||||
|
let mut proc = proc_lock.as_mut().unwrap();
|
||||||
|
proc.status = Status::Running(cpu_id);
|
||||||
|
(pid, proc.context.take().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called by Processor to finish running a process
|
||||||
|
/// and give its context back.
|
||||||
|
pub fn stop(&self, pid: Pid, context: Box<Context>) {
|
||||||
|
let mut proc_lock = self.procs[pid].lock();
|
||||||
|
let mut proc = proc_lock.as_mut().unwrap();
|
||||||
|
proc.status = proc.status_after_stop.clone();
|
||||||
|
proc.status_after_stop = Status::Ready;
|
||||||
|
proc.context = Some(context);
|
||||||
|
if proc.status == Status::Ready {
|
||||||
|
self.scheduler.lock().insert(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Switch the status of a process.
|
||||||
|
/// Insert/Remove it to/from scheduler if necessary.
|
||||||
|
pub fn set_status(&self, pid: Pid, status: Status) {
|
||||||
|
let mut scheduler = self.scheduler.lock();
|
||||||
|
let mut proc_lock = self.procs[pid].lock();
|
||||||
|
let mut proc = proc_lock.as_mut().unwrap();
|
||||||
|
match (&proc.status, &status) {
|
||||||
|
(Status::Ready, Status::Ready) => return,
|
||||||
|
(Status::Ready, _) => scheduler.remove(pid),
|
||||||
|
(Status::Running(_), _) => {},
|
||||||
|
(_, Status::Ready) => scheduler.insert(pid),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
trace!("process {} {:?} -> {:?}", pid, proc.status, status);
|
||||||
|
match proc.status {
|
||||||
|
Status::Running(_) => proc.status_after_stop = status,
|
||||||
|
_ => proc.status = status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue