Recover wait/sleep

master
WangRunji 6 years ago
parent c734f79699
commit 0680023e35

@ -3,6 +3,8 @@ use alloc::sync::Arc;
use spin::Mutex; use spin::Mutex;
use scheduler::Scheduler; use scheduler::Scheduler;
use core::cell::UnsafeCell; use core::cell::UnsafeCell;
use alloc::vec::Vec;
use event_hub::EventHub;
struct Process { struct Process {
id: Pid, id: Pid,
@ -20,10 +22,15 @@ pub enum Status {
Ready, Ready,
Running(usize), Running(usize),
Sleeping, Sleeping,
Waiting(Pid),
/// aka ZOMBIE. Its context was dropped. /// aka ZOMBIE. Its context was dropped.
Exited(ExitCode), Exited(ExitCode),
} }
enum Event {
Wakeup(Pid),
}
pub trait Context { pub trait Context {
unsafe fn switch_to(&mut self, target: &mut Context); unsafe fn switch_to(&mut self, target: &mut Context);
} }
@ -31,6 +38,8 @@ pub trait Context {
pub struct ProcessManager { pub struct ProcessManager {
procs: [Mutex<Option<Process>>; MAX_PROC_NUM], procs: [Mutex<Option<Process>>; MAX_PROC_NUM],
scheduler: Mutex<Box<Scheduler>>, scheduler: Mutex<Box<Scheduler>>,
wait_queue: [Mutex<Vec<Pid>>; MAX_PROC_NUM],
event_hub: Mutex<EventHub<Event>>,
} }
impl ProcessManager { impl ProcessManager {
@ -38,6 +47,8 @@ impl ProcessManager {
ProcessManager { ProcessManager {
procs: Default::default(), procs: Default::default(),
scheduler: Mutex::new(scheduler), scheduler: Mutex::new(scheduler),
wait_queue: Default::default(),
event_hub: Mutex::new(EventHub::new()),
} }
} }
@ -53,7 +64,6 @@ impl ProcessManager {
/// Add a new process /// Add a new process
pub fn add(&self, context: Box<Context>) -> Pid { pub fn add(&self, context: Box<Context>) -> Pid {
let pid = self.alloc_pid(); let pid = self.alloc_pid();
// TODO: check parent
*self.procs[pid].lock() = Some(Process { *self.procs[pid].lock() = Some(Process {
id: pid, id: pid,
status: Status::Ready, status: Status::Ready,
@ -68,6 +78,13 @@ impl ProcessManager {
/// Return true if time slice == 0. /// Return true if time slice == 0.
/// Called by timer interrupt handler. /// Called by timer interrupt handler.
pub fn tick(&self, pid: Pid) -> bool { 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) self.scheduler.lock().tick(pid)
} }
@ -107,18 +124,22 @@ impl ProcessManager {
/// Switch the status of a process. /// Switch the status of a process.
/// Insert/Remove it to/from scheduler if necessary. /// 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 scheduler = self.scheduler.lock();
let mut proc_lock = self.procs[pid].lock(); let mut proc_lock = self.procs[pid].lock();
let mut proc = proc_lock.as_mut().unwrap(); let mut proc = proc_lock.as_mut().unwrap();
trace!("process {} {:?} -> {:?}", pid, proc.status, status);
match (&proc.status, &status) { match (&proc.status, &status) {
(Status::Ready, Status::Ready) => return, (Status::Ready, Status::Ready) => return,
(Status::Ready, _) => scheduler.remove(pid), (Status::Ready, _) => scheduler.remove(pid),
(Status::Running(_), _) => {}, (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), (_, Status::Ready) => scheduler.insert(pid),
_ => {} _ => {}
} }
trace!("process {} {:?} -> {:?}", pid, proc.status, status);
match proc.status { match proc.status {
Status::Running(_) => proc.status_after_stop = status, Status::Running(_) => proc.status_after_stop = status,
_ => proc.status = 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) { pub fn sleep(dur: Duration) {
let time = dur_to_ticks(dur); let time = dur_to_ticks(dur);
info!("sleep: {:?} ticks", time); info!("sleep: {:?} ticks", time);
// TODO: register wakeup processor().manager().sleep(current().id(), time);
park(); park();
fn dur_to_ticks(dur: Duration) -> usize { 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(); // unsafe { LocalKey::<usize>::get_map() }.clear();
// 让Processor退出当前线程 // 让Processor退出当前线程
// 把f返回值在堆上的指针以线程返回码的形式传递出去 // 把f返回值在堆上的指针以线程返回码的形式传递出去
let pid = processor().pid();
let exit_code = Box::into_raw(ret) as usize; 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(); processor().yield_now();
// 再也不会被调度回来了 // 再也不会被调度回来了
unreachable!() unreachable!()
@ -116,8 +115,7 @@ pub fn yield_now() {
/// Blocks unless or until the current thread's token is made available. /// Blocks unless or until the current thread's token is made available.
pub fn park() { pub fn park() {
info!("park:"); info!("park:");
let pid = processor().pid(); processor().manager().sleep(current().id(), 0);
processor().manager().set_status(pid, Status::Sleeping);
processor().yield_now(); processor().yield_now();
} }
@ -129,7 +127,7 @@ pub struct Thread {
impl Thread { impl Thread {
/// Atomically makes the handle's token available if it is not already. /// Atomically makes the handle's token available if it is not already.
pub fn unpark(&self) { pub fn unpark(&self) {
processor().manager().set_status(self.pid, Status::Ready); processor().manager().wakeup(self.pid);
} }
/// Gets the thread's unique identifier. /// Gets the thread's unique identifier.
pub fn id(&self) -> usize { pub fn id(&self) -> usize {
@ -150,8 +148,19 @@ impl<T> JoinHandle<T> {
} }
/// Waits for the associated thread to finish. /// Waits for the associated thread to finish.
pub fn join(self) -> Result<T, ()> { pub fn join(self) -> Result<T, ()> {
// TODO: wait for the thread loop {
unimplemented!() 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()) { if let Ok(file) = root.borrow().lookup(name.as_str()) {
use process::*; use process::*;
let len = file.borrow().read_at(0, &mut *buf).unwrap(); let len = file.borrow().read_at(0, &mut *buf).unwrap();
processor().manager().add(ContextImpl::new_user(&buf[..len])); let pid = processor().manager().add(ContextImpl::new_user(&buf[..len]));
// TODO: wait for new process processor().manager().wait(thread::current().id(), pid);
processor().yield_now();
} else { } else {
println!("Program not exist"); println!("Program not exist");
} }

@ -68,7 +68,22 @@ fn sys_fork(tf: &TrapFrame) -> i32 {
/// Wait the process exit. /// Wait the process exit.
/// Return the PID. Store exit code to `code` if it's not null. /// Return the PID. Store exit code to `code` if it's not null.
fn sys_wait(pid: usize, code: *mut i32) -> i32 { 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 { fn sys_yield() -> i32 {
@ -78,7 +93,7 @@ fn sys_yield() -> i32 {
/// Kill the process /// Kill the process
fn sys_kill(pid: usize) -> i32 { fn sys_kill(pid: usize) -> i32 {
processor().manager().set_status(pid, Status::Exited(0x100)); processor().manager().exit(pid, 0x100);
0 0
} }
@ -90,9 +105,9 @@ fn sys_getpid() -> i32 {
/// Exit the current process /// Exit the current process
fn sys_exit(exit_code: usize) -> i32 { fn sys_exit(exit_code: usize) -> i32 {
let pid = thread::current().id(); let pid = thread::current().id();
processor().manager().set_status(pid, Status::Exited(exit_code)); processor().manager().exit(pid, exit_code);
processor().yield_now(); processor().yield_now();
0 unreachable!();
} }
fn sys_sleep(time: usize) -> i32 { fn sys_sleep(time: usize) -> i32 {
@ -102,7 +117,7 @@ fn sys_sleep(time: usize) -> i32 {
} }
fn sys_get_time() -> i32 { fn sys_get_time() -> i32 {
unimplemented!(); unsafe { ::trap::TICK as i32 }
} }
fn sys_lab6_set_priority(priority: usize) -> i32 { fn sys_lab6_set_priority(priority: usize) -> i32 {

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