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 59f13cb536
commit 26bc01f3bc
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_SLEEP: usize = 101;
const SYSCALL_YIELD: usize = 124;
const SYSCALL_KILL: usize = 129;
const SYSCALL_GET_TIME: usize = 169;
const SYSCALL_GETPID: usize = 172;
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_SLEEP => sys_sleep(args[0]),
SYSCALL_YIELD => sys_yield(),
SYSCALL_KILL => sys_kill(args[0], args[1] as u32),
SYSCALL_GET_TIME => sys_get_time(),
SYSCALL_GETPID => sys_getpid(),
SYSCALL_FORK => sys_fork(),

View file

@ -1,8 +1,8 @@
use crate::fs::{open_file, OpenFlags};
use crate::mm::{translated_ref, translated_refmut, translated_str};
use crate::task::{
current_process, current_task, current_user_token, exit_current_and_run_next,
suspend_current_and_run_next,
current_process, current_task, current_user_token, exit_current_and_run_next, pid2process,
suspend_current_and_run_next, SignalFlags,
};
use crate::timer::get_time_ms;
use alloc::string::String;
@ -103,3 +103,16 @@ pub fn sys_waitpid(pid: isize, exit_code_ptr: *mut i32) -> isize {
}
// ---- 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 alloc::collections::VecDeque;
use alloc::collections::{BTreeMap, VecDeque};
use alloc::sync::Arc;
use lazy_static::*;
@ -26,6 +26,8 @@ impl TaskManager {
lazy_static! {
pub static ref TASK_MANAGER: UPSafeCell<TaskManager> =
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>) {
@ -35,3 +37,19 @@ pub fn add_task(task: Arc<TaskControlBlock>) {
pub fn fetch_task() -> Option<Arc<TaskControlBlock>> {
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 process;
mod processor;
mod signal;
mod switch;
mod task;
@ -15,11 +16,12 @@ use switch::__switch;
pub use context::TaskContext;
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::{
current_kstack_top, current_process, current_task, current_trap_cx, current_trap_cx_user_va,
current_user_token, run_tasks, schedule, take_current_task,
};
pub use signal::SignalFlags;
pub use task::{TaskControlBlock, TaskStatus};
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
// the process should terminate at once
if tid == 0 {
remove_from_pid2process(process.getpid());
let mut process_inner = process.inner_exclusive_access();
// mark this process as a zombie process
process_inner.is_zombie = true;
@ -111,3 +114,15 @@ lazy_static! {
pub fn add_initproc() {
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::manager::insert_into_pid2process;
use super::TaskControlBlock;
use super::{add_task, SignalFlags};
use super::{pid_alloc, PidHandle};
use crate::fs::{File, Stdin, Stdout};
use crate::mm::{translated_refmut, MemorySet, KERNEL_SPACE};
@ -26,6 +27,7 @@ pub struct ProcessControlBlockInner {
pub children: Vec<Arc<ProcessControlBlock>>,
pub exit_code: i32,
pub fd_table: Vec<Option<Arc<dyn File + Send + Sync>>>,
pub signals: SignalFlags,
pub tasks: Vec<Option<Arc<TaskControlBlock>>>,
pub task_res_allocator: RecycleAllocator,
pub mutex_list: Vec<Option<Arc<dyn Mutex>>>,
@ -92,6 +94,7 @@ impl ProcessControlBlock {
// 2 -> stderr
Some(Arc::new(Stdout)),
],
signals: SignalFlags::empty(),
tasks: Vec::new(),
task_res_allocator: RecycleAllocator::new(),
mutex_list: Vec::new(),
@ -123,6 +126,7 @@ impl ProcessControlBlock {
let mut process_inner = process.inner_exclusive_access();
process_inner.tasks.push(Some(Arc::clone(&task)));
drop(process_inner);
insert_into_pid2process(process.getpid(), Arc::clone(&process));
// add main thread to scheduler
add_task(task);
process
@ -209,6 +213,7 @@ impl ProcessControlBlock {
children: Vec::new(),
exit_code: 0,
fd_table: new_fd_table,
signals: SignalFlags::empty(),
tasks: Vec::new(),
task_res_allocator: RecycleAllocator::new(),
mutex_list: Vec::new(),
@ -242,6 +247,7 @@ impl ProcessControlBlock {
let trap_cx = task_inner.get_trap_cx();
trap_cx.kernel_sp = task.kstack.get_top();
drop(task_inner);
insert_into_pid2process(child.getpid(), Arc::clone(&child));
// add this thread to scheduler
add_task(task);
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::syscall::syscall;
use crate::task::{
current_trap_cx, current_trap_cx_user_va, current_user_token, exit_current_and_run_next,
suspend_current_and_run_next,
check_signals_of_current, current_add_signal, current_trap_cx, current_trap_cx_user_va,
current_user_token, exit_current_and_run_next, suspend_current_and_run_next, SignalFlags,
};
use crate::timer::{check_timer, set_next_trigger};
use core::arch::{asm, global_asm};
@ -60,19 +60,18 @@ pub fn trap_handler() -> ! {
| Trap::Exception(Exception::InstructionPageFault)
| Trap::Exception(Exception::LoadFault)
| Trap::Exception(Exception::LoadPageFault) => {
/*
println!(
"[kernel] {:?} in application, bad addr = {:#x}, bad instruction = {:#x}, kernel killed it.",
scause.cause(),
stval,
current_trap_cx().sepc,
);
// page fault exit code
exit_current_and_run_next(-2);
*/
current_add_signal(SignalFlags::SIGSEGV);
}
Trap::Exception(Exception::IllegalInstruction) => {
println!("[kernel] IllegalInstruction in application, kernel killed it.");
// illegal instruction exit code
exit_current_and_run_next(-3);
current_add_signal(SignalFlags::SIGILL);
}
Trap::Interrupt(Interrupt::SupervisorTimer) => {
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();
}