Refactor process mod

master
WangRunji 6 years ago
parent 97b838981f
commit 37a6df252f

@ -41,7 +41,7 @@ pub extern fn rust_trap(tf: &mut TrapFrame) {
match tf.scause.cause() { match tf.scause.cause() {
Trap::Interrupt(SupervisorTimer) => timer(), Trap::Interrupt(SupervisorTimer) => timer(),
Trap::Exception(UserEnvCall) => syscall(tf), Trap::Exception(UserEnvCall) => syscall(tf),
_ => panic!("Unhandled interrupt: {:?}\n{:#010x?}", tf.scause.cause(), tf), _ => ::trap::error(tf),
} }
::trap::before_return(); ::trap::before_return();
trace!("Interrupt end"); trace!("Interrupt end");

@ -6,7 +6,7 @@ struct SerialPort;
impl Write for SerialPort { impl Write for SerialPort {
fn write_str(&mut self, s: &str) -> Result { fn write_str(&mut self, s: &str) -> Result {
for c in s.bytes() { for c in s.bytes() {
if c == 8 { if c == 127 {
sbi::console_putchar(8); sbi::console_putchar(8);
sbi::console_putchar(' ' as usize); sbi::console_putchar(' ' as usize);
sbi::console_putchar(8); sbi::console_putchar(8);
@ -20,9 +20,9 @@ impl Write for SerialPort {
pub fn getchar() -> char { pub fn getchar() -> char {
match sbi::console_getchar() as u8 { match sbi::console_getchar() as u8 {
255 => 0, // null 255 => '\0', // null
c => c, c => c as char,
} as char }
} }
pub fn putfmt(fmt: Arguments) { pub fn putfmt(fmt: Arguments) {

@ -170,16 +170,7 @@ fn syscall32(tf: &mut TrapFrame) {
} }
fn error(tf: &TrapFrame) { fn error(tf: &TrapFrame) {
use process::PROCESSOR; ::trap::error(tf);
if let Some(processor) = PROCESSOR.try() {
let mut processor = processor.lock();
let pid = processor.current_pid();
error!("Process {} error:\n{:#x?}", pid, tf);
processor.exit(pid, 0x100); // TODO: Exit code for error
} else {
error!("Exception {:#x} when processor not inited\n{:#x?}", tf.trap_num, tf);
loop {}
}
} }
#[no_mangle] #[no_mangle]

@ -3,7 +3,6 @@ use alloc::boxed::Box;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use arch::driver::ide; use arch::driver::ide;
use spin::Mutex; use spin::Mutex;
use process;
pub fn shell() { pub fn shell() {
#[cfg(target_arch = "riscv")] #[cfg(target_arch = "riscv")]
@ -31,7 +30,8 @@ pub fn shell() {
} }
if let Ok(file) = root.borrow().lookup(name.as_str()) { if let Ok(file) = root.borrow().lookup(name.as_str()) {
let len = file.borrow().read_at(0, &mut *buf).unwrap(); let len = file.borrow().read_at(0, &mut *buf).unwrap();
process::add_user_process(name, &buf[..len]); use process::*;
processor().add(Context::new_user(&buf[..len]));
} else { } else {
println!("Program not exist"); println!("Program not exist");
} }

@ -1,57 +1,30 @@
use alloc::String; use arch::interrupt::{TrapFrame, Context as ArchContext};
use arch::interrupt::*;
use memory::{MemoryArea, MemoryAttr, MemorySet}; use memory::{MemoryArea, MemoryAttr, MemorySet};
use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}}; use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}};
use core::fmt::{Debug, Error, Formatter};
#[derive(Debug)] pub struct Context {
pub struct Process { arch: ArchContext,
pub(in process) pid: Pid, memory_set: MemorySet,
pub(in process) parent: Pid,
pub(in process) name: String,
pub(in process) memory_set: MemorySet,
pub(in process) status: Status,
pub(in process) context: Context,
} }
pub type Pid = usize; impl Context {
pub type ErrorCode = usize; pub unsafe fn switch(&mut self, target: &mut Self) {
self.arch.switch(&mut target.arch);
#[derive(Debug, Clone, Eq, PartialEq)] }
pub enum Status {
Ready,
Running,
Waiting(Pid),
Sleeping,
Exited(ErrorCode),
}
impl Process {
/// Make a new kernel thread
pub fn new(name: &str, entry: extern fn(usize) -> !, arg: usize) -> Self {
let ms = MemorySet::new();
let context = unsafe { Context::new_kernel_thread(entry, arg, ms.kstack_top(), ms.token()) };
Process { pub unsafe fn new_init() -> Self {
pid: 0, Context {
parent: 0, arch: ArchContext::null(),
name: String::from(name), memory_set: MemorySet::new(),
memory_set: ms,
status: Status::Ready,
context,
} }
} }
/// Make the first kernel thread `initproc` pub fn new_kernel(entry: extern fn(usize) -> !, arg: usize) -> Self {
/// Should be called only once let ms = MemorySet::new();
pub fn new_init() -> Self { Context {
assert_has_not_been_called!(); arch: unsafe { ArchContext::new_kernel_thread(entry, arg, ms.kstack_top(), ms.token()) },
Process { memory_set: ms,
pid: 0,
parent: 0,
name: String::from("init"),
memory_set: MemorySet::new(),
status: Status::Running,
context: unsafe { Context::null() }, // will be set at first schedule
} }
} }
@ -100,20 +73,12 @@ impl Process {
}); });
} }
Context {
// Allocate kernel stack and push trap frame arch: unsafe {
let context = unsafe { ArchContext::new_user_thread(
Context::new_user_thread( entry_addr, user_stack_top - 8, memory_set.kstack_top(), is32, memory_set.token())
entry_addr, user_stack_top - 8, memory_set.kstack_top(), is32, memory_set.token()) },
};
Process {
pid: 0,
parent: 0,
name: String::new(),
memory_set, memory_set,
status: Status::Ready,
context,
} }
} }
@ -123,7 +88,7 @@ impl Process {
let memory_set = self.memory_set.clone(); let memory_set = self.memory_set.clone();
// Copy data to temp space // Copy data to temp space
use alloc::Vec; use alloc::vec::Vec;
let datas: Vec<Vec<u8>> = memory_set.iter().map(|area| { let datas: Vec<Vec<u8>> = memory_set.iter().map(|area| {
Vec::from(unsafe { area.as_slice() }) Vec::from(unsafe { area.as_slice() })
}).collect(); }).collect();
@ -137,24 +102,16 @@ impl Process {
}); });
} }
// Push context at kstack top Context {
let context = unsafe { Context::new_fork(tf, memory_set.kstack_top(), memory_set.token()) }; arch: unsafe { ArchContext::new_fork(tf, memory_set.kstack_top(), memory_set.token()) },
Process {
pid: 0,
parent: self.pid,
name: self.name.clone() + "_fork",
memory_set, memory_set,
status: Status::Ready,
context,
} }
} }
}
pub fn exit_code(&self) -> Option<ErrorCode> { impl Debug for Context {
match self.status { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
Status::Exited(code) => Some(code), write!(f, "{:?}", self.arch)
_ => None,
}
} }
} }

