mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-25 19:03:35 +04:00
Implement many process syscalls.
This commit is contained in:
parent
81bef97f09
commit
3642f9c56d
@ -7,12 +7,6 @@ pub const PAGE_SIZE_BITS: usize = 0xc;
|
|||||||
|
|
||||||
pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1;
|
pub const TRAMPOLINE: usize = usize::MAX - PAGE_SIZE + 1;
|
||||||
pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE;
|
pub const TRAP_CONTEXT: usize = TRAMPOLINE - PAGE_SIZE;
|
||||||
/// Return (bottom, top) of a kernel stack in kernel space.
|
|
||||||
pub fn kernel_stack_position(app_id: usize) -> (usize, usize) {
|
|
||||||
let top = TRAMPOLINE - app_id * (KERNEL_STACK_SIZE + PAGE_SIZE);
|
|
||||||
let bottom = top - KERNEL_STACK_SIZE;
|
|
||||||
(bottom, top)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "board_k210")]
|
#[cfg(feature = "board_k210")]
|
||||||
pub const CPU_FREQ: usize = 10000000;
|
pub const CPU_FREQ: usize = 10000000;
|
||||||
|
@ -45,7 +45,8 @@ fn app_names() -> Vec<&'static str> {
|
|||||||
let slice = core::slice::from_raw_parts(start, end as usize - start as usize);
|
let slice = core::slice::from_raw_parts(start, end as usize - start as usize);
|
||||||
let str = core::str::from_utf8(slice).unwrap();
|
let str = core::str::from_utf8(slice).unwrap();
|
||||||
v.push(str);
|
v.push(str);
|
||||||
start = end.add(1);
|
// Mention that there is a extra char between names
|
||||||
|
start = end.add(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
v
|
v
|
||||||
|
@ -41,20 +41,11 @@ pub fn rust_main() -> ! {
|
|||||||
clear_bss();
|
clear_bss();
|
||||||
println!("[kernel] Hello, world!");
|
println!("[kernel] Hello, world!");
|
||||||
mm::init();
|
mm::init();
|
||||||
println!("[kernel] back to world!");
|
|
||||||
mm::remap_test();
|
mm::remap_test();
|
||||||
|
task::add_initproc();
|
||||||
// add apps
|
|
||||||
let num_app = loader::get_num_app();
|
|
||||||
println!("num_app={}", num_app);
|
|
||||||
for i in 0..num_app {
|
|
||||||
println!("i={}", i);
|
|
||||||
task::add_application(loader::get_app_data(i), i);
|
|
||||||
}
|
|
||||||
trap::init();
|
trap::init();
|
||||||
trap::enable_timer_interrupt();
|
trap::enable_timer_interrupt();
|
||||||
timer::set_next_trigger();
|
timer::set_next_trigger();
|
||||||
println!("before task::run_tasks!");
|
|
||||||
task::run_tasks();
|
task::run_tasks();
|
||||||
panic!("Unreachable in rust_main!");
|
panic!("Unreachable in rust_main!");
|
||||||
}
|
}
|
@ -110,6 +110,13 @@ impl VirtPageNum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PhysAddr {
|
||||||
|
pub fn get_mut<T>(&self) -> &'static mut T {
|
||||||
|
unsafe {
|
||||||
|
(self.0 as *mut T).as_mut().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
impl PhysPageNum {
|
impl PhysPageNum {
|
||||||
pub fn get_pte_array(&self) -> &'static mut [PageTableEntry] {
|
pub fn get_pte_array(&self) -> &'static mut [PageTableEntry] {
|
||||||
let pa: PhysAddr = self.clone().into();
|
let pa: PhysAddr = self.clone().into();
|
||||||
@ -125,9 +132,7 @@ impl PhysPageNum {
|
|||||||
}
|
}
|
||||||
pub fn get_mut<T>(&self) -> &'static mut T {
|
pub fn get_mut<T>(&self) -> &'static mut T {
|
||||||
let pa: PhysAddr = self.clone().into();
|
let pa: PhysAddr = self.clone().into();
|
||||||
unsafe {
|
pa.get_mut()
|
||||||
(pa.0 as *mut T).as_mut().unwrap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ impl MemorySet {
|
|||||||
areas: Vec::new(),
|
areas: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(unused)]
|
||||||
pub fn dealloc_all_frames(&mut self) {
|
pub fn dealloc_all_frames(&mut self) {
|
||||||
*self = Self::new_bare();
|
*self = Self::new_bare();
|
||||||
}
|
}
|
||||||
@ -68,7 +69,6 @@ impl MemorySet {
|
|||||||
area.unmap(&mut self.page_table);
|
area.unmap(&mut self.page_table);
|
||||||
self.areas.remove(idx);
|
self.areas.remove(idx);
|
||||||
}
|
}
|
||||||
panic!("Area not found!");
|
|
||||||
}
|
}
|
||||||
fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
|
fn push(&mut self, mut map_area: MapArea, data: Option<&[u8]>) {
|
||||||
map_area.map(&mut self.page_table);
|
map_area.map(&mut self.page_table);
|
||||||
@ -189,6 +189,23 @@ impl MemorySet {
|
|||||||
), None);
|
), None);
|
||||||
(memory_set, user_stack_top, elf.header.pt2.entry_point() as usize)
|
(memory_set, user_stack_top, elf.header.pt2.entry_point() as usize)
|
||||||
}
|
}
|
||||||
|
pub fn from_existed_user(user_space: &MemorySet) -> MemorySet {
|
||||||
|
let mut memory_set = Self::new_bare();
|
||||||
|
// map trampoline
|
||||||
|
memory_set.map_trampoline();
|
||||||
|
// copy data sections/trap_context/user_stack
|
||||||
|
for area in user_space.areas.iter() {
|
||||||
|
let new_area = MapArea::from_another(area);
|
||||||
|
memory_set.push(new_area, None);
|
||||||
|
// copy data from another space
|
||||||
|
for vpn in area.vpn_range {
|
||||||
|
let src_ppn = user_space.translate(vpn).unwrap().ppn();
|
||||||
|
let dst_ppn = memory_set.translate(vpn).unwrap().ppn();
|
||||||
|
dst_ppn.get_bytes_array().copy_from_slice(src_ppn.get_bytes_array());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memory_set
|
||||||
|
}
|
||||||
pub fn activate(&self) {
|
pub fn activate(&self) {
|
||||||
let satp = self.page_table.token();
|
let satp = self.page_table.token();
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -199,6 +216,9 @@ impl MemorySet {
|
|||||||
pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
|
pub fn translate(&self, vpn: VirtPageNum) -> Option<PageTableEntry> {
|
||||||
self.page_table.translate(vpn)
|
self.page_table.translate(vpn)
|
||||||
}
|
}
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
*self = Self::new_bare();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MapArea {
|
pub struct MapArea {
|
||||||
@ -224,6 +244,14 @@ impl MapArea {
|
|||||||
map_perm,
|
map_perm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn from_another(another: &MapArea) -> Self {
|
||||||
|
Self {
|
||||||
|
vpn_range: VPNRange::new(another.vpn_range.get_start(), another.vpn_range.get_end()),
|
||||||
|
data_frames: BTreeMap::new(),
|
||||||
|
map_type: another.map_type,
|
||||||
|
map_perm: another.map_perm,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn map_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
|
pub fn map_one(&mut self, page_table: &mut PageTable, vpn: VirtPageNum) {
|
||||||
let ppn: PhysPageNum;
|
let ppn: PhysPageNum;
|
||||||
match self.map_type {
|
match self.map_type {
|
||||||
|
@ -8,7 +8,12 @@ use page_table::{PageTable, PTEFlags};
|
|||||||
use address::{VPNRange, StepByOne};
|
use address::{VPNRange, StepByOne};
|
||||||
pub use address::{PhysAddr, VirtAddr, PhysPageNum, VirtPageNum};
|
pub use address::{PhysAddr, VirtAddr, PhysPageNum, VirtPageNum};
|
||||||
pub use frame_allocator::{FrameTracker, frame_alloc};
|
pub use frame_allocator::{FrameTracker, frame_alloc};
|
||||||
pub use page_table::{PageTableEntry, translated_byte_buffer};
|
pub use page_table::{
|
||||||
|
PageTableEntry,
|
||||||
|
translated_byte_buffer,
|
||||||
|
translated_str,
|
||||||
|
translated_refmut,
|
||||||
|
};
|
||||||
pub use memory_set::{MemorySet, KERNEL_SPACE, MapPermission};
|
pub use memory_set::{MemorySet, KERNEL_SPACE, MapPermission};
|
||||||
pub use memory_set::remap_test;
|
pub use memory_set::remap_test;
|
||||||
|
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
use super::{frame_alloc, PhysPageNum, FrameTracker, VirtPageNum, VirtAddr, StepByOne};
|
use super::{
|
||||||
|
frame_alloc,
|
||||||
|
PhysPageNum,
|
||||||
|
FrameTracker,
|
||||||
|
VirtPageNum,
|
||||||
|
VirtAddr,
|
||||||
|
PhysAddr,
|
||||||
|
StepByOne
|
||||||
|
};
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
|
use alloc::string::String;
|
||||||
use bitflags::*;
|
use bitflags::*;
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
@ -126,6 +135,17 @@ impl PageTable {
|
|||||||
self.find_pte(vpn)
|
self.find_pte(vpn)
|
||||||
.map(|pte| {pte.clone()})
|
.map(|pte| {pte.clone()})
|
||||||
}
|
}
|
||||||
|
pub fn translate_va(&self, va: VirtAddr) -> Option<PhysAddr> {
|
||||||
|
self.find_pte(va.clone().floor())
|
||||||
|
.map(|pte| {
|
||||||
|
//println!("translate_va:va = {:?}", va);
|
||||||
|
let aligned_pa: PhysAddr = pte.ppn().into();
|
||||||
|
//println!("translate_va:pa_align = {:?}", aligned_pa);
|
||||||
|
let offset = va.page_offset();
|
||||||
|
let aligned_pa_usize: usize = aligned_pa.into();
|
||||||
|
(aligned_pa_usize + offset).into()
|
||||||
|
})
|
||||||
|
}
|
||||||
pub fn token(&self) -> usize {
|
pub fn token(&self) -> usize {
|
||||||
8usize << 60 | self.root_ppn.0
|
8usize << 60 | self.root_ppn.0
|
||||||
}
|
}
|
||||||
@ -151,3 +171,27 @@ pub fn translated_byte_buffer(token: usize, ptr: *const u8, len: usize) -> Vec<&
|
|||||||
}
|
}
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn translated_str(token: usize, ptr: *const u8) -> String {
|
||||||
|
let page_table = PageTable::from_token(token);
|
||||||
|
let mut string = String::new();
|
||||||
|
let mut va = ptr as usize;
|
||||||
|
loop {
|
||||||
|
let ch: u8 = *(page_table.translate_va(VirtAddr::from(va)).unwrap().get_mut());
|
||||||
|
if ch == 0 {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
string.push(ch as char);
|
||||||
|
va += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translated_refmut<T>(token: usize, ptr: *mut T) -> &'static mut T {
|
||||||
|
//println!("into translated_refmut!");
|
||||||
|
let page_table = PageTable::from_token(token);
|
||||||
|
let va = ptr as usize;
|
||||||
|
//println!("translated_refmut: before translate_va");
|
||||||
|
page_table.translate_va(VirtAddr::from(va)).unwrap().get_mut()
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
use crate::mm::translated_byte_buffer;
|
use crate::mm::translated_byte_buffer;
|
||||||
use crate::task::{current_user_token, suspend_current_and_run_next};
|
use crate::task::{current_user_token};
|
||||||
use crate::sbi::console_getchar;
|
use crate::sbi::console_getchar;
|
||||||
|
|
||||||
const FD_STDIN: usize = 0;
|
const FD_STDIN: usize = 0;
|
||||||
@ -28,7 +28,7 @@ pub fn sys_read(fd: usize, buf: *const u8, len: usize) -> isize {
|
|||||||
loop {
|
loop {
|
||||||
c = console_getchar();
|
c = console_getchar();
|
||||||
if c == 0 {
|
if c == 0 {
|
||||||
suspend_current_and_run_next();
|
//suspend_current_and_run_next();
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -3,6 +3,10 @@ const SYSCALL_WRITE: usize = 64;
|
|||||||
const SYSCALL_EXIT: usize = 93;
|
const SYSCALL_EXIT: usize = 93;
|
||||||
const SYSCALL_YIELD: usize = 124;
|
const SYSCALL_YIELD: usize = 124;
|
||||||
const SYSCALL_GET_TIME: usize = 169;
|
const SYSCALL_GET_TIME: usize = 169;
|
||||||
|
const SYSCALL_GETPID: usize = 172;
|
||||||
|
const SYSCALL_FORK: usize = 220;
|
||||||
|
const SYSCALL_EXEC: usize = 221;
|
||||||
|
const SYSCALL_WAITPID: usize = 260;
|
||||||
|
|
||||||
mod fs;
|
mod fs;
|
||||||
mod process;
|
mod process;
|
||||||
@ -17,6 +21,10 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize {
|
|||||||
SYSCALL_EXIT => sys_exit(args[0] as i32),
|
SYSCALL_EXIT => sys_exit(args[0] as i32),
|
||||||
SYSCALL_YIELD => sys_yield(),
|
SYSCALL_YIELD => sys_yield(),
|
||||||
SYSCALL_GET_TIME => sys_get_time(),
|
SYSCALL_GET_TIME => sys_get_time(),
|
||||||
|
SYSCALL_GETPID => sys_getpid(),
|
||||||
|
SYSCALL_FORK => sys_fork(),
|
||||||
|
SYSCALL_EXEC => sys_exec(args[0] as *const u8),
|
||||||
|
SYSCALL_WAITPID => sys_waitpid(args[0] as isize, args[1] as *mut i32),
|
||||||
_ => panic!("Unsupported syscall_id: {}", syscall_id),
|
_ => panic!("Unsupported syscall_id: {}", syscall_id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,30 @@
|
|||||||
use crate::task::{
|
use crate::task::{
|
||||||
suspend_current_and_run_next,
|
suspend_current_and_run_next,
|
||||||
exit_current_and_run_next,
|
exit_current_and_run_next,
|
||||||
|
current_task,
|
||||||
|
current_user_token,
|
||||||
|
add_task,
|
||||||
};
|
};
|
||||||
use crate::timer::get_time;
|
use crate::timer::get_time;
|
||||||
|
use crate::mm::{
|
||||||
|
translated_str,
|
||||||
|
translated_refmut,
|
||||||
|
};
|
||||||
|
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);
|
||||||
|
|
||||||
pub fn sys_exit(xstate: i32) -> ! {
|
|
||||||
println!("[kernel] Application exited with code {}", xstate);
|
|
||||||
exit_current_and_run_next();
|
exit_current_and_run_next();
|
||||||
panic!("Unreachable in sys_exit!");
|
panic!("Unreachable in sys_exit!");
|
||||||
}
|
}
|
||||||
@ -18,3 +37,59 @@ pub fn sys_yield() -> isize {
|
|||||||
pub fn sys_get_time() -> isize {
|
pub fn sys_get_time() -> isize {
|
||||||
get_time() as isize
|
get_time() as isize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sys_getpid() -> isize {
|
||||||
|
current_task().unwrap().pid.0 as isize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_fork() -> isize {
|
||||||
|
let current_task = current_task().unwrap();
|
||||||
|
let new_task = current_task.fork();
|
||||||
|
let new_pid = new_task.pid.0;
|
||||||
|
// modify trap context of new_task, because it returns immediately after switching
|
||||||
|
let trap_cx = new_task.acquire_inner_lock().get_trap_cx();
|
||||||
|
// we do not have to move to next instruction since we have done it before
|
||||||
|
// for child process, fork returns 0
|
||||||
|
trap_cx.x[10] = 0;
|
||||||
|
// add new task to scheduler
|
||||||
|
add_task(new_task);
|
||||||
|
new_pid as isize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_exec(path: *const u8) -> isize {
|
||||||
|
let token = current_user_token();
|
||||||
|
let path = translated_str(token, path);
|
||||||
|
let data = get_app_data_by_name(path.as_str()).unwrap();
|
||||||
|
let task = current_task().unwrap();
|
||||||
|
task.exec(data);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
let pair = inner.children
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.find(|(_, p)| {
|
||||||
|
// ++++ temporarily hold child PCB lock
|
||||||
|
p.acquire_inner_lock().is_zombie() && (pid == -1 || pid as usize == p.getpid())
|
||||||
|
// ++++ release child PCB lock
|
||||||
|
});
|
||||||
|
if let Some((idx, _)) = pair {
|
||||||
|
let child = inner.children.remove(idx);
|
||||||
|
// confirm that child will be deallocated after removing from children list
|
||||||
|
assert_eq!(Arc::strong_count(&child), 1);
|
||||||
|
let found_pid = child.getpid();
|
||||||
|
// ++++ temporarily hold child lock
|
||||||
|
let exit_code = child.acquire_inner_lock().exit_code;
|
||||||
|
// ++++ release child PCB lock
|
||||||
|
*translated_refmut(inner.memory_set.token(), exit_code_ptr) = exit_code;
|
||||||
|
found_pid as isize
|
||||||
|
} else {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
// ---- release current PCB lock automatically
|
||||||
|
}
|
@ -5,7 +5,7 @@ use spin::Mutex;
|
|||||||
use lazy_static::*;
|
use lazy_static::*;
|
||||||
|
|
||||||
pub struct TaskManager {
|
pub struct TaskManager {
|
||||||
ready_queue: VecDeque<Arc<Mutex<TaskControlBlock>>>,
|
ready_queue: VecDeque<Arc<TaskControlBlock>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A simple FIFO scheduler.
|
/// A simple FIFO scheduler.
|
||||||
@ -13,10 +13,10 @@ impl TaskManager {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { ready_queue: VecDeque::new(), }
|
Self { ready_queue: VecDeque::new(), }
|
||||||
}
|
}
|
||||||
pub fn add(&mut self, task: Arc<Mutex<TaskControlBlock>>) {
|
pub fn add(&mut self, task: Arc<TaskControlBlock>) {
|
||||||
self.ready_queue.push_back(task);
|
self.ready_queue.push_back(task);
|
||||||
}
|
}
|
||||||
pub fn fetch(&mut self) -> Option<Arc<Mutex<TaskControlBlock>>> {
|
pub fn fetch(&mut self) -> Option<Arc<TaskControlBlock>> {
|
||||||
self.ready_queue.pop_front()
|
self.ready_queue.pop_front()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -25,10 +25,10 @@ lazy_static! {
|
|||||||
pub static ref TASK_MANAGER: Mutex<TaskManager> = Mutex::new(TaskManager::new());
|
pub static ref TASK_MANAGER: Mutex<TaskManager> = Mutex::new(TaskManager::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_task(task: Arc<Mutex<TaskControlBlock>>) {
|
pub fn add_task(task: Arc<TaskControlBlock>) {
|
||||||
TASK_MANAGER.lock().add(task);
|
TASK_MANAGER.lock().add(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch_task() -> Option<Arc<Mutex<TaskControlBlock>>> {
|
pub fn fetch_task() -> Option<Arc<TaskControlBlock>> {
|
||||||
TASK_MANAGER.lock().fetch()
|
TASK_MANAGER.lock().fetch()
|
||||||
}
|
}
|
@ -5,17 +5,11 @@ mod manager;
|
|||||||
mod processor;
|
mod processor;
|
||||||
mod pid;
|
mod pid;
|
||||||
|
|
||||||
use crate::loader::{get_num_app, get_app_data};
|
use crate::loader::{get_app_data_by_name};
|
||||||
use crate::trap::TrapContext;
|
|
||||||
use core::cell::RefCell;
|
|
||||||
use lazy_static::*;
|
|
||||||
use switch::__switch;
|
use switch::__switch;
|
||||||
use task::{TaskControlBlock, TaskStatus};
|
use task::{TaskControlBlock, TaskStatus};
|
||||||
use alloc::vec::Vec;
|
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use spin::Mutex;
|
|
||||||
use manager::fetch_task;
|
use manager::fetch_task;
|
||||||
use pid::{PidHandle, pid_alloc, KernelStack};
|
|
||||||
|
|
||||||
pub use context::TaskContext;
|
pub use context::TaskContext;
|
||||||
pub use processor::{
|
pub use processor::{
|
||||||
@ -27,13 +21,21 @@ pub use processor::{
|
|||||||
schedule,
|
schedule,
|
||||||
};
|
};
|
||||||
pub use manager::add_task;
|
pub use manager::add_task;
|
||||||
|
pub use pid::{PidHandle, pid_alloc, KernelStack};
|
||||||
|
|
||||||
pub fn suspend_current_and_run_next() {
|
pub fn suspend_current_and_run_next() {
|
||||||
// There must be an application running.
|
// There must be an application running.
|
||||||
let task = current_task().unwrap();
|
let task = take_current_task().unwrap();
|
||||||
let task_cx_ptr = task.lock().get_task_cx_ptr2();
|
|
||||||
// Change status to Ready.
|
// ---- temporarily hold current PCB lock
|
||||||
task.lock().task_status = TaskStatus::Ready;
|
let task_cx_ptr = task.acquire_inner_lock().get_task_cx_ptr2();
|
||||||
|
// ---- release current PCB lock
|
||||||
|
|
||||||
|
// ++++ temporarily hold current PCB lock
|
||||||
|
// Change status to Ready
|
||||||
|
task.acquire_inner_lock().task_status = TaskStatus::Ready;
|
||||||
|
// ++++ release current PCB lock
|
||||||
|
|
||||||
// push back to ready queue.
|
// push back to ready queue.
|
||||||
add_task(task);
|
add_task(task);
|
||||||
// jump to scheduling cycle
|
// jump to scheduling cycle
|
||||||
@ -41,10 +43,37 @@ pub fn suspend_current_and_run_next() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit_current_and_run_next() {
|
pub fn exit_current_and_run_next() {
|
||||||
// The resource recycle mechanism needs child processes. Now we just panic!
|
// take from Processor
|
||||||
panic!("An application exited!");
|
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;
|
||||||
|
// move any child to its parent
|
||||||
|
|
||||||
|
// ++++++ hold parent PCB lock here
|
||||||
|
{
|
||||||
|
let parent = inner.parent.as_ref().unwrap().upgrade().unwrap();
|
||||||
|
let mut parent_inner = parent.acquire_inner_lock();
|
||||||
|
for child in inner.children.iter() {
|
||||||
|
parent_inner.children.push(child.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ++++++ release parent PCB lock here
|
||||||
|
|
||||||
|
inner.children.clear();
|
||||||
|
// deallocate user space
|
||||||
|
inner.memory_set.clear();
|
||||||
|
drop(inner);
|
||||||
|
// **** release current PCB lock
|
||||||
|
// drop task manually to maintain rc correctly
|
||||||
|
drop(task);
|
||||||
|
// we do not have to save task context
|
||||||
|
let _unused: usize = 0;
|
||||||
|
schedule(&_unused as *const _);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_application(elf_data: &[u8], app_id: usize) {
|
pub fn add_initproc() {
|
||||||
add_task(Arc::new(Mutex::new(TaskControlBlock::new(elf_data, app_id))));
|
let data = get_app_data_by_name("initproc").unwrap();
|
||||||
|
add_task(Arc::new(TaskControlBlock::new(data)));
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ pub struct PidHandle(pub usize);
|
|||||||
|
|
||||||
impl Drop for PidHandle {
|
impl Drop for PidHandle {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
//println!("drop pid {}", self.0);
|
||||||
PID_ALLOCATOR.lock().dealloc(self.0);
|
PID_ALLOCATOR.lock().dealloc(self.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,7 +83,7 @@ impl KernelStack {
|
|||||||
}
|
}
|
||||||
pub fn push_on_top<T>(&self, value: T) -> *mut T where
|
pub fn push_on_top<T>(&self, value: T) -> *mut T where
|
||||||
T: Sized, {
|
T: Sized, {
|
||||||
let (_, kernel_stack_top) = kernel_stack_position(self.pid);
|
let kernel_stack_top = self.get_top();
|
||||||
let ptr_mut = (kernel_stack_top - core::mem::size_of::<T>()) as *mut T;
|
let ptr_mut = (kernel_stack_top - core::mem::size_of::<T>()) as *mut T;
|
||||||
unsafe { *ptr_mut = value; }
|
unsafe { *ptr_mut = value; }
|
||||||
ptr_mut
|
ptr_mut
|
||||||
|
@ -2,7 +2,7 @@ use super::TaskControlBlock;
|
|||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use lazy_static::*;
|
use lazy_static::*;
|
||||||
use super::{add_task, fetch_task};
|
use super::{fetch_task, TaskStatus};
|
||||||
use super::__switch;
|
use super::__switch;
|
||||||
use crate::trap::TrapContext;
|
use crate::trap::TrapContext;
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ pub struct Processor {
|
|||||||
unsafe impl Sync for Processor {}
|
unsafe impl Sync for Processor {}
|
||||||
|
|
||||||
struct ProcessorInner {
|
struct ProcessorInner {
|
||||||
current: Option<Arc<Mutex<TaskControlBlock>>>,
|
current: Option<Arc<TaskControlBlock>>,
|
||||||
idle_task_cx_ptr: usize,
|
idle_task_cx_ptr: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,13 +31,13 @@ impl Processor {
|
|||||||
&inner.idle_task_cx_ptr as *const usize
|
&inner.idle_task_cx_ptr as *const usize
|
||||||
}
|
}
|
||||||
pub fn run(&self) {
|
pub fn run(&self) {
|
||||||
//println!("into Processor::run");
|
|
||||||
loop {
|
loop {
|
||||||
if let Some(task) = fetch_task() {
|
if let Some(task) = fetch_task() {
|
||||||
//println!("found task!");
|
|
||||||
let idle_task_cx_ptr = self.get_idle_task_cx_ptr2();
|
let idle_task_cx_ptr = self.get_idle_task_cx_ptr2();
|
||||||
let next_task_cx_ptr = task.lock().get_task_cx_ptr2();
|
// acquire
|
||||||
//println!("next_task_cx_ptr={:p}", next_task_cx_ptr);
|
let next_task_cx_ptr = task.acquire_inner_lock().get_task_cx_ptr2();
|
||||||
|
task.acquire_inner_lock().task_status = TaskStatus::Running;
|
||||||
|
// release
|
||||||
self.inner.lock().current = Some(task);
|
self.inner.lock().current = Some(task);
|
||||||
unsafe {
|
unsafe {
|
||||||
__switch(
|
__switch(
|
||||||
@ -48,10 +48,10 @@ impl Processor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn take_current(&self) -> Option<Arc<Mutex<TaskControlBlock>>> {
|
pub fn take_current(&self) -> Option<Arc<TaskControlBlock>> {
|
||||||
self.inner.lock().current.take()
|
self.inner.lock().current.take()
|
||||||
}
|
}
|
||||||
pub fn current(&self) -> Option<Arc<Mutex<TaskControlBlock>>> {
|
pub fn current(&self) -> Option<Arc<TaskControlBlock>> {
|
||||||
self.inner.lock().current.as_ref().map(|task| task.clone())
|
self.inner.lock().current.as_ref().map(|task| task.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,25 +64,22 @@ pub fn run_tasks() {
|
|||||||
PROCESSOR.run();
|
PROCESSOR.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take_current_task() -> Option<Arc<Mutex<TaskControlBlock>>> {
|
pub fn take_current_task() -> Option<Arc<TaskControlBlock>> {
|
||||||
PROCESSOR.take_current()
|
PROCESSOR.take_current()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_task() -> Option<Arc<Mutex<TaskControlBlock>>> {
|
pub fn current_task() -> Option<Arc<TaskControlBlock>> {
|
||||||
//println!("into current_task!");
|
|
||||||
PROCESSOR.current()
|
PROCESSOR.current()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_user_token() -> usize {
|
pub fn current_user_token() -> usize {
|
||||||
//println!("into current_user_token!");
|
|
||||||
let task = current_task().unwrap();
|
let task = current_task().unwrap();
|
||||||
//println!("Got task in current_user_token!");
|
let token = task.acquire_inner_lock().get_user_token();
|
||||||
let token = task.lock().get_user_token();
|
|
||||||
token
|
token
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_trap_cx() -> &'static mut TrapContext {
|
pub fn current_trap_cx() -> &'static mut TrapContext {
|
||||||
current_task().unwrap().as_ref().lock().get_trap_cx()
|
current_task().unwrap().acquire_inner_lock().get_trap_cx()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn schedule(switched_task_cx_ptr2: *const usize) {
|
pub fn schedule(switched_task_cx_ptr2: *const usize) {
|
||||||
|
@ -1,22 +1,32 @@
|
|||||||
use crate::mm::{MemorySet, MapPermission, PhysPageNum, KERNEL_SPACE, VirtAddr};
|
use crate::mm::{MemorySet, PhysPageNum, KERNEL_SPACE, VirtAddr};
|
||||||
use crate::trap::{TrapContext, trap_handler};
|
use crate::trap::{TrapContext, trap_handler};
|
||||||
use crate::config::{TRAP_CONTEXT, kernel_stack_position};
|
use crate::config::{TRAP_CONTEXT};
|
||||||
use super::TaskContext;
|
use super::TaskContext;
|
||||||
use super::{PidHandle, pid_alloc, KernelStack};
|
use super::{PidHandle, pid_alloc, KernelStack};
|
||||||
|
use alloc::sync::{Weak, Arc};
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use spin::{Mutex, MutexGuard};
|
||||||
|
|
||||||
pub struct TaskControlBlock {
|
pub struct TaskControlBlock {
|
||||||
// immutable
|
// immutable
|
||||||
pub trap_cx_ppn: PhysPageNum,
|
|
||||||
pub base_size: usize,
|
|
||||||
pub pid: PidHandle,
|
pub pid: PidHandle,
|
||||||
pub kernel_stack: KernelStack,
|
pub kernel_stack: KernelStack,
|
||||||
// mutable
|
// mutable
|
||||||
|
inner: Mutex<TaskControlBlockInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TaskControlBlockInner {
|
||||||
|
pub trap_cx_ppn: PhysPageNum,
|
||||||
|
pub base_size: usize,
|
||||||
pub task_cx_ptr: usize,
|
pub task_cx_ptr: usize,
|
||||||
pub task_status: TaskStatus,
|
pub task_status: TaskStatus,
|
||||||
pub memory_set: MemorySet,
|
pub memory_set: MemorySet,
|
||||||
|
pub parent: Option<Weak<TaskControlBlock>>,
|
||||||
|
pub children: Vec<Arc<TaskControlBlock>>,
|
||||||
|
pub exit_code: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaskControlBlock {
|
impl TaskControlBlockInner {
|
||||||
pub fn get_task_cx_ptr2(&self) -> *const usize {
|
pub fn get_task_cx_ptr2(&self) -> *const usize {
|
||||||
&self.task_cx_ptr as *const usize
|
&self.task_cx_ptr as *const usize
|
||||||
}
|
}
|
||||||
@ -26,7 +36,19 @@ impl TaskControlBlock {
|
|||||||
pub fn get_user_token(&self) -> usize {
|
pub fn get_user_token(&self) -> usize {
|
||||||
self.memory_set.token()
|
self.memory_set.token()
|
||||||
}
|
}
|
||||||
pub fn new(elf_data: &[u8], app_id: usize) -> Self {
|
fn get_status(&self) -> TaskStatus {
|
||||||
|
self.task_status
|
||||||
|
}
|
||||||
|
pub fn is_zombie(&self) -> bool {
|
||||||
|
self.get_status() == TaskStatus::Zombie
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TaskControlBlock {
|
||||||
|
pub fn acquire_inner_lock(&self) -> MutexGuard<TaskControlBlockInner> {
|
||||||
|
self.inner.lock()
|
||||||
|
}
|
||||||
|
pub fn new(elf_data: &[u8]) -> Self {
|
||||||
// memory_set with elf program headers/trampoline/trap context/user stack
|
// memory_set with elf program headers/trampoline/trap context/user stack
|
||||||
let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data);
|
let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data);
|
||||||
let trap_cx_ppn = memory_set
|
let trap_cx_ppn = memory_set
|
||||||
@ -41,16 +63,23 @@ impl TaskControlBlock {
|
|||||||
// push a task context which goes to trap_return to the top of kernel stack
|
// push a task context which goes to trap_return to the top of kernel stack
|
||||||
let task_cx_ptr = kernel_stack.push_on_top(TaskContext::goto_trap_return());
|
let task_cx_ptr = kernel_stack.push_on_top(TaskContext::goto_trap_return());
|
||||||
let task_control_block = Self {
|
let task_control_block = Self {
|
||||||
trap_cx_ppn,
|
|
||||||
base_size: user_sp,
|
|
||||||
pid: pid_handle,
|
pid: pid_handle,
|
||||||
kernel_stack,
|
kernel_stack,
|
||||||
|
inner: Mutex::new(TaskControlBlockInner {
|
||||||
|
trap_cx_ppn,
|
||||||
|
base_size: user_sp,
|
||||||
task_cx_ptr: task_cx_ptr as usize,
|
task_cx_ptr: task_cx_ptr as usize,
|
||||||
task_status,
|
task_status,
|
||||||
memory_set,
|
memory_set,
|
||||||
|
parent: None,
|
||||||
|
children: Vec::new(),
|
||||||
|
exit_code: 0,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
// prepare TrapContext in user space
|
// prepare TrapContext in user space
|
||||||
let trap_cx = task_control_block.get_trap_cx();
|
// ---- acquire child PCB lock
|
||||||
|
let trap_cx = task_control_block.acquire_inner_lock().get_trap_cx();
|
||||||
|
// ---- release child PCB lock
|
||||||
*trap_cx = TrapContext::app_init_context(
|
*trap_cx = TrapContext::app_init_context(
|
||||||
entry_point,
|
entry_point,
|
||||||
user_sp,
|
user_sp,
|
||||||
@ -60,12 +89,86 @@ impl TaskControlBlock {
|
|||||||
);
|
);
|
||||||
task_control_block
|
task_control_block
|
||||||
}
|
}
|
||||||
|
pub fn exec(&self, elf_data: &[u8]) {
|
||||||
|
// memory_set with elf program headers/trampoline/trap context/user stack
|
||||||
|
let (memory_set, user_sp, entry_point) = MemorySet::from_elf(elf_data);
|
||||||
|
let trap_cx_ppn = memory_set
|
||||||
|
.translate(VirtAddr::from(TRAP_CONTEXT).into())
|
||||||
|
.unwrap()
|
||||||
|
.ppn();
|
||||||
|
|
||||||
|
// **** hold current PCB lock
|
||||||
|
let mut inner = self.inner.lock();
|
||||||
|
// substitute memory_set
|
||||||
|
inner.memory_set = memory_set;
|
||||||
|
// update trap_cx ppn
|
||||||
|
inner.trap_cx_ppn = trap_cx_ppn;
|
||||||
|
drop(inner);
|
||||||
|
// **** release current PCB lock manually
|
||||||
|
|
||||||
|
// initialize trap_cx
|
||||||
|
// **** acquire current PCB lock
|
||||||
|
let trap_cx = self.acquire_inner_lock().get_trap_cx();
|
||||||
|
// **** release current PCB lock
|
||||||
|
*trap_cx = TrapContext::app_init_context(
|
||||||
|
entry_point,
|
||||||
|
user_sp,
|
||||||
|
KERNEL_SPACE.lock().token(),
|
||||||
|
self.kernel_stack.get_top(),
|
||||||
|
trap_handler as usize,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pub fn fork(self: &Arc<TaskControlBlock>) -> Arc<TaskControlBlock> {
|
||||||
|
// ---- hold parent PCB lock
|
||||||
|
let mut parent_inner = self.inner.lock();
|
||||||
|
// copy user space(include trap context)
|
||||||
|
let memory_set = MemorySet::from_existed_user(
|
||||||
|
&parent_inner.memory_set
|
||||||
|
);
|
||||||
|
let trap_cx_ppn = memory_set
|
||||||
|
.translate(VirtAddr::from(TRAP_CONTEXT).into())
|
||||||
|
.unwrap()
|
||||||
|
.ppn();
|
||||||
|
let task_status = TaskStatus::Ready;
|
||||||
|
// alloc a pid and a kernel stack in kernel space
|
||||||
|
let pid_handle = pid_alloc();
|
||||||
|
let kernel_stack = KernelStack::new(&pid_handle);
|
||||||
|
let kernel_stack_top = kernel_stack.get_top();
|
||||||
|
// push a goto_trap_return task_cx on the top of kernel stack
|
||||||
|
let task_cx_ptr = kernel_stack.push_on_top(TaskContext::goto_trap_return());
|
||||||
|
let task_control_block = Arc::new(TaskControlBlock {
|
||||||
|
pid: pid_handle,
|
||||||
|
kernel_stack,
|
||||||
|
inner: Mutex::new(TaskControlBlockInner {
|
||||||
|
trap_cx_ppn,
|
||||||
|
base_size: parent_inner.base_size,
|
||||||
|
task_cx_ptr: task_cx_ptr as usize,
|
||||||
|
task_status,
|
||||||
|
memory_set,
|
||||||
|
parent: Some(Arc::downgrade(self)),
|
||||||
|
children: Vec::new(),
|
||||||
|
exit_code: 0,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
// add child
|
||||||
|
parent_inner.children.push(task_control_block.clone());
|
||||||
|
// modify kernel_sp in trap_cx
|
||||||
|
// **** acquire child PCB lock
|
||||||
|
let trap_cx = task_control_block.acquire_inner_lock().get_trap_cx();
|
||||||
|
// **** release child PCB lock
|
||||||
|
trap_cx.kernel_sp = kernel_stack_top;
|
||||||
|
// return
|
||||||
|
task_control_block
|
||||||
|
// ---- release parent PCB lock
|
||||||
|
}
|
||||||
|
pub fn getpid(&self) -> usize {
|
||||||
|
self.pid.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum TaskStatus {
|
pub enum TaskStatus {
|
||||||
Ready,
|
Ready,
|
||||||
Running,
|
Running,
|
||||||
Exited,
|
|
||||||
Zombie,
|
Zombie,
|
||||||
}
|
}
|
@ -20,7 +20,9 @@ impl TrapContext {
|
|||||||
trap_handler: usize,
|
trap_handler: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut sstatus = sstatus::read();
|
let mut sstatus = sstatus::read();
|
||||||
|
// set CPU privilege to User after trapping back
|
||||||
sstatus.set_spp(SPP::User);
|
sstatus.set_spp(SPP::User);
|
||||||
|
// enable Supervisor mode interrupt after trapping back
|
||||||
sstatus.set_spie(true);
|
sstatus.set_spie(true);
|
||||||
let mut cx = Self {
|
let mut cx = Self {
|
||||||
x: [0; 32],
|
x: [0; 32],
|
||||||
|
@ -53,17 +53,22 @@ pub fn enable_timer_interrupt() {
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn trap_handler() -> ! {
|
pub fn trap_handler() -> ! {
|
||||||
set_kernel_trap_entry();
|
set_kernel_trap_entry();
|
||||||
let cx = current_trap_cx();
|
|
||||||
let scause = scause::read();
|
let scause = scause::read();
|
||||||
let stval = stval::read();
|
let stval = stval::read();
|
||||||
match scause.cause() {
|
match scause.cause() {
|
||||||
Trap::Exception(Exception::UserEnvCall) => {
|
Trap::Exception(Exception::UserEnvCall) => {
|
||||||
|
// jump to next instruction anyway
|
||||||
|
let mut cx = current_trap_cx();
|
||||||
cx.sepc += 4;
|
cx.sepc += 4;
|
||||||
cx.x[10] = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]) as usize;
|
// get system call return value
|
||||||
|
let result = syscall(cx.x[17], [cx.x[10], cx.x[11], cx.x[12]]);
|
||||||
|
// cx is changed during sys_exec, so we have to call it again
|
||||||
|
cx = current_trap_cx();
|
||||||
|
cx.x[10] = result as usize;
|
||||||
}
|
}
|
||||||
Trap::Exception(Exception::StoreFault) |
|
Trap::Exception(Exception::StoreFault) |
|
||||||
Trap::Exception(Exception::StorePageFault) => {
|
Trap::Exception(Exception::StorePageFault) => {
|
||||||
println!("[kernel] PageFault in application, bad addr = {:#x}, bad instruction = {:#x}, core dumped.", stval, cx.sepc);
|
println!("[kernel] PageFault in application, bad addr = {:#x}, bad instruction = {:#x}, core dumped.", stval, current_trap_cx().sepc);
|
||||||
exit_current_and_run_next();
|
exit_current_and_run_next();
|
||||||
}
|
}
|
||||||
Trap::Exception(Exception::IllegalInstruction) => {
|
Trap::Exception(Exception::IllegalInstruction) => {
|
||||||
@ -83,7 +88,6 @@ pub fn trap_handler() -> ! {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn trap_return() -> ! {
|
pub fn trap_return() -> ! {
|
||||||
//println!("into trap_return!");
|
|
||||||
set_user_trap_entry();
|
set_user_trap_entry();
|
||||||
let trap_cx_ptr = TRAP_CONTEXT;
|
let trap_cx_ptr = TRAP_CONTEXT;
|
||||||
let user_satp = current_user_token();
|
let user_satp = current_user_token();
|
||||||
@ -92,7 +96,6 @@ pub fn trap_return() -> ! {
|
|||||||
fn __restore();
|
fn __restore();
|
||||||
}
|
}
|
||||||
let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE;
|
let restore_va = __restore as usize - __alltraps as usize + TRAMPOLINE;
|
||||||
//println!("before jr!");
|
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("jr $0" :: "r"(restore_va), "{a0}"(trap_cx_ptr), "{a1}"(user_satp) :: "volatile");
|
llvm_asm!("jr $0" :: "r"(restore_va), "{a0}"(trap_cx_ptr), "{a1}"(user_satp) :: "volatile");
|
||||||
}
|
}
|
||||||
@ -101,7 +104,7 @@ pub fn trap_return() -> ! {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn trap_from_kernel() -> ! {
|
pub fn trap_from_kernel() -> ! {
|
||||||
panic!("a trap from kernel!");
|
panic!("a trap {:?} from kernel!", scause::read().cause());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use context::{TrapContext};
|
pub use context::{TrapContext};
|
||||||
|
@ -12,7 +12,7 @@ const DL: u8 = 0x7fu8;
|
|||||||
const BS: u8 = 0x08u8;
|
const BS: u8 = 0x08u8;
|
||||||
|
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use user_lib::{fork, exec, wait};
|
use user_lib::{fork, exec, waitpid, yield_};
|
||||||
use user_lib::console::getchar;
|
use user_lib::console::getchar;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@ -37,8 +37,17 @@ pub fn main() -> i32 {
|
|||||||
unreachable!();
|
unreachable!();
|
||||||
} else {
|
} else {
|
||||||
let mut xstate: i32 = 0;
|
let mut xstate: i32 = 0;
|
||||||
wait(&mut xstate);
|
let mut exit_pid: isize = 0;
|
||||||
|
loop {
|
||||||
|
exit_pid = waitpid(pid as usize, &mut xstate);
|
||||||
|
if exit_pid == -1 {
|
||||||
|
yield_();
|
||||||
|
} else {
|
||||||
|
assert_eq!(pid, exit_pid);
|
||||||
println!("Shell: Process {} exited with code {}", pid, xstate);
|
println!("Shell: Process {} exited with code {}", pid, xstate);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
line.clear();
|
line.clear();
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ fn main() -> i32 {
|
|||||||
|
|
||||||
pub fn read(fd: usize, buf: &mut [u8]) -> isize { sys_read(fd, buf) }
|
pub fn read(fd: usize, buf: &mut [u8]) -> isize { sys_read(fd, buf) }
|
||||||
pub fn write(fd: usize, buf: &[u8]) -> isize { sys_write(fd, buf) }
|
pub fn write(fd: usize, buf: &[u8]) -> isize { sys_write(fd, buf) }
|
||||||
pub fn exit(xstate: i32) -> ! { sys_exit(xstate); }
|
pub fn exit(exit_code: i32) -> ! { sys_exit(exit_code); }
|
||||||
pub fn yield_() -> isize { sys_yield() }
|
pub fn yield_() -> isize { sys_yield() }
|
||||||
pub fn get_time() -> isize { sys_get_time() }
|
pub fn get_time() -> isize { sys_get_time() }
|
||||||
pub fn getpid() -> isize { sys_getpid() }
|
pub fn getpid() -> isize { sys_getpid() }
|
||||||
|
@ -29,8 +29,8 @@ pub fn sys_write(fd: usize, buffer: &[u8]) -> isize {
|
|||||||
syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()])
|
syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sys_exit(xstate: i32) -> ! {
|
pub fn sys_exit(exit_code: i32) -> ! {
|
||||||
syscall(SYSCALL_EXIT, [xstate as usize, 0, 0]);
|
syscall(SYSCALL_EXIT, [exit_code as usize, 0, 0]);
|
||||||
panic!("sys_exit never returns!");
|
panic!("sys_exit never returns!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user