|
|
|
@ -3,6 +3,8 @@ use alloc::sync::Arc;
|
|
|
|
|
use spin::Mutex;
|
|
|
|
|
use scheduler::Scheduler;
|
|
|
|
|
use core::cell::UnsafeCell;
|
|
|
|
|
use alloc::vec::Vec;
|
|
|
|
|
use event_hub::EventHub;
|
|
|
|
|
|
|
|
|
|
struct Process {
|
|
|
|
|
id: Pid,
|
|
|
|
@ -20,10 +22,15 @@ pub enum Status {
|
|
|
|
|
Ready,
|
|
|
|
|
Running(usize),
|
|
|
|
|
Sleeping,
|
|
|
|
|
Waiting(Pid),
|
|
|
|
|
/// aka ZOMBIE. Its context was dropped.
|
|
|
|
|
Exited(ExitCode),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum Event {
|
|
|
|
|
Wakeup(Pid),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub trait Context {
|
|
|
|
|
unsafe fn switch_to(&mut self, target: &mut Context);
|
|
|
|
|
}
|
|
|
|
@ -31,6 +38,8 @@ pub trait Context {
|
|
|
|
|
pub struct ProcessManager {
|
|
|
|
|
procs: [Mutex<Option<Process>>; MAX_PROC_NUM],
|
|
|
|
|
scheduler: Mutex<Box<Scheduler>>,
|
|
|
|
|
wait_queue: [Mutex<Vec<Pid>>; MAX_PROC_NUM],
|
|
|
|
|
event_hub: Mutex<EventHub<Event>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ProcessManager {
|
|
|
|
@ -38,6 +47,8 @@ impl ProcessManager {
|
|
|
|
|
ProcessManager {
|
|
|
|
|
procs: Default::default(),
|
|
|
|
|
scheduler: Mutex::new(scheduler),
|
|
|
|
|
wait_queue: Default::default(),
|
|
|
|
|
event_hub: Mutex::new(EventHub::new()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -53,7 +64,6 @@ impl ProcessManager {
|
|
|
|
|
/// 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,
|
|
|
|
@ -68,6 +78,13 @@ impl ProcessManager {
|
|
|
|
|
/// Return true if time slice == 0.
|
|
|
|
|
/// Called by timer interrupt handler.
|
|
|
|
|
pub fn tick(&self, pid: Pid) -> bool {
|
|
|
|
|
let mut event_hub = self.event_hub.lock();
|
|
|
|
|
event_hub.tick();
|
|
|
|
|
while let Some(event) = event_hub.pop() {
|
|
|
|
|
match event {
|
|
|
|
|
Event::Wakeup(pid) => self.set_status(pid, Status::Ready),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
self.scheduler.lock().tick(pid)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -107,18 +124,22 @@ impl ProcessManager {
|
|
|
|
|
|
|
|
|
|
/// Switch the status of a process.
|
|
|
|
|
/// Insert/Remove it to/from scheduler if necessary.
|
|
|
|
|
pub fn set_status(&self, pid: Pid, status: Status) {
|
|
|
|
|
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();
|
|
|
|
|
trace!("process {} {:?} -> {:?}", pid, proc.status, status);
|
|
|
|
|
match (&proc.status, &status) {
|
|
|
|
|
(Status::Ready, Status::Ready) => return,
|
|
|
|
|
(Status::Ready, _) => scheduler.remove(pid),
|
|
|
|
|
(Status::Running(_), _) => {},
|
|
|
|
|
(Status::Exited(_), _) => panic!("can not set status for a exited process"),
|
|
|
|
|
(Status::Waiting(target), Status::Exited(_)) =>
|
|
|
|
|
self.wait_queue[*target].lock().retain(|&i| i != pid),
|
|
|
|
|
// TODO: Sleep -> Exited Remove wakeup event.
|
|
|
|
|
(_, Status::Ready) => scheduler.insert(pid),
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
trace!("process {} {:?} -> {:?}", pid, proc.status, status);
|
|
|
|
|
match proc.status {
|
|
|
|
|
Status::Running(_) => proc.status_after_stop = status,
|
|
|
|
|
_ => proc.status = status,
|
|
|
|
@ -128,4 +149,41 @@ impl ProcessManager {
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn get_status(&self, pid: Pid) -> Option<Status> {
|
|
|
|
|
self.procs[pid].lock().as_ref().map(|p| p.status.clone())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn remove(&self, pid: Pid) {
|
|
|
|
|
let mut proc_lock = self.procs[pid].lock();
|
|
|
|
|
let proc = proc_lock.as_ref().unwrap();
|
|
|
|
|
match proc.status {
|
|
|
|
|
Status::Exited(_) => *proc_lock = None,
|
|
|
|
|
_ => panic!("can not remove non-exited process"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sleep(&self, pid: Pid, time: usize) {
|
|
|
|
|
self.set_status(pid, Status::Sleeping);
|
|
|
|
|
if time != 0 {
|
|
|
|
|
self.event_hub.lock().push(time, Event::Wakeup(pid));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn wakeup(&self, pid: Pid) {
|
|
|
|
|
self.set_status(pid, Status::Ready);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn wait(&self, pid: Pid, target: Pid) {
|
|
|
|
|
self.set_status(pid, Status::Waiting(target));
|
|
|
|
|
self.wait_queue[target].lock().push(pid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn exit(&self, pid: Pid, code: ExitCode) {
|
|
|
|
|
self.set_status(pid, Status::Exited(code));
|
|
|
|
|
for waiter in self.wait_queue[pid].lock().drain(..) {
|
|
|
|
|
self.wakeup(waiter);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|