diff --git a/os/src/mm/frame_allocator.rs b/os/src/mm/frame_allocator.rs index c17385f1..3cbc5623 100644 --- a/os/src/mm/frame_allocator.rs +++ b/os/src/mm/frame_allocator.rs @@ -48,6 +48,7 @@ impl StackFrameAllocator { pub fn init(&mut self, l: PhysPageNum, r: PhysPageNum) { self.current = l.0; self.end = r.0; + println!("last {} Physical Frames.", self.end - self.current); } } impl FrameAllocator for StackFrameAllocator { diff --git a/os/src/mm/memory_set.rs b/os/src/mm/memory_set.rs index 55c04614..766c7594 100644 --- a/os/src/mm/memory_set.rs +++ b/os/src/mm/memory_set.rs @@ -47,10 +47,6 @@ impl MemorySet { areas: Vec::new(), } } - #[allow(unused)] - pub fn dealloc_all_frames(&mut self) { - *self = Self::new_bare(); - } pub fn token(&self) -> usize { self.page_table.token() } @@ -217,7 +213,8 @@ impl MemorySet { self.page_table.translate(vpn) } pub fn clear(&mut self) { - *self = Self::new_bare(); + //*self = Self::new_bare(); + self.areas.clear(); } } diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index ca5d6c8f..7ace0ffe 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -5,7 +5,7 @@ use crate::task::{ current_user_token, add_task, }; -use crate::timer::get_time; +use crate::timer::get_time_ms; use crate::mm::{ translated_str, translated_refmut, @@ -14,18 +14,7 @@ use crate::loader::get_app_data_by_name; use alloc::sync::Arc; pub fn sys_exit(exit_code: i32) -> ! { - // save exit code - let task = current_task().unwrap(); - - // ---- hold current PCB lock - task.acquire_inner_lock().exit_code = exit_code; - // ---- release current PCB lock - - // this function will not return - // drop task manually to maintain rc correctly - drop(task); - - exit_current_and_run_next(); + exit_current_and_run_next(exit_code); panic!("Unreachable in sys_exit!"); } @@ -35,7 +24,7 @@ pub fn sys_yield() -> isize { } pub fn sys_get_time() -> isize { - get_time() as isize + get_time_ms() as isize } pub fn sys_getpid() -> isize { @@ -68,11 +57,21 @@ pub fn sys_exec(path: *const u8) -> isize { } } +/// If there is not a child process whose pid is same as given, return -1. +/// Else if there is a child process but it is still running, return -2. pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize { let task = current_task().unwrap(); // find a child process + // ---- hold current PCB lock let mut inner = task.acquire_inner_lock(); + if inner.children + .iter() + .find(|p| {pid == -1 || pid as usize == p.getpid()}) + .is_none() { + return -1; + // ---- release current PCB lock + } let pair = inner.children .iter() .enumerate() @@ -92,7 +91,7 @@ pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize { *translated_refmut(inner.memory_set.token(), exit_code_ptr) = exit_code; found_pid as isize } else { - -1 + -2 } // ---- release current PCB lock automatically } \ No newline at end of file diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index fd7fea8d..cebcb3b2 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -42,14 +42,17 @@ pub fn suspend_current_and_run_next() { schedule(task_cx_ptr); } -pub fn exit_current_and_run_next() { +pub fn exit_current_and_run_next(exit_code: i32) { // take from Processor let task = take_current_task().unwrap(); // **** hold current PCB lock let mut inner = task.acquire_inner_lock(); // Change status to Zombie inner.task_status = TaskStatus::Zombie; + // Record exit code + inner.exit_code = exit_code; // move any child to its parent + // TODO: do not move to its parent but under initproc // ++++++ hold parent PCB lock here { diff --git a/os/src/timer.rs b/os/src/timer.rs index 7522e708..612d51af 100644 --- a/os/src/timer.rs +++ b/os/src/timer.rs @@ -3,11 +3,16 @@ use crate::sbi::set_timer; use crate::config::CPU_FREQ; const TICKS_PER_SEC: usize = 100; +const MSEC_PER_SEC: usize = 1000; pub fn get_time() -> usize { time::read() } +pub fn get_time_ms() -> usize { + time::read() / (CPU_FREQ / MSEC_PER_SEC) +} + pub fn set_next_trigger() { set_timer(get_time() + CPU_FREQ / TICKS_PER_SEC); } \ No newline at end of file diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 66f463da..f7b0bc29 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -67,13 +67,24 @@ pub fn trap_handler() -> ! { cx.x[10] = result as usize; } Trap::Exception(Exception::StoreFault) | - Trap::Exception(Exception::StorePageFault) => { - println!("[kernel] PageFault in application, bad addr = {:#x}, bad instruction = {:#x}, core dumped.", stval, current_trap_cx().sepc); - exit_current_and_run_next(); + Trap::Exception(Exception::StorePageFault) | + Trap::Exception(Exception::InstructionFault) | + Trap::Exception(Exception::InstructionPageFault) | + Trap::Exception(Exception::LoadFault) | + Trap::Exception(Exception::LoadPageFault) => { + println!( + "[kernel] {:?} in application, bad addr = {:#x}, bad instruction = {:#x}, core dumped.", + scause.cause(), + stval, + current_trap_cx().sepc, + ); + // page fault exit code + exit_current_and_run_next(-2); } Trap::Exception(Exception::IllegalInstruction) => { println!("[kernel] IllegalInstruction in application, core dumped."); - exit_current_and_run_next(); + // illegal instruction exit code + exit_current_and_run_next(-3); } Trap::Interrupt(Interrupt::SupervisorTimer) => { set_next_trigger(); diff --git a/user/src/bin/exit.rs b/user/src/bin/exit.rs new file mode 100644 index 00000000..5bde550b --- /dev/null +++ b/user/src/bin/exit.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +use user_lib::{fork, yield_, waitpid, exit, wait}; + +const MAGIC: i32 = -0x10384; + +#[no_mangle] +pub fn main() -> i32 { + println!("I am the parent. Forking the child..."); + let pid = fork(); + if pid == 0 { + println!("I am the child."); + for _ in 0..7 { yield_(); } + exit(MAGIC); + } else { + println!("I am parent, fork a child pid {}", pid); + } + println!("I am the parent, waiting now.."); + let mut xstate: i32 = 0; + assert!(waitpid(pid as usize, &mut xstate) == pid && xstate == MAGIC); + assert!(waitpid(pid as usize, &mut xstate) < 0 && wait(&mut xstate) <= 0); + println!("waitpid {} ok.", pid); + println!("exit pass."); + 0 +} + diff --git a/user/src/bin/fantastic_text.rs b/user/src/bin/fantastic_text.rs new file mode 100644 index 00000000..bb51db30 --- /dev/null +++ b/user/src/bin/fantastic_text.rs @@ -0,0 +1,44 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +macro_rules! color_text { + ($text:expr, $color:expr) => {{ + format_args!("\x1b[{}m{}\x1b[0m", $color, $text) + }}; +} + +#[no_mangle] +pub fn main() -> i32 { + println!( + "{}{}{}{}{} {}{}{}{} {}{}{}{}{}{}", + color_text!("H", 31), + color_text!("e", 32), + color_text!("l", 33), + color_text!("l", 34), + color_text!("o", 35), + color_text!("R", 36), + color_text!("u", 37), + color_text!("s", 90), + color_text!("t", 91), + color_text!("u", 92), + color_text!("C", 93), + color_text!("o", 94), + color_text!("r", 95), + color_text!("e", 96), + color_text!("!", 97), + ); + + let text = + "reguler \x1b[4munderline\x1b[24m \x1b[7mreverse\x1b[27m \x1b[9mstrikethrough\x1b[29m"; + println!("\x1b[47m{}\x1b[0m", color_text!(text, 30)); + for i in 31..38 { + println!("{}", color_text!(text, i)); + } + for i in 90..98 { + println!("{}", color_text!(text, i)); + } + 0 +} \ No newline at end of file diff --git a/user/src/bin/forktest.rs b/user/src/bin/forktest.rs new file mode 100644 index 00000000..dcf8859e --- /dev/null +++ b/user/src/bin/forktest.rs @@ -0,0 +1,34 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{fork, wait, exit}; + +const MAX_CHILD: usize = 20; + +#[no_mangle] +pub fn main() -> i32 { + for i in 0..MAX_CHILD { + let pid = fork(); + if pid == 0 { + println!("I am child {}", i); + exit(0); + } else { + println!("forked child pid = {}", pid); + } + assert!(pid > 0); + } + let mut exit_code: i32 = 0; + for _ in 0..MAX_CHILD { + if wait(&mut exit_code) <= 0 { + panic!("wait stopped early"); + } + } + if wait(&mut exit_code) > 0 { + panic!("wait got too many"); + } + println!("forktest pass."); + 0 +} \ No newline at end of file diff --git a/user/src/bin/forktest2.rs b/user/src/bin/forktest2.rs new file mode 100644 index 00000000..95d5ca75 --- /dev/null +++ b/user/src/bin/forktest2.rs @@ -0,0 +1,35 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{fork, wait, get_time, getpid, exit, yield_,}; + +static NUM: usize = 13; + +#[no_mangle] +pub fn main() -> i32 { + for _ in 0..NUM { + let pid = fork(); + if pid == 0 { + let current_time = get_time(); + let sleep_length = (current_time as i32 as isize) * (current_time as i32 as isize) % 1000 + 1000; + println!("Subprocess {} sleep for {} ms", getpid(), sleep_length); + while get_time() < current_time + sleep_length { + yield_(); + } + println!("Subprocess {} OK!", getpid()); + exit(0); + } + } + + let mut xstate: i32 = 0; + for _ in 0..NUM { + assert!(wait(&mut xstate) > 0); + assert_eq!(xstate, 0); + } + assert!(wait(&mut xstate) < 0); + println!("r_forktest2 test passed!"); + 0 +} \ No newline at end of file diff --git a/user/src/bin/forktest_simple.rs b/user/src/bin/forktest_simple.rs new file mode 100644 index 00000000..1851aea0 --- /dev/null +++ b/user/src/bin/forktest_simple.rs @@ -0,0 +1,28 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{fork, getpid, wait}; + +#[no_mangle] +pub fn main() -> i32 { + assert_eq!(wait(&mut 0i32), -1); + println!("sys_wait without child process test passed!"); + println!("parent start, pid = {}!", getpid()); + let pid = fork(); + if pid == 0 { + // child process + println!("hello child process!"); + 100 + } else { + // parent process + let mut xstate: i32 = 0; + println!("ready waiting on parent process!"); + assert_eq!(pid, wait(&mut xstate)); + assert_eq!(xstate, 100); + println!("child process pid = {}, exit code = {}", pid, xstate); + 0 + } +} \ No newline at end of file diff --git a/user/src/bin/hello_world.rs b/user/src/bin/hello_world.rs new file mode 100644 index 00000000..de4a6a92 --- /dev/null +++ b/user/src/bin/hello_world.rs @@ -0,0 +1,11 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +#[no_mangle] +pub fn main() -> i32 { + println!("Hello world from user mode program!"); + 0 +} \ No newline at end of file diff --git a/user/src/bin/matrix.rs b/user/src/bin/matrix.rs index 729625e0..d5f946b8 100644 --- a/user/src/bin/matrix.rs +++ b/user/src/bin/matrix.rs @@ -4,9 +4,9 @@ #[macro_use] extern crate user_lib; -use user_lib::{fork, wait, yield_, exit, getpid, get_time, wait_once}; +use user_lib::{fork, wait, yield_, exit, getpid, get_time}; -static NUM: usize = 13; +static NUM: usize = 20; const N: usize = 10; static P: i32 = 10007; type Arr = [[i32; N]; N]; @@ -50,7 +50,7 @@ pub fn main() -> i32 { if pid == 0 { let current_time = get_time(); let times = (current_time as i32 as isize) * (current_time as i32 as isize) % 1000; - work(times * 40); + work(times * 10); } } @@ -62,7 +62,7 @@ pub fn main() -> i32 { panic!("wait failed."); } } - assert!(wait_once(&mut xstate) < 0); + assert!(wait(&mut xstate) < 0); println!("matrix passed."); 0 } \ No newline at end of file diff --git a/user/src/bin/sleep.rs b/user/src/bin/sleep.rs new file mode 100644 index 00000000..439e8a65 --- /dev/null +++ b/user/src/bin/sleep.rs @@ -0,0 +1,30 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{sleep, exit, get_time, fork, waitpid}; + +fn sleepy() { + let time: usize = 100; + for i in 0..5 { + sleep(time); + println!("sleep {} x {} msecs.", i + 1, time); + } + exit(0); +} + +#[no_mangle] +pub fn main() -> i32 { + let current_time = get_time(); + let pid = fork(); + let mut xstate: i32 = 0; + if pid == 0 { + sleepy(); + } + assert!(waitpid(pid as usize, &mut xstate) == pid && xstate == 0); + println!("use {} msecs.", get_time() - current_time); + println!("sleep pass."); + 0 +} \ No newline at end of file diff --git a/user/src/bin/sleep_simple.rs b/user/src/bin/sleep_simple.rs new file mode 100644 index 00000000..4c058f87 --- /dev/null +++ b/user/src/bin/sleep_simple.rs @@ -0,0 +1,19 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +use user_lib::{get_time, sleep}; + +#[no_mangle] +pub fn main() -> i32 { + println!("into sleep test!"); + let start = get_time(); + println!("current time_msec = {}", start); + sleep(100); + let end = get_time(); + println!("time_msec = {} after sleeping 100 ticks, delta = {}ms!", end, end - start); + println!("r_sleep passed!"); + 0 +} \ No newline at end of file diff --git a/user/src/bin/stack_overflow.rs b/user/src/bin/stack_overflow.rs new file mode 100644 index 00000000..e0ea471d --- /dev/null +++ b/user/src/bin/stack_overflow.rs @@ -0,0 +1,17 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +fn f(d: usize) { + println!("d = {}",d); + f(d + 1); +} + +#[no_mangle] +pub fn main() -> i32 { + println!("It should trigger segmentation fault!"); + f(0); + 0 +} \ No newline at end of file diff --git a/user/src/bin/user_shell.rs b/user/src/bin/user_shell.rs index b871ea74..6aa8e31f 100644 --- a/user/src/bin/user_shell.rs +++ b/user/src/bin/user_shell.rs @@ -53,7 +53,7 @@ pub fn main() -> i32 { } print!(">> "); } - DL => { + BS | DL => { if !line.is_empty() { print!("{}", BS as char); print!(" "); diff --git a/user/src/bin/usertests.rs b/user/src/bin/usertests.rs new file mode 100644 index 00000000..d5d0d7d2 --- /dev/null +++ b/user/src/bin/usertests.rs @@ -0,0 +1,40 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; + +static TESTS: &[&str] = &[ + "exit\0", + "fantastic_text\0", + "forktest\0", + "forktest2\0", + "forktest_simple\0", + "hello_world\0", + "matrix\0", + "sleep\0", + "sleep_simple\0", + "stack_overflow\0", + "yield\0", +]; + +use user_lib::{exec, fork, waitpid}; + +#[no_mangle] +pub fn main() -> i32 { + for test in TESTS { + println!("Usertests: Running {}", test); + let pid = fork(); + if pid == 0 { + exec(*test); + panic!("unreachable!"); + } else { + let mut xstate: i32 = Default::default(); + let wait_pid = waitpid(pid as usize, &mut xstate); + assert_eq!(pid, wait_pid); + println!("\x1b[32mUsertests: Test {} in Process {} exited with code {}\x1b[0m", test, pid, xstate); + } + } + println!("Usertests passed!"); + 0 +} \ No newline at end of file diff --git a/user/src/bin/yield.rs b/user/src/bin/yield.rs new file mode 100644 index 00000000..55032e40 --- /dev/null +++ b/user/src/bin/yield.rs @@ -0,0 +1,17 @@ +#![no_std] +#![no_main] + +#[macro_use] +extern crate user_lib; +use user_lib::{getpid, yield_}; + +#[no_mangle] +pub fn main() -> i32 { + println!("Hello, I am process {}.", getpid()); + for i in 0..5 { + yield_(); + println!("Back in process {}, iteration {}.", getpid(), i); + } + println!("yield pass."); + 0 +} \ No newline at end of file diff --git a/user/src/lib.rs b/user/src/lib.rs index 8f3c77da..5c434e6d 100644 --- a/user/src/lib.rs +++ b/user/src/lib.rs @@ -51,19 +51,25 @@ pub fn exec(path: &str) -> isize { sys_exec(path) } pub fn wait(exit_code: &mut i32) -> isize { loop { match sys_waitpid(-1, exit_code as *mut _) { - -1 => { yield_(); } + -2 => { yield_(); } + // -1 or a real pid exit_pid => return exit_pid, } } } -pub fn wait_once(exit_code: &mut i32) -> isize { - sys_waitpid(-1, exit_code as *mut _) -} + pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize { loop { match sys_waitpid(pid as isize, exit_code as *mut _) { - -1 => { yield_(); } + -2 => { yield_(); } + // -1 or a real pid exit_pid => return exit_pid, } } +} +pub fn sleep(period_ms: usize) { + let start = sys_get_time(); + while sys_get_time() < start + period_ms as isize { + sys_yield(); + } } \ No newline at end of file