Support signal mechanism for ch8(only works on signal-thread apps)

This commit is contained in:
Yifan Wu 2022-01-23 13:14:56 -08:00
parent 29d6d26644
commit 6f09af2c0f
17 changed files with 235 additions and 17 deletions

View File

@ -7,6 +7,7 @@ const SYSCALL_WRITE: usize = 64;
const SYSCALL_EXIT: usize = 93; const SYSCALL_EXIT: usize = 93;
const SYSCALL_SLEEP: usize = 101; const SYSCALL_SLEEP: usize = 101;
const SYSCALL_YIELD: usize = 124; const SYSCALL_YIELD: usize = 124;
const SYSCALL_KILL: usize = 129;
const SYSCALL_GET_TIME: usize = 169; const SYSCALL_GET_TIME: usize = 169;
const SYSCALL_GETPID: usize = 172; const SYSCALL_GETPID: usize = 172;
const SYSCALL_FORK: usize = 220; const SYSCALL_FORK: usize = 220;
@ -46,6 +47,7 @@ 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_SLEEP => sys_sleep(args[0]), SYSCALL_SLEEP => sys_sleep(args[0]),
SYSCALL_YIELD => sys_yield(), SYSCALL_YIELD => sys_yield(),
SYSCALL_KILL => sys_kill(args[0], args[1] as u32),
SYSCALL_GET_TIME => sys_get_time(), SYSCALL_GET_TIME => sys_get_time(),
SYSCALL_GETPID => sys_getpid(), SYSCALL_GETPID => sys_getpid(),
SYSCALL_FORK => sys_fork(), SYSCALL_FORK => sys_fork(),

View File

@ -1,8 +1,8 @@
use crate::fs::{open_file, OpenFlags}; use crate::fs::{open_file, OpenFlags};
use crate::mm::{translated_ref, translated_refmut, translated_str}; use crate::mm::{translated_ref, translated_refmut, translated_str};
use crate::task::{ use crate::task::{
current_process, current_task, current_user_token, exit_current_and_run_next, current_process, current_task, current_user_token, exit_current_and_run_next, pid2process,
suspend_current_and_run_next, suspend_current_and_run_next, SignalFlags,
}; };
use crate::timer::get_time_ms; use crate::timer::get_time_ms;
use alloc::string::String; use alloc::string::String;
@ -103,3 +103,16 @@ pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize {
} }
// ---- release current PCB automatically // ---- release current PCB automatically
} }
pub fn sys_kill(pid: usize, signal: u32) -> isize {
if let Some(process) = pid2process(pid) {
if let Some(flag) = SignalFlags::from_bits(signal) {
process.inner_exclusive_access().signals |= flag;
0
} else {
-1
}
} else {
-1
}
}

View File

