feat(syscall): 实现syscall restart (#1075)

能够在系统调用返回ERESTARTSYS时,信号处理结束后,自动重启系统调用.

TODO: 实现wait等需要restart_block的系统调用的重启

Signed-off-by: longjin <longjin@DragonOS.org>
This commit is contained in:
LoGin 2024-12-13 00:56:20 +08:00 committed by GitHub
parent 72423f90bb
commit 2b72148cae
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 657 additions and 180 deletions

View File

@ -76,6 +76,7 @@ unwinding = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/unwi
"panic",
"personality"
]}
defer = "0.2.1"
# target为x86_64时使用下面的依赖
[target.'cfg(target_arch = "x86_64")'.dependencies]
@ -106,4 +107,4 @@ debug = true # Controls whether the compiler passes `-g`
# The release profile, used for `cargo build --release`
[profile.release]
debug = false
debug = true

View File

@ -7,4 +7,4 @@ edition = "2021"
[dependencies]
num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num-traits.git", rev="1597c1c", default-features = false }
num-derive = "0.3"
num-derive = "0.3"

View File

@ -277,31 +277,51 @@ pub enum SystemError {
// === 以下错误码不应该被用户态程序使用 ===
ERESTARTSYS = 512,
// VMX on 虚拟化开启指令出错
EVMXONFailed = 513,
// VMX off 虚拟化关闭指令出错
EVMXOFFFailed = 514,
// VMX VMWRITE 写入虚拟化VMCS内存出错
EVMWRITEFailed = 515,
EVMREADFailed = 516,
EVMPRTLDFailed = 517,
EVMLAUNCHFailed = 518,
KVM_HVA_ERR_BAD = 519,
ERESTARTNOINTR = 513,
/// restart if no handler
ERESTARTNOHAND = 514,
/// 没有对应的ioctlcmd
ENOIOCTLCMD = 520,
ENOIOCTLCMD = 515,
/// restart by calling sys restart syscall
ERESTART_RESTARTBLOCK = 516,
// === TODO: 这几个KVM的错误码不要放在这里 ===
// VMX on 虚拟化开启指令出错
EVMXONFailed = 1513,
// VMX off 虚拟化关闭指令出错
EVMXOFFFailed = 1514,
// VMX VMWRITE 写入虚拟化VMCS内存出错
EVMWRITEFailed = 1515,
EVMREADFailed = 1516,
EVMPRTLDFailed = 1517,
EVMLAUNCHFailed = 1518,
KVM_HVA_ERR_BAD = 1519,
MAXERRNO = 4095,
}
impl SystemError {
/// @brief 把posix错误码转换为系统错误枚举类型。
/// 判断一个值是否是有效的posix错误码。
pub fn is_valid_posix_errno<T>(val: T) -> bool
where
T: PartialOrd + From<i32>,
{
let max_errno = T::from(-(Self::MAXERRNO as i32));
val < T::from(0) && val >= max_errno
}
/// 尝试把posix错误码转换为系统错误枚举类型。
pub fn from_posix_errno(errno: i32) -> Option<SystemError> {
// posix 错误码是小于0的
if errno >= 0 {
if !Self::is_valid_posix_errno(errno) {
return None;
}
return <Self as num_traits::FromPrimitive>::from_i32(-errno);
}
/// @brief 把系统错误枚举类型转换为负数posix错误码。
/// 把系统错误枚举类型转换为负数posix错误码。
pub fn to_posix_errno(&self) -> i32 {
return -<Self as num_traits::ToPrimitive>::to_i32(self).unwrap();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -263,7 +263,7 @@ impl IndexNode for TtyDevice {
break;
}
if pcb.sig_info_irqsave().sig_pending().has_pending() {
if pcb.has_pending_signal_fast() {
return Err(SystemError::ERESTARTSYS);
}
}

View File

@ -4,7 +4,7 @@ use system_error::SystemError;
use crate::{
arch::ipc::signal::{SigSet, Signal},
mm::VirtAddr,
process::{Pid, ProcessManager},
process::{Pid, ProcessFlags, ProcessManager},
syscall::{
user_access::{UserBufferReader, UserBufferWriter},
Syscall,
@ -51,9 +51,9 @@ impl TtyJobCtrlManager {
if tty_pgid.is_some() && tty_pgid.unwrap() != pgid {
if pcb
.sig_info_irqsave()
.sig_block()
.sig_blocked()
.contains(SigSet::from_bits_truncate(1 << sig as u64))
|| pcb.sig_struct_irqsave().handlers[sig as usize].is_ignore()
|| pcb.sig_struct_irqsave().handlers[sig as usize - 1].is_ignore()
{
// 忽略该信号
if sig == Signal::SIGTTIN {
@ -62,7 +62,11 @@ impl TtyJobCtrlManager {
} else {
// 暂时使用kill而不是killpg
Syscall::kill(pgid, sig as i32)?;
return Err(SystemError::ERESTART);
ProcessManager::current_pcb()
.flags()
.insert(ProcessFlags::HAS_PENDING_SIGNAL);
return Err(SystemError::ERESTARTSYS);
}
}

View File

@ -21,7 +21,7 @@ use crate::{
},
mm::VirtAddr,
net::event_poll::EPollEventType,
process::ProcessManager,
process::{ProcessFlags, ProcessManager},
syscall::{user_access::UserBufferWriter, Syscall},
};
@ -1680,11 +1680,11 @@ impl TtyLineDiscipline for NTtyLinediscipline {
break;
}
if ProcessManager::current_pcb()
.sig_info_irqsave()
.sig_pending()
.has_pending()
{
if ProcessManager::current_pcb().has_pending_signal_fast() {
ProcessManager::current_pcb()
.flags()
.insert(ProcessFlags::HAS_PENDING_SIGNAL);
ret = Err(SystemError::ERESTARTSYS);
break;
}
@ -1763,7 +1763,11 @@ impl TtyLineDiscipline for NTtyLinediscipline {
// drop(ldata);
let mut offset = 0;
loop {
if pcb.sig_info_irqsave().sig_pending().has_pending() {
if pcb.has_pending_signal_fast() {
ProcessManager::current_pcb()
.flags()
.insert(ProcessFlags::HAS_PENDING_SIGNAL);
return Err(SystemError::ERESTARTSYS);
}
if core.flags().contains(TtyFlag::HUPPED) {

View File

@ -0,0 +1,46 @@
use crate::{
arch::{interrupt::TrapFrame, CurrentSignalArch},
ipc::signal_types::SignalArch,
process::{ProcessFlags, ProcessManager},
};
#[no_mangle]
unsafe extern "C" fn irqentry_exit(frame: &mut TrapFrame) {
if frame.is_from_user() {
irqentry_exit_to_user_mode(frame);
}
}
/// 退出到用户态之前,在这个函数内做最后的处理
///
/// # Safety
///
/// 由于这个函数内可能会直接退出进程,因此,在进入函数之前,
/// 必须保证所有的栈上的Arc/Box指针等都已经被释放。否则可能会导致内存泄漏。
unsafe fn irqentry_exit_to_user_mode(frame: &mut TrapFrame) {
exit_to_user_mode_prepare(frame);
}
/// # Safety
///
/// 由于这个函数内可能会直接退出进程,因此,在进入函数之前,
/// 必须保证所有的栈上的Arc/Box指针等都已经被释放。否则可能会导致内存泄漏。
unsafe fn exit_to_user_mode_prepare(frame: &mut TrapFrame) {
let process_flags_work = *ProcessManager::current_pcb().flags();
if !process_flags_work.exit_to_user_mode_work().is_empty() {
exit_to_user_mode_loop(frame, process_flags_work);
}
}
/// # Safety
///
/// 由于这个函数内可能会直接退出进程,因此,在进入函数之前,
/// 必须保证所有的栈上的Arc/Box指针等都已经被释放。否则可能会导致内存泄漏。
unsafe fn exit_to_user_mode_loop(frame: &mut TrapFrame, mut process_flags_work: ProcessFlags) {
while !process_flags_work.exit_to_user_mode_work().is_empty() {
if process_flags_work.contains(ProcessFlags::HAS_PENDING_SIGNAL) {
unsafe { CurrentSignalArch::do_signal_or_restart(frame) };
}
process_flags_work = *ProcessManager::current_pcb().flags();
}
}

View File

@ -7,6 +7,7 @@ use crate::arch::CurrentIrqArch;
pub mod debug;
pub mod dummychip;
pub mod ebreak;
pub mod entry;
pub mod handle;
pub mod init;
pub mod ipi;

View File

@ -4,7 +4,7 @@ use crate::filesystem::vfs::{FilePrivateData, FileSystem, FileType, IndexNode, M
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
use crate::libs::wait_queue::WaitQueue;
use crate::net::event_poll::{EPollEventType, EPollItem, EventPoll, KernelIoctlData};
use crate::process::ProcessManager;
use crate::process::{ProcessFlags, ProcessManager};
use crate::sched::SchedMode;
use crate::syscall::Syscall;
use alloc::collections::LinkedList;
@ -127,6 +127,10 @@ impl IndexNode for EventFdInode {
drop(lock_efd);
let r = wq_wait_event_interruptible!(self.wait_queue, self.readable(), {});
if r.is_err() {
ProcessManager::current_pcb()
.flags()
.insert(ProcessFlags::HAS_PENDING_SIGNAL);
return Err(SystemError::ERESTARTSYS);
}

View File

@ -311,14 +311,7 @@ impl File {
let len = self
.inode
.read_at(offset, len, buf, self.private_data.lock())
.map_err(|e| {
if e == SystemError::ERESTARTSYS {
SystemError::EINTR
} else {
e
}
})?;
.read_at(offset, len, buf, self.private_data.lock())?;
if update_offset {
self.offset
@ -343,24 +336,11 @@ impl File {
// 如果文件指针已经超过了文件大小,则需要扩展文件大小
if offset > self.inode.metadata()?.size as usize {
self.inode.resize(offset).map_err(|e| {
if e == SystemError::ERESTARTSYS {
SystemError::EINTR
} else {
e
}
})?;
self.inode.resize(offset)?;
}
let len = self
.inode
.write_at(offset, len, buf, self.private_data.lock())
.map_err(|e| {
if e == SystemError::ERESTARTSYS {
SystemError::EINTR
} else {
e
}
})?;
.write_at(offset, len, buf, self.private_data.lock())?;
if update_offset {
self.offset

View File

@ -11,7 +11,7 @@ use crate::{
wait_queue::WaitQueue,
},
net::event_poll::{EPollEventType, EPollItem, EventPoll},
process::{ProcessManager, ProcessState},
process::{ProcessFlags, ProcessManager, ProcessState},
sched::SchedMode,
time::PosixTimeSpec,
};
@ -232,6 +232,9 @@ impl IndexNode for LockedPipeInode {
drop(inode);
let r = wq_wait_event_interruptible!(self.read_wait_queue, self.readable(), {});
if r.is_err() {
ProcessManager::current_pcb()
.flags()
.insert(ProcessFlags::HAS_PENDING_SIGNAL);
return Err(SystemError::ERESTARTSYS);
}

View File

@ -8,7 +8,9 @@ use crate::{
arch::ipc::signal::{SigCode, SigFlags, SigSet, Signal},
ipc::signal_types::SigactionType,
libs::spinlock::SpinLockGuard,
process::{pid::PidType, Pid, ProcessControlBlock, ProcessFlags, ProcessManager},
process::{
pid::PidType, Pid, ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSignalInfo,
},
};
use super::signal_types::{
@ -25,7 +27,7 @@ impl Signal {
return false;
}
if !pcb.has_pending_signal() {
if !pcb.has_pending_signal_fast() {
return false;
}
@ -112,7 +114,7 @@ impl Signal {
}
if !self.prepare_sianal(pcb.clone(), force_send) {
return Err(SystemError::EINVAL);
return Ok(0);
}
// debug!("force send={}", force_send);
let pcb_info = pcb.sig_info_irqsave();
@ -213,13 +215,18 @@ impl Signal {
}
}
/// @brief 本函数用于检测指定的进程是否想要接收SIG这个信号。
/// 本函数用于检测指定的进程是否想要接收SIG这个信号。
///
/// 当我们对于进程组中的所有进程都运行了这个检查之后,我们将可以找到组内愿意接收信号的进程。
/// 这么做是为了防止我们把信号发送给了一个正在或已经退出的进程,或者是不响应该信号的进程。
#[inline]
fn wants_signal(&self, pcb: Arc<ProcessControlBlock>) -> bool {
// 如果改进程屏蔽了这个signal则不能接收
if pcb.sig_info_irqsave().sig_block().contains((*self).into()) {
if pcb
.sig_info_irqsave()
.sig_blocked()
.contains((*self).into())
{
return false;
}
@ -291,7 +298,7 @@ impl Signal {
// 一个被阻塞了的信号肯定是要被处理的
if pcb
.sig_info_irqsave()
.sig_block()
.sig_blocked()
.contains(self.into_sigset())
{
return true;
@ -316,6 +323,7 @@ fn signal_wake_up(pcb: Arc<ProcessControlBlock>, _guard: SpinLockGuard<SignalStr
// debug!("signal_wake_up");
// 如果目标进程已经在运行则发起一个ipi使得它陷入内核
let state = pcb.sched_info().inner_lock_read_irqsave().state();
pcb.flags().insert(ProcessFlags::HAS_PENDING_SIGNAL);
let mut wakeup_ok = true;
if state.is_blocked_interruptable() {
ProcessManager::wakeup(&pcb).unwrap_or_else(|e| {
@ -350,16 +358,67 @@ fn signal_wake_up(pcb: Arc<ProcessControlBlock>, _guard: SpinLockGuard<SignalStr
}
}
/// @brief 当一个进程具有多个线程之后在这里需要重新计算线程的flag中的TIF_SIGPENDING位
fn recalc_sigpending() {
// todo:
fn has_pending_signals(sigset: &SigSet, blocked: &SigSet) -> bool {
sigset.bits() & (!blocked.bits()) != 0
}
/// @brief 刷新指定进程的sighand的sigaction将满足条件的sigaction恢复为Default
/// 除非某个信号被设置为ignore且force_default为false否则都不会将其恢复
impl ProcessControlBlock {
/// 重新计算线程的flag中的TIF_SIGPENDING位
/// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/signal.c?r=&mo=4806&fi=182#182
pub fn recalc_sigpending(&self, siginfo_guard: Option<&ProcessSignalInfo>) {
if !self.recalc_sigpending_tsk(siginfo_guard) {
self.flags().remove(ProcessFlags::HAS_PENDING_SIGNAL);
}
}
fn recalc_sigpending_tsk(&self, siginfo_guard: Option<&ProcessSignalInfo>) -> bool {
let mut _siginfo_tmp_guard = None;
let siginfo = if let Some(siginfo_guard) = siginfo_guard {
siginfo_guard
} else {
_siginfo_tmp_guard = Some(self.sig_info_irqsave());
_siginfo_tmp_guard.as_ref().unwrap()
};
return siginfo.do_recalc_sigpending_tsk(self);
}
}
impl ProcessSignalInfo {
fn do_recalc_sigpending_tsk(&self, pcb: &ProcessControlBlock) -> bool {
if has_pending_signals(&self.sig_pending().signal(), self.sig_blocked())
|| has_pending_signals(&self.sig_shared_pending().signal(), self.sig_blocked())
{
pcb.flags().insert(ProcessFlags::HAS_PENDING_SIGNAL);
return true;
}
/*
* We must never clear the flag in another thread, or in current
* when it's possible the current syscall is returning -ERESTART*.
* So we don't clear it here, and only callers who know they should do.
*/
return false;
}
}
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/sched/signal.h?fi=restore_saved_sigmask#547
pub fn restore_saved_sigmask() {
if ProcessManager::current_pcb()
.flags()
.test_and_clear(ProcessFlags::RESTORE_SIG_MASK)
{
let saved = *ProcessManager::current_pcb()
.sig_info_irqsave()
.saved_sigmask();
__set_current_blocked(&saved);
}
}
/// 刷新指定进程的sighand的sigaction将满足条件的sigaction恢复为默认状态。
/// 除非某个信号被设置为忽略且 `force_default` 为 `false`,否则都不会将其恢复。
///
/// @param pcb 要被刷新的pcb
/// @param force_default 是否强制将sigaction恢复成默认状态
/// # 参数
///
/// - `pcb`: 要被刷新的pcb。
/// - `force_default`: 是否强制将sigaction恢复成默认状态。
pub fn flush_signal_handlers(pcb: Arc<ProcessControlBlock>, force_default: bool) {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// debug!("hand=0x{:018x}", hand as *const sighand_struct as usize);
@ -467,7 +526,7 @@ fn __set_task_blocked(pcb: &Arc<ProcessControlBlock>, new_set: &SigSet) {
if pcb.has_pending_signal() {
let mut newblocked = *new_set;
let guard = pcb.sig_info_irqsave();
newblocked.remove(*guard.sig_block());
newblocked.remove(*guard.sig_blocked());
drop(guard);
// 从主线程开始去遍历
@ -476,7 +535,7 @@ fn __set_task_blocked(pcb: &Arc<ProcessControlBlock>, new_set: &SigSet) {
}
}
*pcb.sig_info_mut().sig_block_mut() = *new_set;
recalc_sigpending();
pcb.recalc_sigpending(None);
}
fn __set_current_blocked(new_set: &SigSet) {
@ -485,10 +544,10 @@ fn __set_current_blocked(new_set: &SigSet) {
pcb的sig_blocked和新的相等
sig_blocked字段不能被其他进程修改
*/
if pcb.sig_info_irqsave().sig_block().eq(new_set) {
if pcb.sig_info_irqsave().sig_blocked().eq(new_set) {
return;
}
let guard = pcb.sig_struct_irqsave();
let guard: SpinLockGuard<'_, SignalStruct> = pcb.sig_struct_irqsave();
__set_task_blocked(&pcb, new_set);
@ -560,7 +619,7 @@ pub fn set_current_blocked(new_set: &mut SigSet) {
pub fn set_sigprocmask(how: SigHow, set: SigSet) -> Result<SigSet, SystemError> {
let pcb: Arc<ProcessControlBlock> = ProcessManager::current_pcb();
let guard = pcb.sig_info_irqsave();
let oset = *guard.sig_block();
let oset = *guard.sig_blocked();
let mut res_set = oset;
drop(guard);

View File

@ -75,9 +75,15 @@ pub struct InnerSignalStruct {
impl SignalStruct {
#[inline(never)]
pub fn new() -> Self {
Self {
let mut r = Self {
inner: Box::<InnerSignalStruct>::default(),
}
};
let sig_ign = Sigaction::default();
r.inner.handlers[Signal::SIGCHLD as usize - 1] = sig_ign;
r.inner.handlers[Signal::SIGURG as usize - 1] = sig_ign;
r.inner.handlers[Signal::SIGWINCH as usize - 1] = sig_ign;
r
}
}
@ -447,8 +453,6 @@ impl SigPending {
None
};
// 当一个进程具有多个线程之后在这里需要重新计算线程的flag中的TIF_SIGPENDING位
// recalc_sigpending();
return (sig, info);
}
/// @brief 从sigpending中删除mask中被置位的信号。也就是说比如mask的第1位被置为1,那么就从sigqueue中删除所有signum为2的信号的信息。
@ -539,10 +543,12 @@ impl SigQueue {
pub trait SignalArch {
/// 信号处理函数
///
/// 处理信号或重启系统调用
///
/// ## 参数
///
/// - `frame` 中断栈帧
unsafe fn do_signal(frame: &mut TrapFrame);
unsafe fn do_signal_or_restart(frame: &mut TrapFrame);
fn sys_rt_sigreturn(trap_frame: &mut TrapFrame) -> u64;
}

View File

@ -567,4 +567,10 @@ impl Syscall {
Ok(0)
}
pub fn restart_syscall() -> Result<usize, SystemError> {
// todo: https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/signal.c#2998
unimplemented!("restart_syscall with restart block");
// Err(SystemError::ENOSYS)
}
}

View File

@ -612,6 +612,32 @@ bitflags! {
const NEED_MIGRATE = 1 << 7;
/// 随机化的虚拟地址空间,主要用于动态链接器的加载
const RANDOMIZE = 1 << 8;
/// 进程有未处理的信号(这是一个用于快速判断的标志位)
/// 相当于Linux的TIF_SIGPENDING
const HAS_PENDING_SIGNAL = 1 << 9;
/// 进程需要恢复之前保存的信号掩码
const RESTORE_SIG_MASK = 1 << 10;
}
}
impl ProcessFlags {
pub const fn exit_to_user_mode_work(&self) -> Self {
Self::from_bits_truncate(self.bits & (Self::HAS_PENDING_SIGNAL.bits))
}
/// 测试并清除标志位
///
/// ## 参数
///
/// - `rhs` : 需要测试并清除的标志位
///
/// ## 返回值
///
/// 如果标志位在清除前是置位的,则返回 `true`,否则返回 `false`
pub const fn test_and_clear(&mut self, rhs: Self) -> bool {
let r = (self.bits & rhs.bits) != 0;
self.bits &= !rhs.bits;
r
}
}
#[derive(Debug)]
@ -673,6 +699,7 @@ pub struct ProcessControlBlock {
/// 进程作为主体的凭证集
cred: SpinLock<Cred>,
self_ref: Weak<ProcessControlBlock>,
}
impl ProcessControlBlock {
@ -734,7 +761,7 @@ impl ProcessControlBlock {
let ppcb: Weak<ProcessControlBlock> = ProcessManager::find(ppid)
.map(|p| Arc::downgrade(&p))
.unwrap_or_default();
let pcb = Self {
let mut pcb = Self {
pid,
tgid: pid,
thread_pid: Arc::new(RwLock::new(PidStrcut::new())),
@ -759,6 +786,7 @@ impl ProcessControlBlock {
robust_list: RwLock::new(None),
nsproxy: Arc::new(RwLock::new(NsProxy::new())),
cred: SpinLock::new(cred),
self_ref: Weak::new(),
};
pcb.sig_info.write().set_tty(tty);
@ -769,7 +797,10 @@ impl ProcessControlBlock {
.lock()
.init_syscall_stack(&pcb.syscall_stack.read());
let pcb = Arc::new(pcb);
let pcb = Arc::new_cyclic(|weak| {
pcb.self_ref = weak.clone();
pcb
});
pcb.sched_info()
.sched_entity()
@ -1017,6 +1048,11 @@ impl ProcessControlBlock {
return has_pending;
}
/// 根据 pcb 的 flags 判断当前进程是否有未处理的信号
pub fn has_pending_signal_fast(&self) -> bool {
self.flags.get().contains(ProcessFlags::HAS_PENDING_SIGNAL)
}
pub fn sig_struct(&self) -> SpinLockGuard<SignalStruct> {
self.sig_struct.lock_irqsave()
}
@ -1546,8 +1582,9 @@ pub fn process_init() {
#[derive(Debug)]
pub struct ProcessSignalInfo {
// 当前进程
sig_block: SigSet,
// 当前进程被屏蔽的信号
sig_blocked: SigSet,
saved_sigmask: SigSet,
// sig_pending 中存储当前线程要处理的信号
sig_pending: SigPending,
// sig_shared_pending 中存储当前线程所属进程要处理的信号
@ -1557,8 +1594,8 @@ pub struct ProcessSignalInfo {
}
impl ProcessSignalInfo {
pub fn sig_block(&self) -> &SigSet {
&self.sig_block
pub fn sig_blocked(&self) -> &SigSet {
&self.sig_blocked
}
pub fn sig_pending(&self) -> &SigPending {
@ -1570,7 +1607,15 @@ impl ProcessSignalInfo {
}
pub fn sig_block_mut(&mut self) -> &mut SigSet {
&mut self.sig_block
&mut self.sig_blocked
}
pub fn saved_sigmask(&self) -> &SigSet {
&self.saved_sigmask
}
pub fn saved_sigmask_mut(&mut self) -> &mut SigSet {
&mut self.saved_sigmask
}
pub fn sig_shared_pending_mut(&mut self) -> &mut SigPending {
@ -1595,12 +1640,19 @@ impl ProcessSignalInfo {
///
/// - `sig_mask` 被忽略掉的信号
///
pub fn dequeue_signal(&mut self, sig_mask: &SigSet) -> (Signal, Option<SigInfo>) {
pub fn dequeue_signal(
&mut self,
sig_mask: &SigSet,
pcb: &Arc<ProcessControlBlock>,
) -> (Signal, Option<SigInfo>) {
let res = self.sig_pending.dequeue_signal(sig_mask);
pcb.recalc_sigpending(Some(self));
if res.0 != Signal::INVALID {
return res;
} else {
return self.sig_shared_pending.dequeue_signal(sig_mask);
let res = self.sig_shared_pending.dequeue_signal(sig_mask);
pcb.recalc_sigpending(Some(self));
return res;
}
}
}
@ -1608,7 +1660,8 @@ impl ProcessSignalInfo {
impl Default for ProcessSignalInfo {
fn default() -> Self {
Self {
sig_block: SigSet::empty(),
sig_blocked: SigSet::empty(),
saved_sigmask: SigSet::empty(),
sig_pending: SigPending::default(),
sig_shared_pending: SigPending::default(),
tty: None,

View File

@ -1217,6 +1217,7 @@ impl Syscall {
Self::sys_perf_event_open(attr, pid, cpu, group_fd, flags)
}
SYS_SETRLIMIT => Ok(0),
SYS_RESTART_SYSCALL => Self::restart_syscall(),
_ => panic!("Unsupported syscall ID: {}", syscall_num),
};

View File

@ -62,9 +62,11 @@ int main() {
perror("signal");
exit(EXIT_FAILURE);
}
printf("Signal handler for SIGINT is registered.\n");
signal_received = 0;
kill(getpid(), SIGINT);
sleep(5);
TEST_ASSERT(signal_received, 1, "SIGINT was received", "SIGINT was not received");
signal_received = 0;

View File

@ -0,0 +1 @@
test_signal

View File

@ -0,0 +1,20 @@
ifeq ($(ARCH), x86_64)
CROSS_COMPILE=x86_64-linux-musl-
else ifeq ($(ARCH), riscv64)
CROSS_COMPILE=riscv64-linux-musl-
endif
CC=$(CROSS_COMPILE)gcc
.PHONY: all
all: main.c
$(CC) -static -o test_signal_restart main.c
.PHONY: install clean
install: all
mv test_signal_restart $(DADK_CURRENT_BUILD_DIR)/test_signal_restart
clean:
rm test_signal_restart *.o
fmt:

View File

@ -0,0 +1,106 @@
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#define BUFFER_SIZE 1024
#define MSG "Hello from parent!\n"
static int handled_signal = 0;
// 子进程的信号处理函数
void child_signal_handler(int sig) {
printf("Child received signal %d\n", sig);
handled_signal = 1;
}
// 父进程的信号处理函数
void parent_signal_handler(int sig) {
printf("Parent received signal %d\n", sig);
}
int main() {
int pipefd[2];
pid_t pid;
char buffer[BUFFER_SIZE];
// 创建管道
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
// 创建子进程
pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0) {
// 子进程
close(pipefd[1]); // 关闭写端
// 设置子进程的信号处理函数
signal(SIGUSR1, child_signal_handler);
printf("Child: Waiting for data...\n");
// 尝试从管道中读取数据
ssize_t bytes_read = read(pipefd[0], buffer, BUFFER_SIZE - 1);
if (bytes_read == -1) {
printf("[FAILED]: Child: read error, errno=%d\n", errno);
exit(EXIT_FAILURE);
} else if (bytes_read == 0) {
printf("Child: End of file\n");
}
if (bytes_read != sizeof(MSG) - 1) {
printf("[FAILED]: Child: read error: got %ld bytes, expected %ld\n",
bytes_read, sizeof(MSG) - 1);
} else {
printf("[PASS]: Child: read success: got %ld bytes, expected %ld\n",
bytes_read, sizeof(MSG) - 1);
}
buffer[bytes_read] = '\0';
printf("Child: Received message: %s", buffer);
close(pipefd[0]);
if (!handled_signal)
printf("[FAILED]: Parent: child did not handle signal\n");
else
printf("[PASS]: Parent: child handled signal\n");
exit(EXIT_SUCCESS);
} else {
// 父进程
close(pipefd[0]); // 关闭读端
// 设置父进程的信号处理函数
signal(SIGCHLD, parent_signal_handler);
// 发送信号给子进程,中断它的读操作
sleep(1); // 确保子进程已经开始读取
// printf("Parent: Sending SIGCHLD to child...\n");
// kill(pid, SIGCHLD);
printf("Parent: Sending SIGUSR1 to child...\n");
kill(pid, SIGUSR1);
sleep(1); // 确保子进程已经处理了信号
write(pipefd[1], MSG, strlen(MSG));
printf("Parent: Sent message: %s", MSG);
// 等待子进程结束
waitpid(pid, NULL, 0);
printf("Parent: Child process finished.\n");
close(pipefd[1]);
exit(EXIT_SUCCESS);
}
}

View File

@ -0,0 +1,41 @@
# 用户程序名称
name = "test_signal_restart"
# 版本号
version = "0.1.0"
# 用户程序描述信息
description = "一个用来测试signal能够正常运行的app"
# (可选)默认: false 是否只构建一次如果为trueDADK会在构建成功后将构建结果缓存起来下次构建时直接使用缓存的构建结果
build-once = false
# (可选) 默认: false 是否只安装一次如果为trueDADK会在安装成功后不再重复安装
install-once = false
# 目标架构
# 可选值:"x86_64", "aarch64", "riscv64"
target-arch = ["x86_64"]
# 任务源
[task-source]
# 构建类型
# 可选值:"build-from_source", "install-from-prebuilt"
type = "build-from-source"
# 构建来源
# "build_from_source" 可选值:"git", "local", "archive"
# "install_from_prebuilt" 可选值:"local", "archive"
source = "local"
# 路径或URL
source-path = "user/apps/test_signal_restart"
# 构建相关信息
[build]
# (可选)构建命令
build-command = "make install"
# 安装相关信息
[install]
# 可选安装到DragonOS的路径
in-dragonos-path = "/bin"
# 清除相关信息
[clean]
# (可选)清除命令
clean-command = "make clean"
# (可选)依赖项
# 注意:如果没有依赖项,忽略此项,不允许只留一个[[depends]]
# 由于原文件中依赖项为空,此处省略[[depends]]部分
# (可选)环境变量
# 由于原文件中环境变量为空,此处省略[[envs]]部分