Add sigret and finish signal handling

ch7-signal
liusm18 3 years ago
parent fae8641f36
commit 1d7b8141f0

@ -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(),

@ -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 {

@ -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()
}
}

@ -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 {

@ -0,0 +1,8 @@
.section .text
.global start_sigret
.global end_sigret
start_sigret:
li a7,139;
ecall;
ret;
end_sigret:

@ -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();
}

@ -31,10 +31,15 @@ pub struct TaskControlBlockInner {
pub fd_table: Vec<Option<Arc<dyn File + Send + Sync>>>,
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<TrapContext>
}
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
})
},
});

@ -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,

@ -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);
}

Loading…
Cancel
Save