diff --git a/src/arch/x86_64/interrupt/handler.rs b/src/arch/x86_64/interrupt/handler.rs index c66db3b..f771693 100644 --- a/src/arch/x86_64/interrupt/handler.rs +++ b/src/arch/x86_64/interrupt/handler.rs @@ -13,11 +13,10 @@ //! * 调用`rust_trap`,并把此时的rsp传过来,也就是`TrapFrame`的指针 //! * `rust_trap`完成以下工作: //! * 根据tf中的中断号,再次分发到具体的中断处理函数。 -//! 一些函数可能会修改rsp的值以完成进程切换。 -//! * 在离开前,检查新的tf中的cs段,如果是用户态,向TSS中设置下一次中断时重置rsp的值,使其指向该用户线程的内核栈 -//! * 返回新的rsp的值 +//! 一些函数可能会调用switch(),切换到其它线程执行,在某一时刻再切换回来。 +//! * 如果需要,执行进程调度 //! * `__alltraps`完成以下工作: -//! * 重置rsp +//! * 检查tf中的cs段,如果是用户态,向TSS中设置下一次中断时重置rsp的值,使其指向该用户线程的内核栈 //! * 从栈中pop全部寄存器的值,pop中断号和错误码 //! * 执行iret,CPU从栈中pop一些值(若其中的CS是Ring0,3项,否则5项),重置rip和rsp(Ring3时) @@ -29,7 +28,7 @@ pub extern fn rust_trap(tf: &mut TrapFrame) { // Dispatch match tf.trap_num as u8 { T_BRKPT => breakpoint(), - T_DBLFLT => double_fault(), + T_DBLFLT => double_fault(tf), T_PGFLT => page_fault(tf), T_IRQ0...64 => { let irq = tf.trap_num as u8 - T_IRQ0; @@ -62,8 +61,8 @@ fn breakpoint() { error!("\nEXCEPTION: Breakpoint"); } -fn double_fault() { - error!("\nEXCEPTION: Double Fault"); +fn double_fault(tf: &TrapFrame) { + error!("\nEXCEPTION: Double Fault\n{:#x?}", tf); loop {} } diff --git a/src/arch/x86_64/interrupt/trapframe.rs b/src/arch/x86_64/interrupt/trapframe.rs index 8c55245..b8d0dba 100644 --- a/src/arch/x86_64/interrupt/trapframe.rs +++ b/src/arch/x86_64/interrupt/trapframe.rs @@ -132,6 +132,7 @@ extern fn forkret() { /// Store current rsp at `from_rsp`. Switch kernel stack to `to_rsp`. /// Pop all callee-saved registers, then return to the target. #[naked] +#[inline(never)] pub unsafe extern fn switch(from_rsp: &mut usize, to_rsp: usize) { asm!( " diff --git a/src/process/process.rs b/src/process/process.rs index b7684b6..9128433 100644 --- a/src/process/process.rs +++ b/src/process/process.rs @@ -16,9 +16,6 @@ pub struct Process { pub(in process) status: Status, pub(in process) rsp: usize, pub(in process) is_user: bool, - /// Set (addr, value) after switch. - /// Used to set wait error code. - pub(in process) set_value: Option<(usize, usize)>, } pub type Pid = usize; @@ -50,7 +47,6 @@ impl Process { status: Status::Ready, rsp, is_user: false, - set_value: None, } } @@ -68,7 +64,6 @@ impl Process { status: Status::Running, rsp: 0, // will be set at first schedule is_user: false, - set_value: None, } } @@ -139,7 +134,6 @@ impl Process { status: Status::Ready, rsp, is_user: true, - set_value: None, } } @@ -179,14 +173,9 @@ impl Process { status: Status::Ready, rsp, is_user: true, - set_value: None, } } - pub fn set_return_value(&self, value: usize) { - let tf = unsafe { &mut *(self.rsp as *mut TrapFrame) }; - tf.rax = value; - } pub fn exit_code(&self) -> Option { match self.status { Status::Exited(code) => Some(code), diff --git a/src/process/processor.rs b/src/process/processor.rs index ad5d9c1..07828a3 100644 --- a/src/process/processor.rs +++ b/src/process/processor.rs @@ -130,10 +130,6 @@ impl Processor { *from_pt = Some(old_table); } - if let Some((addr, value)) = to.set_value.take() { - unsafe { *(addr as *mut usize) = value; } - } - info!("Processor: switch from {} to {}\n rsp: ??? -> {:#x}", pid0, pid, to.rsp); unsafe { super::PROCESSOR.try().unwrap().force_unlock(); @@ -163,17 +159,8 @@ impl Processor { self.get_mut(pid).status = Status::Exited(error_code); if let Some(waiter) = self.find_waiter(pid) { info!(" then wakeup {}", waiter); - self.next = Some(waiter); - { - let p = self.get_mut(waiter); - p.set_value.as_mut().unwrap().1 = error_code; - p.status = Status::Ready; - p.set_return_value(0); - } - // FIXME: remove this process - self.get_mut(pid).parent = 0; -// info!("Processor: remove {}", pid); -// self.procs.remove(&pid); + self.get_mut(waiter).status = Status::Ready; + self.switch_to(waiter); // yield } } @@ -183,38 +170,31 @@ impl Processor { } /// Let current process wait for another - pub fn current_wait_for(&mut self, target: WaitTarget, code: *mut i32) -> WaitResult { - info!("Processor: current {} wait for {:?}", self.current_pid, target); - // 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 { - info!("Processor: {} wait find and remove {}", self.current_pid, pid); - self.procs.remove(&pid); - if !code.is_null() { - // WARNING: must be current! (page table) - unsafe { *code = exit_code as i32 }; - } - WaitResult::Ok(pid, exit_code) - } else { + pub fn current_wait_for(&mut self, pid: Pid) -> WaitResult { + info!("Processor: current {} wait for {:?}", self.current_pid, pid); + if self.procs.values().filter(|&p| p.parent == self.current_pid).next().is_none() { + return WaitResult::NotExist; + } + let pid = self.try_wait(pid).unwrap_or_else(|| { info!("Processor: {} wait for {}", self.current_pid, pid); let current_pid = self.current_pid; - let p = self.get_mut(current_pid); - p.status = Status::Waiting(pid); - p.set_value = Some((code as usize, 0)); - WaitResult::Blocked + self.get_mut(current_pid).status = Status::Waiting(pid); + self.schedule(); // yield + self.try_wait(pid).unwrap() + }); + let exit_code = self.get(pid).exit_code().unwrap(); + info!("Processor: {} wait find and remove {}", self.current_pid, pid); + self.procs.remove(&pid); + WaitResult::Ok(pid, exit_code) + } + + /// Try to find a exited wait target + fn try_wait(&mut self, pid: Pid) -> Option { + match pid { + 0 => self.procs.values() + .find(|&p| p.parent == self.current_pid && p.exit_code().is_some()) + .map(|p| p.pid), + _ => self.get(pid).exit_code().map(|_| pid), } } @@ -234,17 +214,8 @@ impl Debug for Processor { } } -#[derive(Debug)] -pub enum WaitTarget { - AnyChild, - Proc(Pid), -} - #[derive(Debug)] pub enum WaitResult { - /// The target process is still running. - /// The waiter's status will be set to `Waiting`. - Blocked, /// The target process is exited with `ErrorCode`. Ok(Pid, ErrorCode), /// The target process is not exist. diff --git a/src/syscall.rs b/src/syscall.rs index 2176a32..ec2d87a 100644 --- a/src/syscall.rs +++ b/src/syscall.rs @@ -94,13 +94,13 @@ fn sys_fork(tf: &TrapFrame) -> i32 { /// Return the PID. Store exit code to `code` if it's not null. fn sys_wait(pid: usize, code: *mut i32) -> i32 { let mut processor = PROCESSOR.try().unwrap().lock(); - let target = match pid { - 0 => WaitTarget::AnyChild, - _ => WaitTarget::Proc(pid), - }; - match processor.current_wait_for(target, code) { - WaitResult::Ok(pid, error_code) => 0, - WaitResult::Blocked => 0, + match processor.current_wait_for(pid) { + WaitResult::Ok(pid, error_code) => { + if !code.is_null() { + unsafe { *code = error_code as i32 }; + } + 0 + }, WaitResult::NotExist => -1, } }