Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 57 additions & 15 deletions kernel/src/ipc/signal.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::{
fmt::Debug,
intrinsics::unlikely,
sync::atomic::{compiler_fence, Ordering},
};

Expand All @@ -9,18 +10,17 @@ use system_error::SystemError;

use crate::{
arch::ipc::signal::{SigSet, Signal},
ipc::signal_types::SigCode,
ipc::signal_types::SigactionType,
ipc::signal_types::{
SigCode, SigInfo, SigType, SigactionType, SignalFlags, SIG_KERNEL_IGNORE_MASK,
SIG_KERNEL_ONLY_MASK, SIG_KERNEL_STOP_MASK,
},
mm::VirtAddr,
process::{
pid::PidType, ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSignalInfo, RawPid,
},
time::{syscall::PosixClockID, timekeeping::getnstimeofday, Instant, PosixTimeSpec},
};

use super::signal_types::{SigInfo, SigType, SIG_KERNEL_STOP_MASK};
use crate::ipc::signal_types::SignalFlags;

impl Signal {
pub fn signal_pending_state(
interruptible: bool,
Expand Down Expand Up @@ -293,6 +293,57 @@ impl Signal {
// todo: 参照linux的sig_fatal实现完整功能
}

/// @brief 检查pcb状态、Init 属性、Handler 设置
fn sig_task_ignored(&self, pcb: &Arc<ProcessControlBlock>, force: bool) -> bool {
// init 进程忽略 SIGKILL 和 SIGSTOP,防止系统意外崩溃。
if unlikely(pcb.raw_pid().data() == 1) && SIG_KERNEL_ONLY_MASK.contains(self.into_sigset())
{
return true;
}
let sighand = pcb.sighand();
if let Some(sa) = sighand.handler(*self) {
// 容器中的 init 进程 或者 被标记为 UNKILLABLE 的进程,如果Handler为默认且不是强制发送,永远不能忽略 SIGKILL 和 SIGSTOP
let is_dfl = sa.is_default();
if unlikely(sighand.flags_contains(SignalFlags::UNKILLABLE))
&& is_dfl
&& !(force && SIG_KERNEL_ONLY_MASK.contains(self.into_sigset()))
{
return true;
}
// sig_handler_ignored() 检查是否被设置为 IGNORE
if sa.is_ignore() || (is_dfl && SIG_KERNEL_IGNORE_MASK.contains(self.into_sigset())) {
return true;
}
}
false
}

/// @brief 判断信号是否应该被忽略
fn sig_ignored(&self, pcb: &Arc<ProcessControlBlock>, force: bool) -> bool {
// 即使信号处理函数是 IGN,如果该信号被阻塞,它也必须留在队列中,直到解除了阻塞(此时 handler 可能已经变了)。
let sig_info = pcb.sig_info_irqsave();
if sig_info.sig_blocked().contains(self.into_sigset())
|| (pcb.flags().contains(ProcessFlags::RESTORE_SIG_MASK)
&& sig_info.saved_sigmask().contains(self.into_sigset()))
{
// log::debug!(
// "sig_ignored: signal {:?} is blocked, current sigblocked={:b}, saved_sigmask={:b}",
// self,
// sig_info.sig_blocked().bits(),
// sig_info.saved_sigmask().bits()
// );
return false;
}
drop(sig_info);

// TODO: ptrace 拦截被忽略的信号
// if pcb.flags().contains(ProcessFlags::PTRACED) && *self != Signal::SIGKILL {
// return false;
// }

Self::sig_task_ignored(self, pcb, force)
}

/// 检查信号是否能被发送,并且而且要处理 SIGCONT 和 STOP 信号
///
/// ## 参数
Expand Down Expand Up @@ -356,17 +407,8 @@ impl Signal {
// TODO 对每个子线程 flush mask;对齐 Linux 更完整语义
}

// 一个被阻塞了的信号肯定是要被处理的
if pcb
.sig_info_irqsave()
.sig_blocked()
.contains(self.into_sigset())
{
return true;
}
return !pcb.sighand().handler(*self).unwrap().is_ignore();

//TODO 仿照 linux 中的prepare signal完善逻辑,linux 中还会根据例如当前进程状态(Existing)进行判断,现在的信号能否发出就只是根据 ignored 来判断
return !self.sig_ignored(&pcb, _force);
}
}