@ -1,48 +1,21 @@
use alloc::String; use alloc::String;
use memory::MemorySet; pub use self::context::*;
use self::process::*;
pub use self::processor::*; pub use self::processor::*;
use spin::Once; use spin::Once;
use sync::SpinNoIrqLock; use sync::{SpinNoIrqLock, Mutex, MutexGuard, SpinNoIrq};
mod process; mod context;
mod processor; mod processor;
mod scheduler; mod scheduler;
pub fn init() { pub fn init() {
PROCESSOR.call_once(|| { PROCESSOR.call_once(||
SpinNoIrqLock::new({ SpinNoIrqLock::new(Processor::new(unsafe { Context::new_init() }))
let initproc = Process::new_init(); );
let idleproc = Process::new("idle", idle_thread, 0);
let mut processor = Processor::new();
processor.add(initproc);
processor.add(idleproc);
processor
})
});
} }
pub static PROCESSOR: Once<SpinNoIrqLock<Processor>> = Once::new(); pub static PROCESSOR: Once<SpinNoIrqLock<Processor>> = Once::new();
extern fn idle_thread(_arg: usize) -> ! { pub fn processor() -> MutexGuard<'static, Processor, SpinNoIrq> {
println!("Hello, I'm idle."); PROCESSOR.try().unwrap().lock()
loop {}
}
pub fn add_user_process(name: impl AsRef<str>, data: &[u8]) {
let mut processor = PROCESSOR.try().unwrap().lock();
let mut new = Process::new_user(data);
new.name = String::from(name.as_ref());
processor.add(new);
}
pub fn add_kernel_process(entry: extern fn(usize) -> !, arg: usize) -> Pid {
let mut processor = PROCESSOR.try().unwrap().lock();
let new = Process::new("", entry, arg);
processor.add(new)
}
pub fn print() {
debug!("{:#x?}", *PROCESSOR.try().unwrap().lock());
} }