@ -1,6 +1,6 @@
use super::TaskControlBlock; use super::{ProcessControlBlock, TaskControlBlock};
use crate::sync::UPSafeCell; use crate::sync::UPSafeCell;
use alloc::collections::VecDeque; use alloc::collections::{BTreeMap, VecDeque};
use alloc::sync::Arc; use alloc::sync::Arc;
use lazy_static::*; use lazy_static::*;
@ -26,6 +26,8 @@ impl TaskManager {
lazy_static! { lazy_static! {
pub static ref TASK_MANAGER: UPSafeCell<TaskManager> = pub static ref TASK_MANAGER: UPSafeCell<TaskManager> =
unsafe { UPSafeCell::new(TaskManager::new()) }; unsafe { UPSafeCell::new(TaskManager::new()) };
pub static ref PID2PCB: UPSafeCell<BTreeMap<usize, Arc<ProcessControlBlock>>> =
unsafe { UPSafeCell::new(BTreeMap::new()) };
} }
pub fn add_task(task: Arc<TaskControlBlock>) { pub fn add_task(task: Arc<TaskControlBlock>) {
@ -35,3 +37,19 @@ pub fn add_task(task: Arc<TaskControlBlock>) {
pub fn fetch_task() -> Option<Arc<TaskControlBlock>> { pub fn fetch_task() -> Option<Arc<TaskControlBlock>> {
TASK_MANAGER.exclusive_access().fetch() TASK_MANAGER.exclusive_access().fetch()
} }
pub fn pid2process(pid: usize) -> Option<Arc<ProcessControlBlock>> {
let map = PID2PCB.exclusive_access();
map.get(&pid).map(|task| Arc::clone(task))
}
pub fn insert_into_pid2process(pid: usize, process: Arc<ProcessControlBlock>) {
PID2PCB.exclusive_access().insert(pid, process);
}
pub fn remove_from_pid2process(pid: usize) {
let mut map = PID2PCB.exclusive_access();
if map.remove(&pid).is_none() {
panic!("cannot find pid {} in pid2task!", pid);
}
}

View File

@ -3,6 +3,7 @@ mod id;
mod manager; mod manager;
mod process; mod process;
mod processor; mod processor;
mod signal;
mod switch; mod switch;
mod task; mod task;
@ -15,11 +16,12 @@ use switch::__switch;
pub use context::TaskContext; pub use context::TaskContext;
pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle}; pub use id::{kstack_alloc, pid_alloc, KernelStack, PidHandle};
pub use manager::add_task; pub use manager::{add_task, pid2process, remove_from_pid2process};
pub use processor::{ pub use processor::{
current_kstack_top, current_process, current_task, current_trap_cx, current_trap_cx_user_va, current_kstack_top, current_process, current_task, current_trap_cx, current_trap_cx_user_va,
current_user_token, run_tasks, schedule, take_current_task, current_user_token, run_tasks, schedule, take_current_task,
}; };
pub use signal::SignalFlags;
pub use task::{TaskControlBlock, TaskStatus}; pub use task::{TaskControlBlock, TaskStatus};
pub fn suspend_current_and_run_next() { pub fn suspend_current_and_run_next() {
@ -64,6 +66,7 @@ pub fn exit_current_and_run_next(exit_code: i32) {
// however, if this is the main thread of current process // however, if this is the main thread of current process
// the process should terminate at once // the process should terminate at once
if tid == 0 { if tid == 0 {
remove_from_pid2process(process.getpid());
let mut process_inner = process.inner_exclusive_access(); let mut process_inner = process.inner_exclusive_access();
// mark this process as a zombie process // mark this process as a zombie process
process_inner.is_zombie = true; process_inner.is_zombie = true;
@ -111,3 +114,15 @@ lazy_static! {
pub fn add_initproc() { pub fn add_initproc() {
let _initproc = INITPROC.clone(); let _initproc = INITPROC.clone();
} }
pub fn check_signals_of_current() -> Option<(i32, &'static str)> {
let process = current_process();
let process_inner = process.inner_exclusive_access();
process_inner.signals.check_error()
}
pub fn current_add_signal(signal: SignalFlags) {
let process = current_process();
let mut process_inner = process.inner_exclusive_access();
process_inner.signals |= signal;
}

View File

@ -1,6 +1,7 @@
use super::add_task;
use super::id::RecycleAllocator; use super::id::RecycleAllocator;
use super::manager::insert_into_pid2process;
use super::TaskControlBlock; use super::TaskControlBlock;
use super::{add_task, SignalFlags};
use super::{pid_alloc, PidHandle}; use super::{pid_alloc, PidHandle};
use crate::fs::{File, Stdin, Stdout}; use crate::fs::{File, Stdin, Stdout};
use crate::mm::{translated_refmut, MemorySet, KERNEL_SPACE}; use crate::mm::{translated_refmut, MemorySet, KERNEL_SPACE};
@ -26,6 +27,7 @@ pub struct ProcessControlBlockInner {
pub children: Vec<Arc<ProcessControlBlock>>, pub children: Vec<Arc<ProcessControlBlock>>,
pub exit_code: i32, pub exit_code: i32,
pub fd_table: Vec<Option<Arc<dyn File + Send + Sync>>>, pub fd_table: Vec<Option<Arc<dyn File + Send + Sync>>>,
pub signals: SignalFlags,
pub tasks: Vec<Option<Arc<TaskControlBlock>>>, pub tasks: Vec<Option<Arc<TaskControlBlock>>>,
pub task_res_allocator: RecycleAllocator, pub task_res_allocator: RecycleAllocator,
pub mutex_list: Vec<Option<Arc<dyn Mutex>>>, pub mutex_list: Vec<Option<Arc<dyn Mutex>>>,
@ -92,6 +94,7 @@ impl ProcessControlBlock {
// 2 -> stderr // 2 -> stderr
Some(Arc::new(Stdout)), Some(Arc::new(Stdout)),
], ],
signals: SignalFlags::empty(),
tasks: Vec::new(), tasks: Vec::new(),
task_res_allocator: RecycleAllocator::new(), task_res_allocator: RecycleAllocator::new(),
mutex_list: Vec::new(), mutex_list: Vec::new(),
@ -123,6 +126,7 @@ impl ProcessControlBlock {
let mut process_inner = process.inner_exclusive_access(); let mut process_inner = process.inner_exclusive_access();
process_inner.tasks.push(Some(Arc::clone(&task))); process_inner.tasks.push(Some(Arc::clone(&task)));
drop(process_inner); drop(process_inner);
insert_into_pid2process(process.getpid(), Arc::clone(&process));
// add main thread to scheduler // add main thread to scheduler
add_task(task); add_task(task);
process process
@ -209,6 +213,7 @@ impl ProcessControlBlock {
children: Vec::new(), children: Vec::new(),
exit_code: 0, exit_code: 0,
fd_table: new_fd_table, fd_table: new_fd_table,
signals: SignalFlags::empty(),
tasks: Vec::new(), tasks: Vec::new(),
task_res_allocator: RecycleAllocator::new(), task_res_allocator: RecycleAllocator::new(),
mutex_list: Vec::new(), mutex_list: Vec::new(),
@ -242,6 +247,7 @@ impl ProcessControlBlock {
let trap_cx = task_inner.get_trap_cx(); let trap_cx = task_inner.get_trap_cx();
trap_cx.kernel_sp = task.kstack.get_top(); trap_cx.kernel_sp = task.kstack.get_top();
drop(task_inner); drop(task_inner);
insert_into_pid2process(child.getpid(), Arc::clone(&child));
// add this thread to scheduler // add this thread to scheduler
add_task(task); add_task(task);
child child

29
os/src/task/signal.rs Normal file
View File

@ -0,0 +1,29 @@
use bitflags::*;
bitflags! {
pub struct SignalFlags: u32 {
const SIGINT = 1 << 2;
const SIGILL = 1 << 4;
const SIGABRT = 1 << 6;
const SIGFPE = 1 << 8;
const SIGSEGV = 1 << 11;
}
}
impl SignalFlags {
pub fn check_error(&self) -> Option<(i32, &'static str)> {
if self.contains(Self::SIGINT) {
Some((-2, "Killed, SIGINT=2"))
} else if self.contains(Self::SIGILL) {
Some((-4, "Illegal Instruction, SIGILL=4"))
} else if self.contains(Self::SIGABRT) {
Some((-6, "Aborted, SIGABRT=6"))
} else if self.contains(Self::SIGFPE) {
Some((-8, "Erroneous Arithmetic Operation, SIGFPE=8"))
} else if self.contains(Self::SIGSEGV) {
Some((-11, "Segmentation Fault, SIGSEGV=11"))
} else {
None
}
}
}

View File

@ -3,8 +3,8 @@ mod context;
use crate::config::TRAMPOLINE; use crate::config::TRAMPOLINE;
use crate::syscall::syscall; use crate::syscall::syscall;
use crate::task::{ use crate::task::{
current_trap_cx, current_trap_cx_user_va, current_user_token, exit_current_and_run_next, check_signals_of_current, current_add_signal, current_trap_cx, current_trap_cx_user_va,
suspend_current_and_run_next, current_user_token, exit_current_and_run_next, suspend_current_and_run_next, SignalFlags,
}; };
use crate::timer::{check_timer, set_next_trigger}; use crate::timer::{check_timer, set_next_trigger};
use core::arch::{asm, global_asm}; use core::arch::{asm, global_asm};
@ -60,19 +60,18 @@ pub fn trap_handler() -> ! {
| Trap::Exception(Exception::InstructionPageFault) | Trap::Exception(Exception::InstructionPageFault)
| Trap::Exception(Exception::LoadFault) | Trap::Exception(Exception::LoadFault)
| Trap::Exception(Exception::LoadPageFault) => { | Trap::Exception(Exception::LoadPageFault) => {
/*
println!( println!(
"[kernel] {:?} in application, bad addr = {:#x}, bad instruction = {:#x}, kernel killed it.", "[kernel] {:?} in application, bad addr = {:#x}, bad instruction = {:#x}, kernel killed it.",
scause.cause(), scause.cause(),
stval, stval,
current_trap_cx().sepc, current_trap_cx().sepc,
); );
// page fault exit code */
exit_current_and_run_next(-2); current_add_signal(SignalFlags::SIGSEGV);
} }
Trap::Exception(Exception::IllegalInstruction) => { Trap::Exception(Exception::IllegalInstruction) => {
println!("[kernel] IllegalInstruction in application, kernel killed it."); current_add_signal(SignalFlags::SIGILL);
// illegal instruction exit code
exit_current_and_run_next(-3);
} }
Trap::Interrupt(Interrupt::SupervisorTimer) => { Trap::Interrupt(Interrupt::SupervisorTimer) => {
set_next_trigger(); set_next_trigger();
@ -87,6 +86,11 @@ pub fn trap_handler() -> ! {
); );
} }
} }
// check signals
if let Some((errno, msg)) = check_signals_of_current() {
println!("[kernel] {}", msg);
exit_current_and_run_next(errno);
}
trap_return(); trap_return();
} }

View File

@ -9,3 +9,4 @@ edition = "2018"
[dependencies] [dependencies]
buddy_system_allocator = "0.6" buddy_system_allocator = "0.6"
bitflags = "1.2.1" bitflags = "1.2.1"
riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }

View File

@ -15,7 +15,7 @@ pub fn main(argc: usize, argv: &[&str]) -> i32 {
panic!("Error occured when opening file"); panic!("Error occured when opening file");
} }
let fd = fd as usize; let fd = fd as usize;
let mut buf = [0u8; 16]; let mut buf = [0u8; 256];
loop { loop {
let size = read(fd, &mut buf) as usize; let size = read(fd, &mut buf) as usize;
if size == 0 { if size == 0 {

10
user/src/bin/infloop.rs Normal file
View File

@ -0,0 +1,10 @@
#![no_std]
#![no_main]
#![allow(clippy::empty_loop)]
extern crate user_lib;
#[no_mangle]
pub fn main(_argc: usize, _argv: &[&str]) -> ! {
loop {}
}

17
user/src/bin/priv_csr.rs Normal file
View File

@ -0,0 +1,17 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
use riscv::register::sstatus::{self, SPP};
#[no_mangle]
fn main() -> i32 {
println!("Try to access privileged CSR in U Mode");
println!("Kernel should kill this application!");
unsafe {
sstatus::set_spp(SPP::User);
}
0
}

17
user/src/bin/priv_inst.rs Normal file
View File

@ -0,0 +1,17 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
use core::arch::asm;
#[no_mangle]
fn main() -> i32 {
println!("Try to execute privileged instruction in U Mode");
println!("Kernel should kill this application!");
unsafe {
asm!("sret");
}
0
}

View File

@ -0,0 +1,15 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
#[no_mangle]
fn main() -> i32 {
println!("Into Test store_fault, we will insert an invalid store operation...");
println!("Kernel should kill this application!");
unsafe {
core::ptr::null_mut::<u8>().write_volatile(0);
}
0
}

View File

@ -0,0 +1,46 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
use user_lib::{exec, fork, get_time, kill, waitpid, waitpid_nb, SignalFlags};
#[no_mangle]
pub fn main(argc: usize, argv: &[&str]) -> i32 {
assert_eq!(argc, 3, "argc must be 3!");
let timeout_ms = argv[2]
.parse::<isize>()
.expect("Error when parsing timeout!");
let pid = fork() as usize;
if pid == 0 {
if exec(argv[1], &[core::ptr::null::<u8>()]) != 0 {
println!("Error when executing '{}'", argv[1]);
return -4;
}
} else {
let start_time = get_time();
let mut child_exited = false;
let mut exit_code: i32 = 0;
loop {
if get_time() - start_time > timeout_ms {
break;
}
if waitpid_nb(pid, &mut exit_code) as usize == pid {
child_exited = true;
println!(
"child exited in {}ms, exit_code = {}",
get_time() - start_time,
exit_code,
);
}
}
if !child_exited {
println!("child has run for {}ms, kill it!", timeout_ms);
kill(pid, SignalFlags::SIGINT.bits());
assert_eq!(waitpid(pid, &mut exit_code) as usize, pid);
println!("exit code of the child is {}", exit_code);
}
}
0
}

View File

@ -1,4 +1,4 @@
use super::exit; use super::{getpid, kill, SignalFlags};
#[panic_handler] #[panic_handler]
fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! { fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
@ -13,5 +13,6 @@ fn panic_handler(panic_info: &core::panic::PanicInfo) -> ! {
} else { } else {
println!("Panicked: {}", err); println!("Panicked: {}", err);
} }
exit(-1); kill(getpid() as usize, SignalFlags::SIGABRT.bits());
unreachable!()
} }

View File

@ -127,6 +127,25 @@ pub fn waitpid(pid: usize, exit_code: &mut i32) -> isize {
} }
} }
} }
pub fn waitpid_nb(pid: usize, exit_code: &mut i32) -> isize {
sys_waitpid(pid as isize, exit_code as *mut _)
}
bitflags! {
pub struct SignalFlags: i32 {
const SIGINT = 1 << 2;
const SIGILL = 1 << 4;
const SIGABRT = 1 << 6;
const SIGFPE = 1 << 8;
const SIGSEGV = 1 << 11;
}
}
pub fn kill(pid: usize, signal: i32) -> isize {
sys_kill(pid, signal)
}
pub fn sleep(sleep_ms: usize) { pub fn sleep(sleep_ms: usize) {
sys_sleep(sleep_ms); sys_sleep(sleep_ms);
} }

View File

@ -9,6 +9,7 @@ const SYSCALL_WRITE: usize = 64;
const SYSCALL_EXIT: usize = 93; const SYSCALL_EXIT: usize = 93;
const SYSCALL_SLEEP: usize = 101; const SYSCALL_SLEEP: usize = 101;
const SYSCALL_YIELD: usize = 124; const SYSCALL_YIELD: usize = 124;
const SYSCALL_KILL: usize = 129;
const SYSCALL_GET_TIME: usize = 169; const SYSCALL_GET_TIME: usize = 169;
const SYSCALL_GETPID: usize = 172; const SYSCALL_GETPID: usize = 172;
const SYSCALL_FORK: usize = 220; const SYSCALL_FORK: usize = 220;
@ -81,6 +82,10 @@ pub fn sys_yield() -> isize {
syscall(SYSCALL_YIELD, [0, 0, 0]) syscall(SYSCALL_YIELD, [0, 0, 0])
} }
pub fn sys_kill(pid: usize, signal: i32) -> isize {
syscall(SYSCALL_KILL, [pid, signal as usize, 0])
}
pub fn sys_get_time() -> isize { pub fn sys_get_time() -> isize {
syscall(SYSCALL_GET_TIME, [0, 0, 0]) syscall(SYSCALL_GET_TIME, [0, 0, 0])
} }