Expand Down
30 changes: 18 additions & 12 deletions kernel/src/ipc/signal_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ pub const USER_SIG_ERR: u64 = 2;

// 因为 Rust 编译器不能在常量声明中正确识别级联的 "|" 运算符(experimental feature: https://github.com/rust-lang/rust/issues/67792),因此
// 暂时只能通过这种方法来声明这些常量,这些常量暂时没有全部用到,但是都出现在 linux 的判断逻辑中,所以都保留下来了
#[allow(dead_code)]
pub const SIG_KERNEL_ONLY_MASK: SigSet =
Signal::into_sigset(Signal::SIGSTOP).union(Signal::into_sigset(Signal::SIGKILL));

Expand All @@ -83,8 +82,13 @@ pub const SIG_KERNEL_COREDUMP_MASK: SigSet = Signal::into_sigset(Signal::SIGQUIT
.union(Signal::into_sigset(Signal::SIGSYS))
.union(Signal::into_sigset(Signal::SIGXCPU))
.union(Signal::into_sigset(Signal::SIGXFSZ));
#[allow(dead_code)]

pub const SIG_KERNEL_IGNORE_MASK: SigSet = Signal::into_sigset(Signal::SIGCONT)
.union(Signal::into_sigset(Signal::SIGCHLD))
.union(Signal::into_sigset(Signal::SIGWINCH))
.union(Signal::into_sigset(Signal::SIGURG));
#[allow(dead_code)]
pub const SIG_SPECIFIC_SICODES_MASK: SigSet = Signal::into_sigset(Signal::SIGILL)
.union(Signal::into_sigset(Signal::SIGFPE))
.union(Signal::into_sigset(Signal::SIGSEGV))
.union(Signal::into_sigset(Signal::SIGBUS))
Expand All @@ -111,6 +115,12 @@ pub enum SigactionType {
}

impl SigactionType {
/// Returns `true` if the sa handler type is [`Self::SaHandler(SaHandlerType::Default)`].
///
/// [`SigDefault`]: SaHandlerType::SigDefault
pub fn is_default(&self) -> bool {
return matches!(self, Self::SaHandler(SaHandlerType::Default));
}
/// Returns `true` if the sa handler type is [`SaHandler(SaHandlerType::SigIgnore)`].
///
/// [`SigIgnore`]: SaHandlerType::SigIgnore
Expand Down Expand Up @@ -191,19 +201,15 @@ impl Default for Sigaction {
}

impl Sigaction {
/// 判断传入的信号是否被设置为默认处理
pub fn is_default(&self) -> bool {
return self.action.is_default();
}
/// 判断传入的信号是否被忽略
///
/// ## 参数
///
/// - `sig` 传入的信号
///
/// ## 返回值
///
/// - `true` 被忽略
/// - `false`未被忽略
pub fn is_ignore(&self) -> bool {
return self.action.is_ignore();
}

pub fn new(
action: SigactionType,
flags: SigFlags,
Expand Down Expand Up @@ -580,7 +586,7 @@ impl SigPending {
/// @brief 从sigpending中删除mask中被置位的信号。也就是说,比如mask的第1位被置为1,那么就从sigqueue中删除所有signum为2的信号的信息。
pub fn flush_by_mask(&mut self, mask: &SigSet) {
// 定义过滤器,从sigqueue中删除mask中被置位的信号
let filter = |x: &SigInfo| !mask.contains(SigSet::from_bits_truncate(x.sig_no as u64));
let filter = |x: &SigInfo| !mask.contains(Signal::from(x.sig_no as usize).into());
self.queue.q.retain(filter);
// 同步清理位图中的相应位,避免仅删除队列项但仍因位图残留被视为pending
self.signal.remove(*mask);
Expand Down
4 changes: 3 additions & 1 deletion kernel/src/ipc/syscall/sys_rt_sigtimedwait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,10 @@ pub fn do_kernel_rt_sigtimedwait(
let pcb = ProcessManager::current_pcb();
let mut new_blocked = *pcb.sig_info_irqsave().sig_blocked();
// 按Linux:等待期间屏蔽 these
new_blocked.insert(awaited);
new_blocked.remove(awaited);
set_user_sigmask(&mut new_blocked);
// 必须重新计算 pending,因为 blocked 变了,可能某些 pending 信号现在变得可见了
pcb.recalc_sigpending(None);

// 计算超时时间
let deadline = if uts.is_null() {
Expand Down
Loading
Loading