@ -1,9 +1,29 @@
use alloc::BTreeMap; use alloc::BTreeMap;
use core::fmt::{Debug, Error, Formatter}; use core::fmt::{Debug, Error, Formatter};
use super::process::*; use super::context::*;
use super::scheduler::*; use super::scheduler::*;
use util::{EventHub, GetMut2}; use util::{EventHub, GetMut2};
#[derive(Debug)]
pub struct Process {
pid: Pid,
parent: Pid,
status: Status,
context: Context,
}
pub type Pid = usize;
pub type ErrorCode = usize;
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Status {
Ready,
Running,
Waiting(Pid),
Sleeping,
Exited(ErrorCode),
}
pub struct Processor { pub struct Processor {
procs: BTreeMap<Pid, Process>, procs: BTreeMap<Pid, Process>,
current_pid: Pid, current_pid: Pid,
@ -14,11 +34,30 @@ pub struct Processor {
scheduler: RRScheduler, scheduler: RRScheduler,
} }
impl Process {
fn exit_code(&self) -> Option<ErrorCode> {
match self.status {
Status::Exited(code) => Some(code),
_ => None,
}
}
}
// TODO: 除schedule()外的其它函数应该只设置进程状态不应调用schedule // TODO: 除schedule()外的其它函数应该只设置进程状态不应调用schedule
impl Processor { impl Processor {
pub fn new() -> Self { pub fn new(init_context: Context) -> Self {
let init_proc = Process {
pid: 0,
parent: 0,
status: Status::Running,
context: init_context,
};
Processor { Processor {
procs: BTreeMap::<Pid, Process>::new(), procs: {
let mut map = BTreeMap::<Pid, Process>::new();
map.insert(0, init_proc);
map
},
current_pid: 0, current_pid: 0,
event_hub: EventHub::new(), event_hub: EventHub::new(),
next: None, next: None,
@ -28,7 +67,6 @@ impl Processor {
} }
pub fn lab6_set_priority(&mut self, priority: u8) { pub fn lab6_set_priority(&mut self, priority: u8) {
unimplemented!();
// self.scheduler.set_priority(self.current_pid, priority); // self.scheduler.set_priority(self.current_pid, priority);
} }
@ -89,12 +127,15 @@ impl Processor {
self.event_hub.get_time() self.event_hub.get_time()
} }
pub fn add(&mut self, mut process: Process) -> Pid { pub fn add(&mut self, context: Context) -> Pid {
let pid = self.alloc_pid(); let pid = self.alloc_pid();
process.pid = pid; let process = Process {
if process.status == Status::Ready { pid,
self.scheduler.insert(pid); parent: self.current_pid,
} status: Status::Ready,
context,
};
self.scheduler.insert(pid);
self.procs.insert(pid, process); self.procs.insert(pid, process);
pid pid
} }
@ -102,7 +143,7 @@ impl Processor {
/// Called every interrupt end /// Called every interrupt end
/// Do schedule ONLY IF current status != Running /// Do schedule ONLY IF current status != Running
pub fn schedule(&mut self) { pub fn schedule(&mut self) {
if self.current().status == Status::Running { if self.get(self.current_pid).status == Status::Running {
return; return;
} }
let pid = self.next.take().unwrap_or_else(|| self.scheduler.select().unwrap()); let pid = self.next.take().unwrap_or_else(|| self.scheduler.select().unwrap());
@ -117,7 +158,7 @@ impl Processor {
let pid0 = self.current_pid; let pid0 = self.current_pid;
if pid == self.current_pid { if pid == self.current_pid {
if self.current().status != Status::Running { if self.get(self.current_pid).status != Status::Running {
self.set_status(pid, Status::Running); self.set_status(pid, Status::Running);
} }
return; return;
@ -137,7 +178,7 @@ impl Processor {
use core::mem::forget; use core::mem::forget;
super::PROCESSOR.try().unwrap().force_unlock(); super::PROCESSOR.try().unwrap().force_unlock();
from.context.switch(&mut to.context); from.context.switch(&mut to.context);
forget(super::PROCESSOR.try().unwrap().lock()); forget(super::processor());
} }
} }
@ -147,8 +188,8 @@ impl Processor {
fn get_mut(&mut self, pid: Pid) -> &mut Process { fn get_mut(&mut self, pid: Pid) -> &mut Process {
self.procs.get_mut(&pid).unwrap() self.procs.get_mut(&pid).unwrap()
} }
pub fn current(&self) -> &Process { pub fn current_context(&self) -> &Context {
self.get(self.current_pid) &self.get(self.current_pid).context
} }
pub fn current_pid(&self) -> Pid { pub fn current_pid(&self) -> Pid {
self.current_pid self.current_pid
@ -215,14 +256,6 @@ impl Processor {
} }
} }
impl Debug for Processor {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
f.debug_map()
.entries(self.procs.iter().map(|(pid, proc0)| { (pid, &proc0.name) }))
.finish()
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum WaitResult { pub enum WaitResult {
/// The target process is exited with `ErrorCode`. /// The target process is exited with `ErrorCode`.

@ -58,9 +58,9 @@ fn sys_close(fd: usize) -> i32 {
/// Fork the current process. Return the child's PID. /// Fork the current process. Return the child's PID.
fn sys_fork(tf: &TrapFrame) -> i32 { fn sys_fork(tf: &TrapFrame) -> i32 {
let mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = processor();
let new = processor.current().fork(tf); let context = processor.current_context().fork(tf);
let pid = processor.add(new); let pid = processor.add(context);
info!("fork: {} -> {}", processor.current_pid(), pid); info!("fork: {} -> {}", processor.current_pid(), pid);
pid as i32 pid as i32
} }
@ -68,7 +68,7 @@ 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 {
let mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = processor();
match processor.current_wait_for(pid) { match processor.current_wait_for(pid) {
WaitResult::Ok(pid, error_code) => { WaitResult::Ok(pid, error_code) => {
if !code.is_null() { if !code.is_null() {
@ -87,7 +87,7 @@ fn sys_yield() -> i32 {
/// Kill the process /// Kill the process
fn sys_kill(pid: usize) -> i32 { fn sys_kill(pid: usize) -> i32 {
PROCESSOR.try().unwrap().lock().kill(pid); processor().kill(pid);
0 0
} }
@ -98,7 +98,7 @@ fn sys_getpid() -> i32 {
/// Exit the current process /// Exit the current process
fn sys_exit(error_code: usize) -> i32 { fn sys_exit(error_code: usize) -> i32 {
let mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = processor();
let pid = processor.current_pid(); let pid = processor.current_pid();
processor.exit(pid, error_code); processor.exit(pid, error_code);
0 0
@ -111,12 +111,12 @@ fn sys_sleep(time: usize) -> i32 {
} }
fn sys_get_time() -> i32 { fn sys_get_time() -> i32 {
let processor = PROCESSOR.try().unwrap().lock(); let processor = processor();
processor.get_time() as i32 processor.get_time() as i32
} }
fn sys_lab6_set_priority(priority: usize) -> i32 { fn sys_lab6_set_priority(priority: usize) -> i32 {
let mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = processor();
processor.lab6_set_priority(priority as u8); processor.lab6_set_priority(priority as u8);
0 0
} }

@ -14,7 +14,7 @@ use process::*;
/// Gets a handle to the thread that invokes it. /// Gets a handle to the thread that invokes it.
pub fn current() -> Thread { pub fn current() -> Thread {
Thread { Thread {
pid: PROCESSOR.try().unwrap().lock().current_pid(), pid: processor().current_pid(),
} }
} }
@ -22,7 +22,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);
let mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = processor();
let pid = processor.current_pid(); let pid = processor.current_pid();
processor.sleep(pid, time); processor.sleep(pid, time);
processor.schedule(); processor.schedule();
@ -39,9 +39,8 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
T: Send + 'static, T: Send + 'static,
{ {
info!("spawn:"); info!("spawn:");
use process;
let f = Box::into_raw(Box::new(f)); let f = Box::into_raw(Box::new(f));
let pid = process::add_kernel_process(kernel_thread_entry::<F, T>, f as usize); let pid = processor().add(Context::new_kernel(kernel_thread_entry::<F, T>, f as usize));
return JoinHandle { return JoinHandle {
thread: Thread { pid }, thread: Thread { pid },
mark: PhantomData, mark: PhantomData,
@ -55,7 +54,7 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
let f = unsafe { Box::from_raw(f as *mut F) }; let f = unsafe { Box::from_raw(f as *mut F) };
let ret = Box::new(f()); let ret = Box::new(f());
unsafe { LocalKey::<usize>::get_map() }.clear(); unsafe { LocalKey::<usize>::get_map() }.clear();
let mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = processor();
let pid = processor.current_pid(); let pid = processor.current_pid();
processor.exit(pid, Box::into_raw(ret) as usize); processor.exit(pid, Box::into_raw(ret) as usize);
processor.schedule(); processor.schedule();
@ -66,7 +65,7 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
/// Cooperatively gives up a timeslice to the OS scheduler. /// Cooperatively gives up a timeslice to the OS scheduler.
pub fn yield_now() { pub fn yield_now() {
info!("yield:"); info!("yield:");
let mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = processor();
processor.set_reschedule(); processor.set_reschedule();
processor.schedule(); processor.schedule();
} }
@ -74,7 +73,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 mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = processor();
let pid = processor.current_pid(); let pid = processor.current_pid();
processor.sleep_(pid); processor.sleep_(pid);
processor.schedule(); processor.schedule();
@ -88,7 +87,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) {
let mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = processor();
processor.wakeup_(self.pid); processor.wakeup_(self.pid);
} }
/// Gets the thread's unique identifier. /// Gets the thread's unique identifier.
@ -110,13 +109,10 @@ 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, ()> {
let mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = processor();
match processor.current_wait_for(self.thread.pid) { match processor.current_wait_for(self.thread.pid) {
WaitResult::Ok(_, exit_code) => { WaitResult::Ok(_, exit_code) => unsafe {
unsafe { Ok(*Box::from_raw(exit_code as *mut T))
let value = Box::from_raw(exit_code as *mut T);
Ok(ptr::read(exit_code as *const T))
}
} }
WaitResult::NotExist => Err(()), WaitResult::NotExist => Err(()),
} }

@ -1,14 +1,24 @@
use process::PROCESSOR; use process::*;
use arch::interrupt::TrapFrame;
pub fn timer() { pub fn timer() {
let mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = processor();
processor.tick(); processor.tick();
} }
pub fn before_return() { pub fn before_return() {
use process::PROCESSOR;
if let Some(processor) = PROCESSOR.try() { if let Some(processor) = PROCESSOR.try() {
processor.lock().schedule(); processor.lock().schedule();
} }
} }
pub fn error(tf: &TrapFrame) {
if let Some(processor) = PROCESSOR.try() {
let mut processor = processor.lock();
let pid = processor.current_pid();
error!("Process {} error:\n{:#x?}", pid, tf);
processor.exit(pid, 0x100); // TODO: Exit code for error
} else {
panic!("Exception when processor not inited\n{:#x?}", tf);
}
}
Loading…
Cancel
Save