mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-20 22:36:31 +00:00
feat(syscall): 实现syscall restart (#1075)
能够在系统调用返回ERESTARTSYS时,信号处理结束后,自动重启系统调用. TODO: 实现wait等需要restart_block的系统调用的重启 Signed-off-by: longjin <longjin@DragonOS.org>
This commit is contained in:
@ -1,8 +1,9 @@
|
||||
use log::error;
|
||||
|
||||
use crate::{
|
||||
arch::{sched::sched, CurrentIrqArch},
|
||||
arch::{interrupt::TrapFrame, sched::sched, CurrentIrqArch},
|
||||
exception::InterruptArch,
|
||||
ipc::signal_types::SignalArch,
|
||||
process::ProcessManager,
|
||||
};
|
||||
|
||||
@ -339,3 +340,18 @@ fn sig_continue(sig: Signal) {
|
||||
fn sig_ignore(_sig: Signal) {
|
||||
return;
|
||||
}
|
||||
|
||||
pub struct RiscV64SignalArch;
|
||||
|
||||
impl SignalArch for RiscV64SignalArch {
|
||||
// TODO: 为RISCV64实现信号处理
|
||||
// 注意,rv64现在在中断/系统调用返回用户态时,没有进入 irqentry_exit() 函数,
|
||||
// 到时候实现信号处理时,需要修改中断/系统调用返回用户态的代码,进入 irqentry_exit() 函数
|
||||
unsafe fn do_signal_or_restart(_frame: &mut TrapFrame) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn sys_rt_sigreturn(_trap_frame: &mut TrapFrame) -> u64 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,8 @@ pub use self::time::RiscV64TimeArch as CurrentTimeArch;
|
||||
|
||||
pub use self::elf::RiscV64ElfArch as CurrentElfArch;
|
||||
|
||||
pub use self::ipc::signal::RiscV64SignalArch as CurrentSignalArch;
|
||||
|
||||
pub use crate::arch::smp::RiscV64SMPArch as CurrentSMPArch;
|
||||
|
||||
pub use crate::arch::sched::RiscV64SchedArch as CurrentSchedArch;
|
||||
|
@ -64,9 +64,9 @@ ENTRY(ret_from_intr)
|
||||
// 进入信号处理流程
|
||||
cli
|
||||
|
||||
// 将原本要返回的栈帧的栈指针传入do_signal的第一个参数
|
||||
// 将原本要返回的栈帧的栈指针传入irqentry_exit的第一个参数
|
||||
movq %rsp, %rdi
|
||||
callq do_signal
|
||||
callq irqentry_exit
|
||||
cli
|
||||
|
||||
__entry_ret_from_intr_before_gs_check_2:
|
||||
@ -375,10 +375,10 @@ ENTRY(syscall_64)
|
||||
sti
|
||||
callq *%rdx //调用服务程序
|
||||
|
||||
// 将原本要返回的栈帧的栈指针传入do_signal的第一个参数
|
||||
// 将原本要返回的栈帧的栈指针传入 irqentry_exit 的第一个参数
|
||||
movq %rsp, %rdi
|
||||
|
||||
callq do_signal
|
||||
callq irqentry_exit
|
||||
|
||||
cli
|
||||
|
||||
|
@ -125,6 +125,8 @@ pub struct TrapFrame {
|
||||
pub es: ::core::ffi::c_ulong,
|
||||
pub rax: ::core::ffi::c_ulong,
|
||||
pub func: ::core::ffi::c_ulong,
|
||||
/// - 该字段在异常发生时,保存的是错误码
|
||||
/// - 在系统调用时,由系统调用入口函数将其设置为系统调用号
|
||||
pub errcode: ::core::ffi::c_ulong,
|
||||
pub rip: ::core::ffi::c_ulong,
|
||||
pub cs: ::core::ffi::c_ulong,
|
||||
@ -182,6 +184,31 @@ impl TrapFrame {
|
||||
pub fn set_pc(&mut self, pc: usize) {
|
||||
self.rip = pc as u64;
|
||||
}
|
||||
|
||||
/// 获取系统调用号
|
||||
///
|
||||
/// # Safety
|
||||
/// 该函数只能在系统调用上下文中调用,
|
||||
/// 在其他上下文中,该函数返回值未定义
|
||||
pub unsafe fn syscall_nr(&self) -> Option<usize> {
|
||||
if self.errcode == u64::MAX {
|
||||
return None;
|
||||
}
|
||||
Some(self.errcode as usize)
|
||||
}
|
||||
|
||||
/// 获取系统调用错误码
|
||||
///
|
||||
/// # Safety
|
||||
/// 该函数只能在系统调用上下文中调用,
|
||||
/// 在其他上下文中,该函数返回值未定义
|
||||
///
|
||||
/// # Returns
|
||||
/// 返回一个 `Option<SystemError>`,表示系统调用的错误码。
|
||||
pub unsafe fn syscall_error(&self) -> Option<SystemError> {
|
||||
let val = self.rax as i32;
|
||||
SystemError::from_posix_errno(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl ProbeArgs for TrapFrame {
|
||||
|
@ -1,5 +1,6 @@
|
||||
use core::{ffi::c_void, intrinsics::unlikely, mem::size_of};
|
||||
|
||||
use defer::defer;
|
||||
use log::error;
|
||||
use system_error::SystemError;
|
||||
|
||||
@ -8,11 +9,12 @@ use crate::{
|
||||
fpu::FpState,
|
||||
interrupt::TrapFrame,
|
||||
process::table::{USER_CS, USER_DS},
|
||||
syscall::nr::SYS_RESTART_SYSCALL,
|
||||
CurrentIrqArch, MMArch,
|
||||
},
|
||||
exception::InterruptArch,
|
||||
ipc::{
|
||||
signal::set_current_blocked,
|
||||
signal::{restore_saved_sigmask, set_current_blocked},
|
||||
signal_types::{SaHandlerType, SigInfo, Sigaction, SigactionType, SignalArch},
|
||||
},
|
||||
mm::MemoryManagementArch,
|
||||
@ -405,99 +407,147 @@ pub struct SigStack {
|
||||
pub fpstate: FpState,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn do_signal(frame: &mut TrapFrame) {
|
||||
X86_64SignalArch::do_signal(frame);
|
||||
return;
|
||||
unsafe fn do_signal(frame: &mut TrapFrame, got_signal: &mut bool) {
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
|
||||
let siginfo = pcb.try_siginfo_irqsave(5);
|
||||
|
||||
if unlikely(siginfo.is_none()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let siginfo_read_guard = siginfo.unwrap();
|
||||
|
||||
// 检查sigpending是否为0
|
||||
if siginfo_read_guard.sig_pending().signal().bits() == 0 || !frame.is_from_user() {
|
||||
// 若没有正在等待处理的信号,或者将要返回到的是内核态,则返回
|
||||
return;
|
||||
}
|
||||
|
||||
let mut sig_number: Signal;
|
||||
let mut info: Option<SigInfo>;
|
||||
let mut sigaction: Option<Sigaction>;
|
||||
let sig_block: SigSet = *siginfo_read_guard.sig_blocked();
|
||||
drop(siginfo_read_guard);
|
||||
|
||||
let sig_guard = pcb.try_sig_struct_irqsave(5);
|
||||
if unlikely(sig_guard.is_none()) {
|
||||
return;
|
||||
}
|
||||
let siginfo_mut = pcb.try_siginfo_mut(5);
|
||||
if unlikely(siginfo_mut.is_none()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let sig_guard = sig_guard.unwrap();
|
||||
let mut siginfo_mut_guard = siginfo_mut.unwrap();
|
||||
loop {
|
||||
(sig_number, info) = siginfo_mut_guard.dequeue_signal(&sig_block, &pcb);
|
||||
|
||||
// 如果信号非法,则直接返回
|
||||
if sig_number == Signal::INVALID {
|
||||
return;
|
||||
}
|
||||
let sa = sig_guard.handlers[sig_number as usize - 1];
|
||||
|
||||
match sa.action() {
|
||||
SigactionType::SaHandler(action_type) => match action_type {
|
||||
SaHandlerType::Error => {
|
||||
error!("Trying to handle a Sigerror on Process:{:?}", pcb.pid());
|
||||
return;
|
||||
}
|
||||
SaHandlerType::Default => {
|
||||
sigaction = Some(sa);
|
||||
}
|
||||
SaHandlerType::Ignore => continue,
|
||||
SaHandlerType::Customized(_) => {
|
||||
sigaction = Some(sa);
|
||||
}
|
||||
},
|
||||
SigactionType::SaSigaction(_) => todo!(),
|
||||
}
|
||||
|
||||
if sigaction.is_some() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let oldset = *siginfo_mut_guard.sig_blocked();
|
||||
//避免死锁
|
||||
drop(siginfo_mut_guard);
|
||||
drop(sig_guard);
|
||||
drop(pcb);
|
||||
// 做完上面的检查后,开中断
|
||||
CurrentIrqArch::interrupt_enable();
|
||||
|
||||
if sigaction.is_none() {
|
||||
return;
|
||||
}
|
||||
*got_signal = true;
|
||||
|
||||
let mut sigaction = sigaction.unwrap();
|
||||
|
||||
// 注意!由于handle_signal里面可能会退出进程,
|
||||
// 因此这里需要检查清楚:上面所有的锁、arc指针都被释放了。否则会产生资源泄露的问题!
|
||||
let res: Result<i32, SystemError> =
|
||||
handle_signal(sig_number, &mut sigaction, &info.unwrap(), &oldset, frame);
|
||||
if res.is_err() {
|
||||
error!(
|
||||
"Error occurred when handling signal: {}, pid={:?}, errcode={:?}",
|
||||
sig_number as i32,
|
||||
ProcessManager::current_pcb().pid(),
|
||||
res.as_ref().unwrap_err()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn try_restart_syscall(frame: &mut TrapFrame) {
|
||||
defer!({
|
||||
// 如果没有信号需要传递,我们只需恢复保存的信号掩码
|
||||
restore_saved_sigmask();
|
||||
});
|
||||
|
||||
if unsafe { frame.syscall_nr() }.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let syscall_err = unsafe { frame.syscall_error() };
|
||||
if syscall_err.is_none() {
|
||||
return;
|
||||
}
|
||||
let syscall_err = syscall_err.unwrap();
|
||||
|
||||
let mut restart = false;
|
||||
match syscall_err {
|
||||
SystemError::ERESTARTSYS | SystemError::ERESTARTNOHAND | SystemError::ERESTARTNOINTR => {
|
||||
frame.rax = frame.errcode;
|
||||
frame.rip -= 2;
|
||||
restart = true;
|
||||
}
|
||||
SystemError::ERESTART_RESTARTBLOCK => {
|
||||
frame.rax = SYS_RESTART_SYSCALL as u64;
|
||||
frame.rip -= 2;
|
||||
restart = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
log::debug!("try restart syscall: {:?}", restart);
|
||||
}
|
||||
|
||||
pub struct X86_64SignalArch;
|
||||
|
||||
impl SignalArch for X86_64SignalArch {
|
||||
unsafe fn do_signal(frame: &mut TrapFrame) {
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
/// 处理信号,并尝试重启系统调用
|
||||
///
|
||||
/// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/signal.c#865
|
||||
unsafe fn do_signal_or_restart(frame: &mut TrapFrame) {
|
||||
let mut got_signal = false;
|
||||
do_signal(frame, &mut got_signal);
|
||||
|
||||
let siginfo = pcb.try_siginfo_irqsave(5);
|
||||
|
||||
if unlikely(siginfo.is_none()) {
|
||||
if got_signal {
|
||||
return;
|
||||
}
|
||||
|
||||
let siginfo_read_guard = siginfo.unwrap();
|
||||
|
||||
// 检查sigpending是否为0
|
||||
if siginfo_read_guard.sig_pending().signal().bits() == 0 || !frame.is_from_user() {
|
||||
// 若没有正在等待处理的信号,或者将要返回到的是内核态,则返回
|
||||
return;
|
||||
}
|
||||
|
||||
let mut sig_number: Signal;
|
||||
let mut info: Option<SigInfo>;
|
||||
let mut sigaction: Sigaction;
|
||||
let sig_block: SigSet = *siginfo_read_guard.sig_block();
|
||||
drop(siginfo_read_guard);
|
||||
|
||||
let sig_guard = pcb.try_sig_struct_irqsave(5);
|
||||
if unlikely(sig_guard.is_none()) {
|
||||
return;
|
||||
}
|
||||
let siginfo_mut = pcb.try_siginfo_mut(5);
|
||||
if unlikely(siginfo_mut.is_none()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let sig_guard = sig_guard.unwrap();
|
||||
let mut siginfo_mut_guard = siginfo_mut.unwrap();
|
||||
loop {
|
||||
(sig_number, info) = siginfo_mut_guard.dequeue_signal(&sig_block);
|
||||
// 如果信号非法,则直接返回
|
||||
if sig_number == Signal::INVALID {
|
||||
return;
|
||||
}
|
||||
|
||||
sigaction = sig_guard.handlers[sig_number as usize - 1];
|
||||
|
||||
match sigaction.action() {
|
||||
SigactionType::SaHandler(action_type) => match action_type {
|
||||
SaHandlerType::Error => {
|
||||
error!("Trying to handle a Sigerror on Process:{:?}", pcb.pid());
|
||||
return;
|
||||
}
|
||||
SaHandlerType::Default => {
|
||||
sigaction = Sigaction::default();
|
||||
break;
|
||||
}
|
||||
SaHandlerType::Ignore => continue,
|
||||
SaHandlerType::Customized(_) => {
|
||||
break;
|
||||
}
|
||||
},
|
||||
SigactionType::SaSigaction(_) => todo!(),
|
||||
}
|
||||
// 如果当前动作是忽略这个信号,就继续循环。
|
||||
}
|
||||
|
||||
let oldset = *siginfo_mut_guard.sig_block();
|
||||
//避免死锁
|
||||
drop(siginfo_mut_guard);
|
||||
drop(sig_guard);
|
||||
drop(pcb);
|
||||
|
||||
// 做完上面的检查后,开中断
|
||||
CurrentIrqArch::interrupt_enable();
|
||||
|
||||
// 注意!由于handle_signal里面可能会退出进程,
|
||||
// 因此这里需要检查清楚:上面所有的锁、arc指针都被释放了。否则会产生资源泄露的问题!
|
||||
let res: Result<i32, SystemError> =
|
||||
handle_signal(sig_number, &mut sigaction, &info.unwrap(), &oldset, frame);
|
||||
if res.is_err() {
|
||||
error!(
|
||||
"Error occurred when handling signal: {}, pid={:?}, errcode={:?}",
|
||||
sig_number as i32,
|
||||
ProcessManager::current_pcb().pid(),
|
||||
res.as_ref().unwrap_err()
|
||||
);
|
||||
}
|
||||
try_restart_syscall(frame);
|
||||
}
|
||||
|
||||
fn sys_rt_sigreturn(trap_frame: &mut TrapFrame) -> u64 {
|
||||
@ -533,6 +583,8 @@ impl SignalArch for X86_64SignalArch {
|
||||
/// @param regs 之前的系统调用将要返回的时候,要弹出的栈帧的拷贝
|
||||
///
|
||||
/// @return Result<0,SystemError> 若Error, 则返回错误码,否则返回Ok(0)
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/signal.c#787
|
||||
fn handle_signal(
|
||||
sig: Signal,
|
||||
sigaction: &mut Sigaction,
|
||||
@ -540,8 +592,28 @@ fn handle_signal(
|
||||
oldset: &SigSet,
|
||||
frame: &mut TrapFrame,
|
||||
) -> Result<i32, SystemError> {
|
||||
// TODO 这里要补充一段逻辑,好像是为了保证引入线程之后的地址空间不会出问题。详见https://code.dragonos.org.cn/xref/linux-6.1.9/arch/mips/kernel/signal.c#830
|
||||
|
||||
if unsafe { frame.syscall_nr() }.is_some() {
|
||||
if let Some(syscall_err) = unsafe { frame.syscall_error() } {
|
||||
match syscall_err {
|
||||
SystemError::ERESTARTNOHAND | SystemError::ERESTART_RESTARTBLOCK => {
|
||||
frame.rax = SystemError::EINTR.to_posix_errno() as i64 as u64;
|
||||
}
|
||||
SystemError::ERESTARTSYS => {
|
||||
if !sigaction.flags().contains(SigFlags::SA_RESTART) {
|
||||
frame.rax = SystemError::EINTR.to_posix_errno() as i64 as u64;
|
||||
} else {
|
||||
frame.rax = frame.errcode;
|
||||
frame.rip -= 2;
|
||||
}
|
||||
}
|
||||
SystemError::ERESTARTNOINTR => {
|
||||
frame.rax = frame.errcode;
|
||||
frame.rip -= 2;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 设置栈帧
|
||||
return setup_frame(sig, sigaction, info, oldset, frame);
|
||||
}
|
||||
|
@ -65,6 +65,8 @@ macro_rules! syscall_return {
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "sysv64" fn syscall_handler(frame: &mut TrapFrame) {
|
||||
// 系统调用进入时,把系统调用号存入errcode字段,以便在syscall_handler退出后,仍能获取到系统调用号
|
||||
frame.errcode = frame.rax;
|
||||
let syscall_num = frame.rax as usize;
|
||||
// 防止sys_sched由于超时无法退出导致的死锁
|
||||
if syscall_num == SYS_SCHED {
|
||||
|
Reference in New Issue
Block a user