Recover wait/sleep

master
WangRunji 6 years ago
parent c734f79699
commit 0680023e35

@ -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);
}
}
}

@ -41,7 +41,7 @@ pub fn current() -> Thread {
pub fn sleep(dur: Duration) {
let time = dur_to_ticks(dur);
info!("sleep: {:?} ticks", time);
// TODO: register wakeup
processor().manager().sleep(current().id(), time);
park();
fn dur_to_ticks(dur: Duration) -> usize {
@ -87,9 +87,8 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
// unsafe { LocalKey::<usize>::get_map() }.clear();
// 让Processor退出当前线程
// 把f返回值在堆上的指针以线程返回码的形式传递出去
let pid = processor().pid();
let exit_code = Box::into_raw(ret) as usize;
processor().manager().set_status(pid, Status::Exited(exit_code));
processor().manager().exit(current().id(), exit_code);
processor().yield_now();
// 再也不会被调度回来了
unreachable!()
@ -116,8 +115,7 @@ pub fn yield_now() {
/// Blocks unless or until the current thread's token is made available.
pub fn park() {
info!("park:");
let pid = processor().pid();
processor().manager().set_status(pid, Status::Sleeping);
processor().manager().sleep(current().id(), 0);
processor().yield_now();
}
@ -129,7 +127,7 @@ pub struct Thread {
impl Thread {
/// Atomically makes the handle's token available if it is not already.
pub fn unpark(&self) {
processor().manager().set_status(self.pid, Status::Ready);
processor().manager().wakeup(self.pid);
}
/// Gets the thread's unique identifier.
pub fn id(&self) -> usize {
@ -150,8 +148,19 @@ impl<T> JoinHandle<T> {
}
/// Waits for the associated thread to finish.
pub fn join(self) -> Result<T, ()> {
// TODO: wait for the thread
unimplemented!()
loop {
match processor().manager().get_status(self.thread.pid) {
Some(Status::Exited(exit_code)) => {
processor().manager().remove(self.thread.pid);
// Find return value on the heap from the exit code.
return Ok(unsafe { *Box::from_raw(exit_code as *mut T) });
}
None => return Err(()),
_ => {}
}
processor().manager().wait(current().id(), self.thread.pid);
processor().yield_now();
}
}
}

@ -46,8 +46,9 @@ pub fn shell() {
if let Ok(file) = root.borrow().lookup(name.as_str()) {
use process::*;
let len = file.borrow().read_at(0, &mut *buf).unwrap();
processor().manager().add(ContextImpl::new_user(&buf[..len]));
// TODO: wait for new process
let pid = processor().manager().add(ContextImpl::new_user(&buf[..len]));
processor().manager().wait(thread::current().id(), pid);
processor().yield_now();
} else {
println!("Program not exist");
}

@ -68,7 +68,22 @@ fn sys_fork(tf: &TrapFrame) -> i32 {
/// Wait the process exit.
/// Return the PID. Store exit code to `code` if it's not null.
fn sys_wait(pid: usize, code: *mut i32) -> i32 {
unimplemented!();
assert_ne!(pid, 0, "wait for 0 is not supported yet");
loop {
match processor().manager().get_status(pid) {
Some(Status::Exited(exit_code)) => {
if !code.is_null() {
unsafe { code.write(exit_code as i32); }
}
processor().manager().remove(pid);
return 0;
}
None => return -1,
_ => {}
}
processor().manager().wait(thread::current().id(), pid);
processor().yield_now();
}
}
fn sys_yield() -> i32 {
@ -78,7 +93,7 @@ fn sys_yield() -> i32 {
/// Kill the process
fn sys_kill(pid: usize) -> i32 {
processor().manager().set_status(pid, Status::Exited(0x100));
processor().manager().exit(pid, 0x100);
0
}
@ -90,9 +105,9 @@ fn sys_getpid() -> i32 {
/// Exit the current process
fn sys_exit(exit_code: usize) -> i32 {
let pid = thread::current().id();
processor().manager().set_status(pid, Status::Exited(exit_code));
processor().manager().exit(pid, exit_code);
processor().yield_now();
0
unreachable!();
}
fn sys_sleep(time: usize) -> i32 {
@ -102,7 +117,7 @@ fn sys_sleep(time: usize) -> i32 {
}
fn sys_get_time() -> i32 {
unimplemented!();
unsafe { ::trap::TICK as i32 }
}
fn sys_lab6_set_priority(priority: usize) -> i32 {

@ -2,8 +2,13 @@ use process::*;
use arch::interrupt::TrapFrame;
use arch::cpu;
pub static mut TICK: usize = 0;
pub fn timer() {
processor().tick();
if cpu::id() == 0 {
unsafe { TICK += 1; }
}
}
pub fn before_return() {
@ -13,7 +18,7 @@ pub fn error(tf: &TrapFrame) -> ! {
let pid = processor().pid();
error!("On CPU{} Process {}:\n{:#x?}", cpu::id(), pid, tf);
processor().manager().set_status(pid, Status::Exited(0x100));
processor().manager().exit(pid, 0x100);
processor().yield_now();
unreachable!();
}
Loading…
Cancel
Save