diff --git a/os/src/syscall/mod.rs b/os/src/syscall/mod.rs index c3953ff8..0db1ed47 100644 --- a/os/src/syscall/mod.rs +++ b/os/src/syscall/mod.rs @@ -9,6 +9,7 @@ const SYSCALL_YIELD: usize = 124; const SYSCALL_KILL: usize = 129; const SYSCALL_SIGACTION: usize = 134; const SYSCALL_SIGPROCMASK: usize = 135; +const SYSCALL_SIGRETURN: usize = 139; const SYSCALL_GET_TIME: usize = 169; const SYSCALL_GETPID: usize = 172; const SYSCALL_FORK: usize = 220; @@ -36,6 +37,7 @@ pub fn syscall(syscall_id: usize, args: [usize; 3]) -> isize { SYSCALL_KILL => sys_kill(args[0], args[1] as u32), SYSCALL_SIGACTION => sys_sigaction(args[0] as u32, args[1] as *const SignalAction, args[2] as *mut SignalAction), SYSCALL_SIGPROCMASK => sys_sigprocmask(args[0] as u32), + SYSCALL_SIGRETURN => sys_sigretrun(), SYSCALL_GET_TIME => sys_get_time(), SYSCALL_GETPID => sys_getpid(), SYSCALL_FORK => sys_fork(), diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index 39ac8b8b..351f7df1 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -137,6 +137,19 @@ pub fn sys_sigprocmask(mask: u32) -> isize { } } +pub fn sys_sigretrun() -> isize { + if let Some(task) = current_task() { + let mut inner = task.inner_exclusive_access(); + inner.handling_sig = -1; + // restore the trap context + let trap_ctx = inner.get_trap_cx(); + *trap_ctx = inner.trap_ctx_backup.unwrap(); + 0 + } else { + -1 + } +} + fn check_sigaction_error(signal: SignalFlags, action: usize, old_action: usize) -> bool { if action == 0 || old_action == 0 || signal == SignalFlags::SIGKILL || signal == SignalFlags::SIGSTOP { diff --git a/os/src/task/mod.rs b/os/src/task/mod.rs index 2bc3ae86..b22dc69a 100644 --- a/os/src/task/mod.rs +++ b/os/src/task/mod.rs @@ -4,11 +4,13 @@ mod pid; mod processor; mod signal; mod switch; +mod sigret; mod action; #[allow(clippy::module_inception)] mod task; use crate::fs::{open_file, OpenFlags}; +use crate::mm::translated_refmut; use alloc::sync::Arc; pub use context::TaskContext; use lazy_static::*; @@ -25,6 +27,9 @@ pub use processor::{ pub use signal::{SignalFlags, MAX_SIG}; pub use action::{SignalAction, SignalActions}; +use self::sigret::end_sigret; +use self::sigret::start_sigret; + pub fn suspend_current_and_run_next() { // There must be an application running. let task = take_current_task().unwrap(); @@ -92,7 +97,7 @@ pub fn add_initproc() { add_task(INITPROC.clone()); } -pub fn check_signals_of_current() -> Option<(i32, &'static str)> { +pub fn check_signals_error_of_current() -> Option<(i32, &'static str)> { let task = current_task().unwrap(); let task_inner = task.inner_exclusive_access(); task_inner.signals.check_error() @@ -103,3 +108,110 @@ pub fn current_add_signal(signal: SignalFlags) { let mut task_inner = task.inner_exclusive_access(); task_inner.signals |= signal; } + +fn call_kernel_signal_handler(signal: SignalFlags) { + let task = current_task().unwrap(); + let mut task_inner = task.inner_exclusive_access(); + match signal { + SignalFlags::SIGSTOP => { + task_inner.frozen = true; + task_inner.signals ^= SignalFlags::SIGSTOP; + } + SignalFlags::SIGCONT => { + if task_inner.signals.contains(SignalFlags::SIGCONT) { + task_inner.signals ^= SignalFlags::SIGCONT; + task_inner.frozen = false; + } + } + _ => { + task_inner.killed = true; + } + } +} + +fn call_user_signal_handler(sig: usize, signal: SignalFlags) { + let task = current_task().unwrap(); + let mut task_inner = task.inner_exclusive_access(); + let token = current_user_token(); + + let handler = task_inner.signal_actions.table[sig].handler; + // change current mask + task_inner.signal_mask = task_inner.signal_actions.table[sig].mask; + // handle flag + task_inner.handling_sig = sig as isize; + task_inner.signals ^= signal; + + // backup trapframe + let mut trap_ctx = task_inner.get_trap_cx(); + task_inner.trap_ctx_backup = Some(*trap_ctx); + + // modify trapframe + trap_ctx.sepc = handler; + + // inject sigret + let sigret_size = end_sigret as usize - start_sigret as usize; + trap_ctx.x[2] -= sigret_size; + let cur_sp = trap_ctx.x[2]; + unsafe { + let target_sigret_ptr = translated_refmut(token, cur_sp as *mut u8); + let target_sigret_ptr = core::slice::from_raw_parts_mut(target_sigret_ptr as *mut u8, sigret_size); + let source_sigret_ptr = core::slice::from_raw_parts(start_sigret as usize as *mut u8, sigret_size); + target_sigret_ptr.copy_from_slice(source_sigret_ptr); + } + + // put args (a0) + trap_ctx.x[10] = sig; + // return addr + trap_ctx.x[1] = cur_sp; +} + +fn check_pending_signals() { + for sig in 0..(MAX_SIG + 1) { + let task = current_task().unwrap(); + let task_inner = task.inner_exclusive_access(); + let signal = SignalFlags::from_bits(1 << sig).unwrap(); + if task_inner.signals.contains(signal) && (!task_inner.signal_mask.contains(signal)) { + if task_inner.handling_sig == -1 { + drop(task_inner); + if signal == SignalFlags::SIGKILL || signal == SignalFlags::SIGSTOP || + signal == SignalFlags::SIGCONT || signal == SignalFlags::SIGDEF { + // signal is a kernel signal + call_kernel_signal_handler(signal); + } else { + // signal is a user signal + call_user_signal_handler(sig, signal); + return; + } + } else { + if !task_inner.signal_actions.table[task_inner.handling_sig as usize].mask.contains(signal) { + drop(task_inner); + if signal == SignalFlags::SIGKILL || signal == SignalFlags::SIGSTOP || + signal == SignalFlags::SIGCONT || signal == SignalFlags::SIGDEF { + // signal is a kernel signal + call_kernel_signal_handler(signal); + } else { + // signal is a user signal + call_user_signal_handler(sig, signal); + return; + } + } + } + } + } +} + +pub fn handle_signals() { + check_pending_signals(); + loop { + let task = current_task().unwrap(); + let task_inner = task.inner_exclusive_access(); + let frozen_flag = task_inner.frozen; + let killed_flag = task_inner.killed; + drop(task_inner); + if (!frozen_flag) || killed_flag { + break; + } + check_pending_signals(); + suspend_current_and_run_next() + } +} diff --git a/os/src/task/signal.rs b/os/src/task/signal.rs index 009ec583..54f56f8f 100644 --- a/os/src/task/signal.rs +++ b/os/src/task/signal.rs @@ -4,6 +4,7 @@ pub const MAX_SIG: usize = 31; bitflags! { pub struct SignalFlags: u32 { + const SIGDEF = 1; // Default signal handling const SIGHUP = 1 << 1; const SIGINT = 1 << 2; const SIGQUIT = 1 << 3; @@ -48,6 +49,8 @@ impl SignalFlags { Some((-6, "Aborted, SIGABRT=6")) } else if self.contains(Self::SIGFPE) { Some((-8, "Erroneous Arithmetic Operation, SIGFPE=8")) + } else if self.contains(Self::SIGKILL) { + Some((-9, "Killed, SIGKILL=9")) } else if self.contains(Self::SIGSEGV) { Some((-11, "Segmentation Fault, SIGSEGV=11")) } else { diff --git a/os/src/task/sigret.S b/os/src/task/sigret.S new file mode 100644 index 00000000..471caf07 --- /dev/null +++ b/os/src/task/sigret.S @@ -0,0 +1,8 @@ +.section .text +.global start_sigret +.global end_sigret +start_sigret: + li a7,139; + ecall; + ret; +end_sigret: diff --git a/os/src/task/sigret.rs b/os/src/task/sigret.rs new file mode 100644 index 00000000..808ba86a --- /dev/null +++ b/os/src/task/sigret.rs @@ -0,0 +1,8 @@ +use core::arch::global_asm; + +global_asm!(include_str!("sigret.S")); + +extern "C" { + pub fn start_sigret(); + pub fn end_sigret(); +} diff --git a/os/src/task/task.rs b/os/src/task/task.rs index 9d7a18c4..c7a132e4 100644 --- a/os/src/task/task.rs +++ b/os/src/task/task.rs @@ -31,10 +31,15 @@ pub struct TaskControlBlockInner { pub fd_table: Vec>>, pub signals: SignalFlags, pub signal_mask: SignalFlags, - // if a the task is handling a signal - pub handling_flag: bool, + // the signal which is being handling + pub handling_sig: isize, // Signal actions - pub signal_actions: SignalActions + pub signal_actions: SignalActions, + // if the task is killed + pub killed: bool, + // if the task is frozen by a signal + pub frozen: bool, + pub trap_ctx_backup: Option } impl TaskControlBlockInner { @@ -98,8 +103,11 @@ impl TaskControlBlock { ], signals: SignalFlags::empty(), signal_mask: SignalFlags::empty(), - handling_flag: false, - signal_actions: SignalActions::default() + handling_sig: -1, + signal_actions: SignalActions::default(), + killed: false, + frozen: false, + trap_ctx_backup: None }) }, }; @@ -204,8 +212,11 @@ impl TaskControlBlock { signals: SignalFlags::empty(), // inherit the signal_mask and signal_action signal_mask: parent_inner.signal_mask, - handling_flag: false, - signal_actions: parent_inner.signal_actions.clone() + handling_sig: -1, + signal_actions: parent_inner.signal_actions.clone(), + killed: false, + frozen: false, + trap_ctx_backup: None }) }, }); diff --git a/os/src/trap/context.rs b/os/src/trap/context.rs index 011b7fb7..4f6ad8ff 100644 --- a/os/src/trap/context.rs +++ b/os/src/trap/context.rs @@ -1,7 +1,7 @@ use riscv::register::sstatus::{self, Sstatus, SPP}; #[repr(C)] -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub struct TrapContext { pub x: [usize; 32], pub sstatus: Sstatus, diff --git a/os/src/trap/mod.rs b/os/src/trap/mod.rs index 05c36b89..15c20379 100644 --- a/os/src/trap/mod.rs +++ b/os/src/trap/mod.rs @@ -3,8 +3,8 @@ mod context; use crate::config::{TRAMPOLINE, TRAP_CONTEXT}; use crate::syscall::syscall; use crate::task::{ - check_signals_of_current, current_add_signal, current_trap_cx, current_user_token, - exit_current_and_run_next, suspend_current_and_run_next, SignalFlags, + check_signals_error_of_current, current_add_signal, current_trap_cx, current_user_token, + exit_current_and_run_next, suspend_current_and_run_next, SignalFlags, handle_signals, }; use crate::timer::set_next_trigger; use core::arch::{asm, global_asm}; @@ -85,8 +85,11 @@ pub fn trap_handler() -> ! { ); } } - // check signals - if let Some((errno, msg)) = check_signals_of_current() { + // handle signals (handle the sent signal) + handle_signals(); + + // check error signals (if error then exit) + if let Some((errno, msg)) = check_signals_error_of_current() { println!("[kernel] {}", msg); exit_current_and_run_next(errno); }