|
|
|
@ -29,10 +29,11 @@ impl Processor {
|
|
|
|
|
return next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn add(&mut self, mut process: Process) {
|
|
|
|
|
pub fn add(&mut self, mut process: Process) -> Pid {
|
|
|
|
|
let pid = self.alloc_pid();
|
|
|
|
|
process.pid = pid;
|
|
|
|
|
self.procs.insert(pid, process);
|
|
|
|
|
pid
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn schedule(&mut self, rsp: &mut usize) {
|
|
|
|
@ -43,10 +44,13 @@ impl Processor {
|
|
|
|
|
fn find_next(&self) -> Pid {
|
|
|
|
|
*self.procs.keys()
|
|
|
|
|
.find(|&&i| i > self.current_pid
|
|
|
|
|
&& self.get(i).status != Status::Exited)
|
|
|
|
|
.unwrap_or(self.procs.keys().nth(0).unwrap())
|
|
|
|
|
&& self.get(i).exit_code().is_none())
|
|
|
|
|
.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 will be set to `Ready` if it is `Running` now.
|
|
|
|
|
fn switch_to(&mut self, pid: Pid, rsp: &mut usize) {
|
|
|
|
|
// for debug print
|
|
|
|
|
let pid0 = self.current_pid;
|
|
|
|
@ -55,44 +59,102 @@ impl Processor {
|
|
|
|
|
if pid == self.current_pid {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
let current = self.procs.get_mut(&self.current_pid).unwrap();
|
|
|
|
|
current.status = Status::Ready;
|
|
|
|
|
current.rsp = *rsp;
|
|
|
|
|
self.current_pid = pid;
|
|
|
|
|
|
|
|
|
|
let (from, to) = self.get_mut2(pid0, pid);
|
|
|
|
|
|
|
|
|
|
// set `from`
|
|
|
|
|
if from.status == Status::Running {
|
|
|
|
|
from.status = Status::Ready;
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
let process = self.procs.get_mut(&pid).unwrap();
|
|
|
|
|
process.status = Status::Running;
|
|
|
|
|
*rsp = process.rsp;
|
|
|
|
|
from.rsp = *rsp;
|
|
|
|
|
|
|
|
|
|
// set `to`
|
|
|
|
|
assert_eq!(to.status, Status::Ready);
|
|
|
|
|
to.status = Status::Running;
|
|
|
|
|
*rsp = to.rsp;
|
|
|
|
|
|
|
|
|
|
// switch page table
|
|
|
|
|
if let Some(page_table) = process.page_table.take() {
|
|
|
|
|
if let Some(page_table) = to.page_table.take() {
|
|
|
|
|
let mut active_table = unsafe { ActivePageTable::new() };
|
|
|
|
|
let old_table = active_table.switch(page_table);
|
|
|
|
|
process.page_table = Some(old_table);
|
|
|
|
|
}
|
|
|
|
|
from.page_table = Some(old_table);
|
|
|
|
|
}
|
|
|
|
|
self.current_pid = pid;
|
|
|
|
|
|
|
|
|
|
debug!("Processor: switch from {} to {}\n rsp: {:#x} -> {:#x}", pid0, pid, rsp0, rsp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get(&self, pid: Pid) -> &Process {
|
|
|
|
|
self.procs.get(&pid).unwrap()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_mut(&mut self, pid: Pid) -> &mut Process {
|
|
|
|
|
self.procs.get_mut(&pid).unwrap()
|
|
|
|
|
}
|
|
|
|
|
fn get_mut2(&mut self, pid1: Pid, pid2: Pid) -> (&mut Process, &mut Process) {
|
|
|
|
|
assert_ne!(pid1, pid2);
|
|
|
|
|
let procs1 = &mut self.procs as *mut BTreeMap<_, _>;
|
|
|
|
|
let procs2 = procs1;
|
|
|
|
|
let p1 = unsafe { &mut *procs1 }.get_mut(&pid1).unwrap();
|
|
|
|
|
let p2 = unsafe { &mut *procs2 }.get_mut(&pid2).unwrap();
|
|
|
|
|
(p1, p2)
|
|
|
|
|
}
|
|
|
|
|
pub fn current(&self) -> &Process {
|
|
|
|
|
self.get(self.current_pid)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn kill(&mut self, pid: Pid) {
|
|
|
|
|
let process = self.procs.get_mut(&pid).unwrap();
|
|
|
|
|
process.status = Status::Exited;
|
|
|
|
|
// TODO: Remove process from set
|
|
|
|
|
self.exit(pid, 0x1000); // TODO: error code for killed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn exit(&mut self, pid: Pid, error_code: usize) {
|
|
|
|
|
pub fn exit(&mut self, pid: Pid, error_code: ErrorCode) {
|
|
|
|
|
assert_ne!(pid, self.current_pid);
|
|
|
|
|
debug!("Processor: {} exit, code: {}", pid, error_code);
|
|
|
|
|
self.kill(pid);
|
|
|
|
|
self.get_mut(pid).status = Status::Exited(error_code);
|
|
|
|
|
if let Some(waiter) = self.find_waiter(pid) {
|
|
|
|
|
{
|
|
|
|
|
let p = self.get_mut(waiter);
|
|
|
|
|
p.status = Status::Ready;
|
|
|
|
|
p.set_return_value(error_code);
|
|
|
|
|
}
|
|
|
|
|
debug!("Processor: remove {}", pid);
|
|
|
|
|
self.procs.remove(&pid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Let current process wait for another
|
|
|
|
|
pub fn current_wait_for(&mut self, target: WaitTarget) -> WaitResult {
|
|
|
|
|
// Find one target process and it's exit code
|
|
|
|
|
let (pid, exit_code) = match target {
|
|
|
|
|
WaitTarget::AnyChild => {
|
|
|
|
|
let childs = self.procs.values()
|
|
|
|
|
.filter(|&p| p.parent == self.current_pid);
|
|
|
|
|
if childs.clone().next().is_none() {
|
|
|
|
|
return WaitResult::NotExist;
|
|
|
|
|
}
|
|
|
|
|
childs.clone()
|
|
|
|
|
.find(|&p| p.exit_code().is_some())
|
|
|
|
|
.map(|p| (p.pid, p.exit_code()))
|
|
|
|
|
.unwrap_or((0, None))
|
|
|
|
|
}
|
|
|
|
|
WaitTarget::Proc(pid) => (pid, self.get(pid).exit_code()),
|
|
|
|
|
};
|
|
|
|
|
if let Some(exit_code) = exit_code {
|
|
|
|
|
debug!("Processor: remove {}", pid);
|
|
|
|
|
self.procs.remove(&pid);
|
|
|
|
|
WaitResult::Ok(exit_code)
|
|
|
|
|
} else {
|
|
|
|
|
debug!("Processor: {} wait for {}", self.current_pid, pid);
|
|
|
|
|
let current_pid = self.current_pid;
|
|
|
|
|
self.get_mut(current_pid).status = Status::Sleeping(pid);
|
|
|
|
|
WaitResult::Blocked
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn find_waiter(&self, pid: Pid) -> Option<Pid> {
|
|
|
|
|
self.procs.values().find(|&p| {
|
|
|
|
|
p.status == Status::Sleeping(pid) ||
|
|
|
|
|
(p.status == Status::Sleeping(0) && self.get(pid).parent == p.pid)
|
|
|
|
|
}).map(|ref p| p.pid)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -103,3 +165,18 @@ impl Debug for Processor {
|
|
|
|
|
.finish()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub enum WaitTarget {
|
|
|
|
|
AnyChild,
|
|
|
|
|
Proc(Pid),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub enum WaitResult {
|
|
|
|
|
/// The target process is still running.
|
|
|
|
|
/// The waiter's status will be set to `Sleeping`.
|
|
|
|
|
Blocked,
|
|
|
|
|
/// The target process is exited with `ErrorCode`.
|
|
|
|
|
Ok(ErrorCode),
|
|
|
|
|
/// The target process is not exist.
|
|
|
|
|
NotExist,
|
|
|
|
|
}
|