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() {
Trap::Interrupt(SupervisorTimer) => timer(),
Trap::Exception(UserEnvCall) => syscall(tf),
_ => panic!("Unhandled interrupt: {:?}\n{:#010x?}", tf.scause.cause(), tf),
_ => ::trap::error(tf),
}
::trap::before_return();
trace!("Interrupt end");

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

@ -170,16 +170,7 @@ fn syscall32(tf: &mut TrapFrame) {
}
fn error(tf: &TrapFrame) {
use process::PROCESSOR;
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 {}
}
::trap::error(tf);
}
#[no_mangle]

@ -3,7 +3,6 @@ use alloc::boxed::Box;
#[cfg(target_arch = "x86_64")]
use arch::driver::ide;
use spin::Mutex;
use process;
pub fn shell() {
#[cfg(target_arch = "riscv")]
@ -31,7 +30,8 @@ pub fn shell() {
}
if let Ok(file) = root.borrow().lookup(name.as_str()) {
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 {
println!("Program not exist");
}

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

@ -1,48 +1,21 @@
use alloc::String;
use memory::MemorySet;
use self::process::*;
pub use self::context::*;
pub use self::processor::*;
use spin::Once;
use sync::SpinNoIrqLock;
use sync::{SpinNoIrqLock, Mutex, MutexGuard, SpinNoIrq};
mod process;
mod context;
mod processor;
mod scheduler;
pub fn init() {
PROCESSOR.call_once(|| {
SpinNoIrqLock::new({
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
})
});
PROCESSOR.call_once(||
SpinNoIrqLock::new(Processor::new(unsafe { Context::new_init() }))
);
}
pub static PROCESSOR: Once<SpinNoIrqLock<Processor>> = Once::new();
extern fn idle_thread(_arg: usize) -> ! {
println!("Hello, I'm idle.");
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());
pub fn processor() -> MutexGuard<'static, Processor, SpinNoIrq> {
PROCESSOR.try().unwrap().lock()
}

@ -1,9 +1,29 @@
use alloc::BTreeMap;
use core::fmt::{Debug, Error, Formatter};
use super::process::*;
use super::context::*;
use super::scheduler::*;
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 {
procs: BTreeMap<Pid, Process>,
current_pid: Pid,
@ -14,11 +34,30 @@ pub struct Processor {
scheduler: RRScheduler,
}
impl Process {
fn exit_code(&self) -> Option<ErrorCode> {
match self.status {
Status::Exited(code) => Some(code),
_ => None,
}
}
}
// TODO: 除schedule()外的其它函数应该只设置进程状态不应调用schedule
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 {
procs: BTreeMap::<Pid, Process>::new(),
procs: {
let mut map = BTreeMap::<Pid, Process>::new();
map.insert(0, init_proc);
map
},
current_pid: 0,
event_hub: EventHub::new(),
next: None,
@ -28,7 +67,6 @@ impl Processor {
}
pub fn lab6_set_priority(&mut self, priority: u8) {
unimplemented!();
// self.scheduler.set_priority(self.current_pid, priority);
}
@ -89,12 +127,15 @@ impl Processor {
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();
process.pid = pid;
if process.status == Status::Ready {
self.scheduler.insert(pid);
}
let process = Process {
pid,
parent: self.current_pid,
status: Status::Ready,
context,
};
self.scheduler.insert(pid);
self.procs.insert(pid, process);
pid
}
@ -102,7 +143,7 @@ impl Processor {
/// Called every interrupt end
/// Do schedule ONLY IF current status != Running
pub fn schedule(&mut self) {
if self.current().status == Status::Running {
if self.get(self.current_pid).status == Status::Running {
return;
}
let pid = self.next.take().unwrap_or_else(|| self.scheduler.select().unwrap());
@ -117,7 +158,7 @@ impl Processor {
let pid0 = 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);
}
return;
@ -137,7 +178,7 @@ impl Processor {
use core::mem::forget;
super::PROCESSOR.try().unwrap().force_unlock();
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 {
self.procs.get_mut(&pid).unwrap()
}
pub fn current(&self) -> &Process {
self.get(self.current_pid)
pub fn current_context(&self) -> &Context {
&self.get(self.current_pid).context
}
pub fn current_pid(&self) -> 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)]
pub enum WaitResult {
/// 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.
fn sys_fork(tf: &TrapFrame) -> i32 {
let mut processor = PROCESSOR.try().unwrap().lock();
let new = processor.current().fork(tf);
let pid = processor.add(new);
let mut processor = processor();
let context = processor.current_context().fork(tf);
let pid = processor.add(context);
info!("fork: {} -> {}", processor.current_pid(), pid);
pid as i32
}
@ -68,7 +68,7 @@ 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 {
let mut processor = PROCESSOR.try().unwrap().lock();
let mut processor = processor();
match processor.current_wait_for(pid) {
WaitResult::Ok(pid, error_code) => {
if !code.is_null() {
@ -87,7 +87,7 @@ fn sys_yield() -> i32 {
/// Kill the process
fn sys_kill(pid: usize) -> i32 {
PROCESSOR.try().unwrap().lock().kill(pid);
processor().kill(pid);
0
}
@ -98,7 +98,7 @@ fn sys_getpid() -> i32 {
/// Exit the current process
fn sys_exit(error_code: usize) -> i32 {
let mut processor = PROCESSOR.try().unwrap().lock();
let mut processor = processor();
let pid = processor.current_pid();
processor.exit(pid, error_code);
0
@ -111,12 +111,12 @@ fn sys_sleep(time: usize) -> i32 {
}
fn sys_get_time() -> i32 {
let processor = PROCESSOR.try().unwrap().lock();
let processor = processor();
processor.get_time() as 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);
0
}

@ -14,7 +14,7 @@ use process::*;
/// Gets a handle to the thread that invokes it.
pub fn current() -> 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) {
let time = dur_to_ticks(dur);
info!("sleep: {:?} ticks", time);
let mut processor = PROCESSOR.try().unwrap().lock();
let mut processor = processor();
let pid = processor.current_pid();
processor.sleep(pid, time);
processor.schedule();
@ -39,9 +39,8 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
T: Send + 'static,
{
info!("spawn:");
use process;
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 {
thread: Thread { pid },
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 ret = Box::new(f());
unsafe { LocalKey::<usize>::get_map() }.clear();
let mut processor = PROCESSOR.try().unwrap().lock();
let mut processor = processor();
let pid = processor.current_pid();
processor.exit(pid, Box::into_raw(ret) as usize);
processor.schedule();
@ -66,7 +65,7 @@ pub fn spawn<F, T>(f: F) -> JoinHandle<T>
/// Cooperatively gives up a timeslice to the OS scheduler.
pub fn yield_now() {
info!("yield:");
let mut processor = PROCESSOR.try().unwrap().lock();
let mut processor = processor();
processor.set_reschedule();
processor.schedule();
}
@ -74,7 +73,7 @@ pub fn yield_now() {
/// Blocks unless or until the current thread's token is made available.
pub fn park() {
info!("park:");
let mut processor = PROCESSOR.try().unwrap().lock();
let mut processor = processor();
let pid = processor.current_pid();
processor.sleep_(pid);
processor.schedule();
@ -88,7 +87,7 @@ pub struct Thread {
impl Thread {
/// Atomically makes the handle's token available if it is not already.
pub fn unpark(&self) {
let mut processor = PROCESSOR.try().unwrap().lock();
let mut processor = processor();
processor.wakeup_(self.pid);
}
/// Gets the thread's unique identifier.
@ -110,13 +109,10 @@ impl<T> JoinHandle<T> {
}
/// Waits for the associated thread to finish.
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) {
WaitResult::Ok(_, exit_code) => {
unsafe {
let value = Box::from_raw(exit_code as *mut T);
Ok(ptr::read(exit_code as *const T))
}
WaitResult::Ok(_, exit_code) => unsafe {
Ok(*Box::from_raw(exit_code as *mut T))
}
WaitResult::NotExist => Err(()),
}

@ -1,14 +1,24 @@
use process::PROCESSOR;
use process::*;
use arch::interrupt::TrapFrame;
pub fn timer() {
let mut processor = PROCESSOR.try().unwrap().lock();
let mut processor = processor();
processor.tick();
}
pub fn before_return() {
use process::PROCESSOR;
if let Some(processor) = PROCESSOR.try() {
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