Use switch() to simplify sys_wait. Add #[inline(never)] to switch().

toolchain_update
WangRunji 7 years ago
parent 64b3716c92
commit dc74d37697

@ -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中断号和错误码
//! * 执行iretCPU从栈中pop一些值若其中的CS是Ring03项否则5项重置rip和rspRing3时
@ -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 {}
}

@ -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!(
"

@ -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<ErrorCode> {
match self.status {
Status::Exited(code) => Some(code),

@ -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<Pid> {
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.

@ -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,
}
}

Loading…
Cancel
Save