Signal refactor (#402)

* 初步完成对 signal_types 和 部分signal代码的初始化

* 重构了一部分架构相关代码进入 arch 中

* 基本修改完成,编译通过,后续补上系统调用

* signal基本完成,能实现 Sigaction 系统调用

* 增加了一组枚举抽象

* 进一步重构了一部分C风格的代码

* 继续重构了一部分C风格代码

* 继续完善了一部分逻辑

* 修改了部分代码逻辑

* 补充了 fork 中复制信号信息的逻辑

* 修复了 kallsysms 未转义引号的问题

* 修复了无法跳转到 sigreturn 的bug

* 调通了 signal

* 实现了 signal 架构抽象层的 trait

* 为信号提供了默认处理函数

* 基本完成了 signal 的大体逻辑

* 修复了 Sigreturn 的一个小错误,格式化

* 修复了一个编译器漏报错误

* 删除了多余的代码

* 修改测试程序为链接 relibc

* 修复了信号处理过程中浮点寄存器错误保存的问题

* 修复了一个结构体错误引起的无法在relibc下正确运行的错误

* 修复了链接 relibc 时无法正常从信号处理返回的 bug

* 修复了 signal 处理流程中 rsp 指针错误导致的浮点运算触发GP

* 修复了一个死锁问题,解决了默认处理函数无法进入调度导致的bug

* 修复了一些错误

* 修改了 relibc 依赖版本号

* 删除了多余的 imports

* 删除一些debug日志

* 删除内核 signal.h 文件

* 删除一个依赖项

* 删除了 binding 相关依赖项
This commit is contained in:
Chiichen
2023-10-24 12:02:20 +08:00
committed by GitHub
parent d7f5742a20
commit 3c82aa56d1
29 changed files with 2353 additions and 261 deletions

View File

@ -1,2 +1,4 @@
pub mod pipe;
pub mod signal;
pub mod signal_types;
pub mod syscall;

416
kernel/src/ipc/signal.rs Normal file
View File

@ -0,0 +1,416 @@
use core::sync::atomic::compiler_fence;
use alloc::sync::Arc;
use crate::{
arch::ipc::signal::{SigCode, SigFlags, SigSet, Signal},
ipc::signal_types::SigactionType,
kwarn,
libs::spinlock::SpinLockGuard,
process::{pid::PidType, Pid, ProcessControlBlock, ProcessFlags, ProcessManager},
syscall::SystemError,
};
use super::signal_types::{
SaHandlerType, SigInfo, SigType, Sigaction, SignalStruct, SIG_KERNEL_STOP_MASK,
};
impl Signal {
/// 向目标进程发送信号
///
/// ## 参数
///
/// - `sig` 要发送的信号
/// - `info` 要发送的信息
/// - `pid` 进程id目前只支持pid>0)
pub fn send_signal_info(
&self,
info: Option<&mut SigInfo>,
pid: Pid,
) -> Result<i32, SystemError> {
// TODO:暂时不支持特殊的信号操作,待引入进程组后补充
// 如果 pid 大于 0那么会发送信号给 pid 指定的进程
// 如果 pid 等于 0那么会发送信号给与调用进程同组的每个进程包括调用进程自身
// 如果 pid 小于 -1那么会向组 ID 等于该 pid 绝对值的进程组内所有下属进程发送信号。向一个进程组的所有进程发送信号在 shell 作业控制中有特殊有途
// 如果 pid 等于 -1那么信号的发送范围是调用进程有权将信号发往的每个目标进程除去 init进程 ID 为 1和调用进程自身。如果特权级进程发起这一调用那么会发送信号给系统中的所有进程上述两个进程除外。显而易见有时也将这种信号发送方式称之为广播信号
// 如果并无进程与指定的 pid 相匹配,那么 kill() 调用失败,同时将 errno 置为 ESRCH“查无此进程”
if pid.lt(&Pid::from(0)) {
kwarn!("Kill operation not support: pid={:?}", pid);
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 检查sig是否符合要求如果不符合要求则退出。
if !self.is_valid() {
return Err(SystemError::EINVAL);
}
let mut retval = Err(SystemError::ESRCH);
let pcb = ProcessManager::find(pid);
if pcb.is_none() {
kwarn!("No such process.");
return retval;
}
// println!("Target pcb = {:?}", pcb.as_ref().unwrap());
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 发送信号
retval = self.send_signal(info, pcb.unwrap(), PidType::PID);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return retval;
}
/// @brief 判断是否需要强制发送信号,然后发送信号
/// 进入函数后加锁
///
/// @return SystemError 错误码
fn send_signal(
&self,
info: Option<&mut SigInfo>,
pcb: Arc<ProcessControlBlock>,
pt: PidType,
) -> Result<i32, SystemError> {
// 是否强制发送信号
let mut force_send = false;
// signal的信息为空
if let Some(ref siginfo) = info {
force_send = matches!(siginfo.sig_code(), SigCode::Kernel);
} else {
// todo: 判断signal是否来自于一个祖先进程的namespace如果是则强制发送信号
//详见 https://opengrok.ringotek.cn/xref/linux-6.1.9/kernel/signal.c?r=&mo=32170&fi=1220#1226
}
if !self.prepare_sianal(pcb.clone(), force_send) {
return Err(SystemError::EINVAL);
}
// kdebug!("force send={}", force_send);
let pcb_info = pcb.sig_info();
let pending = if matches!(pt, PidType::PID) {
pcb_info.sig_shared_pending()
} else {
pcb_info.sig_pending()
};
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 如果是kill或者目标pcb是内核线程则无需获取sigqueue直接发送信号即可
if matches!(self, Signal::SIGKILL) || pcb.flags().contains(ProcessFlags::KTHREAD) {
//避免死锁
drop(pcb_info);
self.complete_signal(pcb.clone(), pt);
}
// 如果不是实时信号的话,同一时刻信号队列里只会有一个待处理的信号,如果重复接收就不做处理
else if !self.is_rt_signal() && pending.queue().find(self.clone()).0.is_some() {
return Ok(0);
} else {
// TODO signalfd_notify 完善 signalfd 机制
// 如果是其他信号则加入到sigqueue内然后complete_signal
let new_sig_info = match info {
Some(siginfo) => {
// 已经显式指定了siginfo则直接使用它。
(*siginfo).clone()
}
None => {
// 不需要显示指定siginfo因此设置为默认值
SigInfo::new(
self.clone(),
0,
SigCode::User,
SigType::Kill(ProcessManager::current_pcb().pid()),
)
}
};
drop(pcb_info);
pcb.sig_info_mut()
.sig_pending_mut()
.queue_mut()
.q
.push(new_sig_info);
if pt == PidType::PGID || pt == PidType::SID {}
self.complete_signal(pcb.clone(), pt);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return Ok(0);
}
/// @brief 将信号添加到目标进程的sig_pending。在引入进程组后本函数还将负责把信号传递给整个进程组。
///
/// @param sig 信号
/// @param pcb 目标pcb
/// @param pt siginfo结构体中pid字段代表的含义
fn complete_signal(&self, pcb: Arc<ProcessControlBlock>, pt: PidType) {
// kdebug!("complete_signal");
// todo: 将信号产生的消息通知到正在监听这个信号的进程引入signalfd之后在这里调用signalfd_notify)
// 将这个信号加到目标进程的sig_pending中
pcb.sig_info_mut()
.sig_pending_mut()
.signal_mut()
.insert(self.clone().into());
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// ===== 寻找需要wakeup的目标进程 =====
// 备注由于当前没有进程组的概念每个进程只有1个对应的线程因此不需要通知进程组内的每个进程。
// todo: 当引入进程组的概念后,需要完善这里,使得它能寻找一个目标进程来唤醒,接着执行信号处理的操作。
// let _signal = pcb.sig_struct();
let mut _target: Option<Arc<ProcessControlBlock>> = None;
// 判断目标进程是否想接收这个信号
if self.wants_signal(pcb.clone()) {
_target = Some(pcb.clone());
} else if pt == PidType::PID {
/*
* There is just one thread and it does not need to be woken.
* It will dequeue unblocked signals before it runs again.
*/
return;
} else {
/*
* Otherwise try to find a suitable thread.
* 由于目前每个进程只有1个线程因此当前情况可以返回。信号队列的dequeue操作不需要考虑同步阻塞的问题。
*/
return;
}
// TODO:引入进程组后,在这里挑选一个进程来唤醒,让它执行相应的操作。
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// TODO: 到这里信号已经被放置在共享的pending队列中我们在这里把目标进程唤醒。
if _target.is_some() {
let guard = pcb.sig_struct();
signal_wake_up(pcb.clone(), guard, *self == Signal::SIGKILL);
}
}
/// @brief 本函数用于检测指定的进程是否想要接收SIG这个信号。
/// 当我们对于进程组中的所有进程都运行了这个检查之后,我们将可以找到组内愿意接收信号的进程。
/// 这么做是为了防止我们把信号发送给了一个正在或已经退出的进程,或者是不响应该信号的进程。
#[inline]
fn wants_signal(&self, pcb: Arc<ProcessControlBlock>) -> bool {
// 如果改进程屏蔽了这个signal则不能接收
if pcb.sig_info().sig_block().contains(self.clone().into()) {
return false;
}
// 如果进程正在退出,则不能接收信号
if pcb.flags().contains(ProcessFlags::EXITING) {
return false;
}
if *self == Signal::SIGKILL {
return true;
}
if pcb.sched_info().state().is_blocked() {
return false;
}
// todo: 检查目标进程是否正在一个cpu上执行如果是则返回true否则继续检查下一项
// 检查目标进程是否有信号正在等待处理如果是则返回false否则返回true
if pcb.sig_info().sig_pending().signal().bits() == 0 {
assert!(pcb.sig_info().sig_pending().queue().q.is_empty());
return true;
} else {
return false;
}
}
/// @brief 判断signal的处理是否可能使得整个进程组退出
/// @return true 可能会导致退出(不一定)
#[allow(dead_code)]
#[inline]
fn sig_fatal(&self, pcb: Arc<ProcessControlBlock>) -> bool {
let action = pcb.sig_struct().handlers[self.clone() as usize - 1].action();
// 如果handler是空采用默认函数signal处理可能会导致进程退出。
match action {
SigactionType::SaHandler(handler) => handler.is_sig_default(),
SigactionType::SaSigaction(sigaction) => sigaction.is_none(),
}
// todo: 参照linux的sig_fatal实现完整功能
}
/// 检查信号是否能被发送,并且而且要处理 SIGCONT 和 STOP 信号
///
/// ## 参数
///
/// - `pcb` 要发送信号的目标pcb
///
/// - `force` 是否强制发送(指走 fast path 不加入 sigpending按顺序处理直接进入 complete_signal)
///
/// ## 返回值
///
/// - `true` 能够发送信号
///
/// - `false` 不能发送信号
fn prepare_sianal(&self, pcb: Arc<ProcessControlBlock>, _force: bool) -> bool {
let flush: SigSet;
if !(self.into_sigset() & SIG_KERNEL_STOP_MASK).is_empty() {
flush = Signal::SIGCONT.into_sigset();
pcb.sig_info_mut()
.sig_shared_pending_mut()
.flush_by_mask(&flush);
// TODO 对每个子线程 flush mask
} else if *self == Signal::SIGCONT {
flush = SIG_KERNEL_STOP_MASK;
assert!(!flush.is_empty());
pcb.sig_info_mut()
.sig_shared_pending_mut()
.flush_by_mask(&flush);
let _r = ProcessManager::wakeup_stop(&pcb);
// TODO 对每个子线程 flush mask
// 这里需要补充一段逻辑详见https://opengrok.ringotek.cn/xref/linux-6.1.9/kernel/signal.c#952
}
// 一个被阻塞了的信号肯定是要被处理的
if pcb.sig_info().sig_block().contains(self.into_sigset()) {
return true;
}
return !pcb.sig_struct().handlers[self.clone() as usize - 1].is_ignore();
//TODO 仿照 linux 中的prepare signal完善逻辑linux 中还会根据例如当前进程状态(Existing)进行判断,现在的信号能否发出就只是根据 ignored 来判断
}
}
/// 因收到信号而唤醒进程
///
/// ## 参数
///
/// - `pcb` 要唤醒的进程pcb
/// - `_guard` 信号结构体锁守卫,来保证信号结构体已上锁
/// - `fatal` 表明这个信号是不是致命的(会导致进程退出)
#[inline]
fn signal_wake_up(pcb: Arc<ProcessControlBlock>, _guard: SpinLockGuard<SignalStruct>, fatal: bool) {
// 如果是 fatal 的话就唤醒 stop 和 block 的进程来响应,因为唤醒后就会终止
// 如果不是 fatal 的就只唤醒 stop 的进程来响应
// kdebug!("signal_wake_up");
// 如果目标进程已经在运行则发起一个ipi使得它陷入内核
let r = ProcessManager::wakeup_stop(&pcb);
if r.is_ok() {
ProcessManager::kick(&pcb);
} else {
if fatal {
let _r = ProcessManager::wakeup(&pcb).map(|_| {
ProcessManager::kick(&pcb);
});
}
}
}
/// @brief 当一个进程具有多个线程之后在这里需要重新计算线程的flag中的TIF_SIGPENDING位
fn recalc_sigpending() {
// todo:
}
/// @brief 刷新指定进程的sighand的sigaction将满足条件的sigaction恢复为Default
/// 除非某个信号被设置为ignore且force_default为false否则都不会将其恢复
///
/// @param pcb 要被刷新的pcb
/// @param force_default 是否强制将sigaction恢复成默认状态
pub fn flush_signal_handlers(pcb: Arc<ProcessControlBlock>, force_default: bool) {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// kdebug!("hand=0x{:018x}", hand as *const sighand_struct as usize);
let actions = &mut pcb.sig_struct().handlers;
for sigaction in actions.iter_mut() {
if force_default || !sigaction.is_ignore() {
sigaction.set_action(SigactionType::SaHandler(SaHandlerType::SigDefault));
}
// 清除flags中除了DFL和IGN以外的所有标志
sigaction.set_restorer(None);
sigaction.mask_mut().remove(SigSet::all());
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
pub(super) fn do_sigaction(
sig: Signal,
act: Option<&mut Sigaction>,
old_act: Option<&mut Sigaction>,
) -> Result<(), SystemError> {
if sig == Signal::INVALID {
return Err(SystemError::EINVAL);
}
let pcb = ProcessManager::current_pcb();
// 指向当前信号的action的引用
let action: &mut Sigaction = &mut pcb.sig_struct().handlers[sig as usize - 1];
// 对比 MUSL 和 relibc 暂时不设置这个标志位
// if action.flags().contains(SigFlags::SA_FLAG_IMMUTABLE) {
// return Err(SystemError::EINVAL);
// }
// 保存原有的 sigaction
let old_act: Option<&mut Sigaction> = {
if old_act.is_some() {
let oa = old_act.unwrap();
*(oa) = (*action).clone();
Some(oa)
} else {
None
}
};
// 清除所有的脏的sa_flags位也就是清除那些未使用的
let act = {
if act.is_some() {
let ac = act.unwrap();
*ac.flags_mut() &= SigFlags::SA_ALL;
Some(ac)
} else {
None
}
};
if old_act.is_some() {
*old_act.unwrap().flags_mut() &= SigFlags::SA_ALL;
}
if act.is_some() {
let ac = act.unwrap();
// 将act.sa_mask的SIGKILL SIGSTOP的屏蔽清除
ac.mask_mut()
.remove(SigSet::from(Signal::SIGKILL.into()) | SigSet::from(Signal::SIGSTOP.into()));
// 将新的sigaction拷贝到进程的action中
*action = *ac;
/*
* 根据POSIX 3.3.1.3规定:
* 1.不管一个信号是否被阻塞只要将其设置SIG_IGN如果当前已经存在了正在pending的信号那么就把这个信号忽略。
*
* 2.不管一个信号是否被阻塞只要将其设置SIG_DFL如果当前已经存在了正在pending的信号
并且对这个信号的默认处理方式是忽略它那么就会把pending的信号忽略。
*/
if action.is_ignore() {
let mut mask: SigSet = SigSet::from_bits_truncate(0);
mask.insert(sig.into());
pcb.sig_info_mut().sig_pending_mut().flush_by_mask(&mask);
// todo: 当有了多个线程后在这里进行操作把每个线程的sigqueue都进行刷新
}
}
return Ok(());
}
/// 设置当前进程的屏蔽信号 (sig_block),待引入 [sigprocmask](https://man7.org/linux/man-pages/man2/sigprocmask.2.html) 系统调用后要删除这个散装函数
///
/// ## 参数
///
/// - `new_set` 新的屏蔽信号bitmap的值
pub fn set_current_sig_blocked(new_set: &mut SigSet) {
new_set.remove(SigSet::from(Signal::SIGKILL.into()) | SigSet::from(Signal::SIGSTOP.into()));
//TODO 把这个散装函数用 sigsetops 替换掉
let pcb = ProcessManager::current_pcb();
/*
如果当前pcb的sig_blocked和新的相等那么就不用改变它。
请注意一个进程的sig_blocked字段不能被其他进程修改
*/
if pcb.sig_info().sig_block().eq(new_set) {
return;
}
let guard = pcb.sig_struct_irq();
// todo: 当一个进程有多个线程后在这里需要设置每个线程的block字段并且 retarget_shared_pending虽然我还没搞明白linux这部分是干啥的
// 设置当前进程的sig blocked
*pcb.sig_info_mut().sig_block_mut() = *new_set;
recalc_sigpending();
drop(guard);
}

View File

@ -0,0 +1,529 @@
use core::{ffi::c_void, mem::size_of, sync::atomic::AtomicI64};
use alloc::vec::Vec;
use crate::{
arch::{
asm::bitops::ffz,
interrupt::TrapFrame,
ipc::signal::{SigCode, SigFlags, SigSet, Signal, MAX_SIG_NUM},
},
mm::VirtAddr,
process::Pid,
syscall::{user_access::UserBufferWriter, SystemError},
};
/// 用户态程序传入的SIG_DFL的值
pub const USER_SIG_DFL: u64 = 0;
/// 用户态程序传入的SIG_IGN的值
pub const USER_SIG_IGN: u64 = 1;
/// 用户态程序传入的SIG_ERR的值
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));
pub const SIG_KERNEL_STOP_MASK: SigSet = Signal::into_sigset(Signal::SIGSTOP)
.union(Signal::into_sigset(Signal::SIGTSTP))
.union(Signal::into_sigset(Signal::SIGTTIN))
.union(Signal::into_sigset(Signal::SIGTTOU));
#[allow(dead_code)]
pub const SIG_KERNEL_COREDUMP_MASK: SigSet = Signal::into_sigset(Signal::SIGQUIT)
.union(Signal::into_sigset(Signal::SIGILL))
.union(Signal::into_sigset(Signal::SIGTRAP))
.union(Signal::into_sigset(Signal::SIGABRT_OR_IOT))
.union(Signal::into_sigset(Signal::SIGFPE))
.union(Signal::into_sigset(Signal::SIGSEGV))
.union(Signal::into_sigset(Signal::SIGBUS))
.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::SIGFPE))
.union(Signal::into_sigset(Signal::SIGSEGV))
.union(Signal::into_sigset(Signal::SIGBUS))
.union(Signal::into_sigset(Signal::SIGTRAP))
.union(Signal::into_sigset(Signal::SIGCHLD))
.union(Signal::into_sigset(Signal::SIGIO_OR_POLL))
.union(Signal::into_sigset(Signal::SIGSYS));
/// SignalStruct 在 pcb 中加锁
#[derive(Debug)]
pub struct SignalStruct {
pub cnt: AtomicI64,
/// 如果对应linux这部分会有一个引用计数但是没发现在哪里有用到需要计算引用的地方因此
/// 暂时删掉不然这个Arc会导致其他地方的代码十分丑陋
pub handlers: [Sigaction; MAX_SIG_NUM as usize],
}
impl Default for SignalStruct {
fn default() -> Self {
Self {
cnt: Default::default(),
handlers: [Sigaction::default(); MAX_SIG_NUM as usize],
}
}
}
#[derive(Debug, Copy, Clone)]
#[allow(dead_code)]
pub enum SigactionType {
SaHandler(SaHandlerType),
SaSigaction(
Option<
unsafe extern "C" fn(
sig: ::core::ffi::c_int,
sinfo: *mut SigInfo,
arg1: *mut ::core::ffi::c_void,
),
>,
), // 暂时没有用上
}
impl SigactionType {
/// Returns `true` if the sa handler type is [`SaHandler(SaHandlerType::SigIgnore)`].
///
/// [`SigIgnore`]: SaHandlerType::SigIgnore
pub fn is_ignore(&self) -> bool {
return matches!(self, Self::SaHandler(SaHandlerType::SigIgnore));
}
/// Returns `true` if the sa handler type is [`SaHandler(SaHandlerType::SigCustomized(_))`].
///
/// [`SigCustomized`]: SaHandlerType::SigCustomized(_)
pub fn is_customized(&self) -> bool {
return matches!(self, Self::SaHandler(SaHandlerType::SigCustomized(_)));
}
}
#[derive(Debug, Copy, Clone)]
#[allow(dead_code)]
pub enum SaHandlerType {
SigError, // 暂时没有用上
SigDefault,
SigIgnore,
SigCustomized(VirtAddr),
}
impl Into<usize> for SaHandlerType {
fn into(self) -> usize {
match self {
Self::SigError => 2 as usize,
Self::SigIgnore => 1 as usize,
Self::SigDefault => 0 as usize,
Self::SigCustomized(handler) => handler.data(),
}
}
}
impl SaHandlerType {
/// Returns `true` if the sa handler type is [`SigDefault`].
///
/// [`SigDefault`]: SaHandlerType::SigDefault
pub fn is_sig_default(&self) -> bool {
matches!(self, Self::SigDefault)
}
/// Returns `true` if the sa handler type is [`SigIgnore`].
///
/// [`SigIgnore`]: SaHandlerType::SigIgnore
pub fn is_sig_ignore(&self) -> bool {
matches!(self, Self::SigIgnore)
}
/// Returns `true` if the sa handler type is [`SigError`].
///
/// [`SigError`]: SaHandlerType::SigError
pub fn is_sig_error(&self) -> bool {
matches!(self, Self::SigError)
}
}
/// 信号处理结构体
///
#[derive(Debug, Copy, Clone)]
pub struct Sigaction {
action: SigactionType,
flags: SigFlags,
mask: SigSet, // 为了可扩展性而设置的sa_mask
/// 信号处理函数执行结束后将会跳转到这个函数内进行执行然后执行sigreturn系统调用
restorer: Option<VirtAddr>,
}
impl Default for Sigaction {
fn default() -> Self {
Self {
action: SigactionType::SaHandler(SaHandlerType::SigDefault),
flags: Default::default(),
mask: Default::default(),
restorer: Default::default(),
}
}
}
impl Sigaction {
/// 判断传入的信号是否被忽略
///
/// ## 参数
///
/// - `sig` 传入的信号
///
/// ## 返回值
///
/// - `true` 被忽略
/// - `false`未被忽略
pub fn is_ignore(&self) -> bool {
return self.action.is_ignore();
}
pub fn new(
action: SigactionType,
flags: SigFlags,
mask: SigSet,
restorer: Option<VirtAddr>,
) -> Self {
Self {
action,
flags,
mask,
restorer,
}
}
pub fn action(&self) -> SigactionType {
self.action
}
pub fn flags(&self) -> SigFlags {
self.flags
}
pub fn restorer(&self) -> Option<VirtAddr> {
self.restorer
}
pub fn flags_mut(&mut self) -> &mut SigFlags {
&mut self.flags
}
pub fn set_action(&mut self, action: SigactionType) {
self.action = action;
}
pub fn mask(&self) -> SigSet {
self.mask
}
pub fn mask_mut(&mut self) -> &mut SigSet {
&mut self.mask
}
pub fn set_restorer(&mut self, restorer: Option<VirtAddr>) {
self.restorer = restorer;
}
/// 默认信号处理程序占位符用于在sighand结构体中的action数组中占位
pub const DEFAULT_SIGACTION: Sigaction = Sigaction {
action: SigactionType::SaHandler(SaHandlerType::SigDefault),
flags: SigFlags::empty(),
mask: SigSet::from_bits_truncate(0),
restorer: None,
};
/// 默认的“忽略信号”的sigaction
pub const DEFAULT_SIGACTION_IGNORE: Sigaction = Sigaction {
action: SigactionType::SaHandler(SaHandlerType::SigIgnore),
flags: SigFlags::empty(),
mask: SigSet::from_bits_truncate(0),
restorer: None,
};
}
/// 用户态传入的sigaction结构体符合posix规范
/// 请注意我们会在sys_sigaction函数里面将其转换成内核使用的sigaction结构体
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct UserSigaction {
pub handler: *mut core::ffi::c_void,
pub flags: SigFlags,
pub restorer: *mut core::ffi::c_void,
pub mask: SigSet,
}
/**
* siginfo中根据signal的来源不同该info中对应了不同的数据./=
* 请注意该info最大占用16字节
*/
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct SigInfo {
sig_no: i32,
sig_code: SigCode,
errno: i32,
sig_type: SigType,
}
impl SigInfo {
pub fn sig_code(&self) -> SigCode {
self.sig_code
}
pub fn set_sig_type(&mut self, sig_type: SigType) {
self.sig_type = sig_type;
}
/// @brief 将siginfo结构体拷贝到用户栈
/// ## 参数
///
/// `to` 用户空间指针
///
/// ## 注意
///
/// 该函数对应Linux中的https://opengrok.ringotek.cn/xref/linux-6.1.9/kernel/signal.c#3323
/// Linux还提供了 https://opengrok.ringotek.cn/xref/linux-6.1.9/kernel/signal.c#3383 用来实现
/// kernel_siginfo 保存到 用户的 compact_siginfo 的功能,但是我们系统内还暂时没有对这两种
/// siginfo做区分因此暂时不需要第二个函数
pub fn copy_siginfo_to_user(&self, to: *mut SigInfo) -> Result<i32, SystemError> {
// 验证目标地址是否为用户空间
let mut user_buffer = UserBufferWriter::new(to, size_of::<SigInfo>(), true)?;
let retval: Result<i32, SystemError> = Ok(0);
user_buffer.copy_one_to_user(self, 0)?;
return retval;
}
}
#[derive(Copy, Clone, Debug)]
pub enum SigType {
Kill(Pid),
// 后续完善下列中的具体字段
// Timer,
// Rt,
// SigChild,
// SigFault,
// SigPoll,
// SigSys,
}
impl SigInfo {
pub fn new(sig: Signal, sig_errno: i32, sig_code: SigCode, sig_type: SigType) -> Self {
Self {
sig_no: sig as i32,
sig_code,
errno: sig_errno,
sig_type,
}
}
}
#[derive(Debug)]
pub struct SigPending {
signal: SigSet,
queue: SigQueue,
}
impl Default for SigPending {
fn default() -> Self {
SigPending {
signal: SigSet::default(),
queue: SigQueue::default(),
}
}
}
impl SigPending {
pub fn signal(&self) -> SigSet {
self.signal
}
pub fn queue(&self) -> &SigQueue {
&self.queue
}
pub fn queue_mut(&mut self) -> &mut SigQueue {
&mut self.queue
}
pub fn signal_mut(&mut self) -> &mut SigSet {
&mut self.signal
}
/// @brief 获取下一个要处理的信号sig number越小的信号优先级越高
///
/// @param pending 等待处理的信号
/// @param sig_mask 屏蔽了的信号
/// @return i32 下一个要处理的信号的number. 如果为0,则无效
pub fn next_signal(&self, sig_mask: &SigSet) -> Signal {
let mut sig = Signal::INVALID;
let s = self.signal();
let m = *sig_mask;
m.is_empty();
// 获取第一个待处理的信号的号码
let x = s & (!m);
if x.bits() != 0 {
sig = Signal::from(ffz(x.complement().bits()) + 1);
return sig;
}
// 暂时只支持64种信号
assert_eq!(MAX_SIG_NUM, 64);
return sig;
}
/// @brief 收集信号的信息
///
/// @param sig 要收集的信号的信息
/// @param pending 信号的排队等待标志
/// @return SigInfo 信号的信息
pub fn collect_signal(&mut self, sig: Signal) -> SigInfo {
let (info, still_pending) = self.queue_mut().find_and_delete(sig);
// 如果没有仍在等待的信号则清除pending位
if !still_pending {
self.signal_mut().remove(sig.into());
}
if info.is_some() {
return info.unwrap();
} else {
// 信号不在sigqueue中这意味着当前信号是来自快速路径因此直接把siginfo设置为0即可。
let mut ret = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(Pid::from(0)));
ret.set_sig_type(SigType::Kill(Pid::new(0)));
return ret;
}
}
/// @brief 从当前进程的sigpending中取出下一个待处理的signal并返回给调用者。调用者应当处理这个信号
/// 请注意进入本函数前当前进程应当持有current_pcb().sighand.siglock
pub fn dequeue_signal(&mut self, sig_mask: &SigSet) -> (Signal, Option<SigInfo>) {
// kdebug!("dequeue signal");
// 获取下一个要处理的信号的编号
let sig = self.next_signal(sig_mask);
let info: Option<SigInfo>;
if sig != Signal::INVALID {
// 如果下一个要处理的信号是合法的则收集其siginfo
info = Some(self.collect_signal(sig));
} else {
info = None;
}
// 当一个进程具有多个线程之后在这里需要重新计算线程的flag中的TIF_SIGPENDING位
// recalc_sigpending();
return (sig, info);
}
/// @brief 从sigpending中删除mask中被置位的信号。也就是说比如mask的第1位被置为1,那么就从sigqueue中删除所有signum为2的信号的信息。
pub fn flush_by_mask(&mut self, mask: &SigSet) {
// 定义过滤器从sigqueue中删除mask中被置位的信号
let filter = |x: &mut SigInfo| {
if mask.contains(SigSet::from_bits_truncate(x.sig_no as u64)) {
return true;
}
return false;
};
let filter_result: Vec<SigInfo> = self.queue.q.drain_filter(filter).collect();
// 回收这些siginfo
for x in filter_result {
drop(x)
}
}
}
/// @brief 进程接收到的信号的队列
#[derive(Debug, Clone)]
pub struct SigQueue {
pub q: Vec<SigInfo>,
}
#[allow(dead_code)]
impl SigQueue {
/// @brief 初始化一个新的信号队列
pub fn new(capacity: usize) -> Self {
SigQueue {
q: Vec::with_capacity(capacity),
}
}
/// @brief 在信号队列中寻找第一个满足要求的siginfo, 并返回它的引用
///
/// @return (第一个满足要求的siginfo的引用; 是否有多个满足条件的siginfo)
pub fn find(&self, sig: Signal) -> (Option<&SigInfo>, bool) {
// 是否存在多个满足条件的siginfo
let mut still_pending = false;
let mut info: Option<&SigInfo> = None;
for x in self.q.iter() {
if x.sig_no == sig as i32 {
if info.is_some() {
still_pending = true;
break;
} else {
info = Some(x);
}
}
}
return (info, still_pending);
}
/// @brief 在信号队列中寻找第一个满足要求的siginfo, 并将其从队列中删除然后返回这个siginfo
///
/// @return (第一个满足要求的siginfo; 从队列中删除前是否有多个满足条件的siginfo)
pub fn find_and_delete(&mut self, sig: Signal) -> (Option<SigInfo>, bool) {
// 是否存在多个满足条件的siginfo
let mut still_pending = false;
let mut first = true; // 标记变量,记录当前是否已经筛选出了一个元素
let filter = |x: &mut SigInfo| {
if x.sig_no == sig as i32 {
if !first {
// 如果之前已经筛选出了一个元素,则不把当前元素删除
still_pending = true;
return false;
} else {
// 当前是第一个被筛选出来的元素
first = false;
return true;
}
}
return false;
};
// 从sigqueue中过滤出结果
let mut filter_result: Vec<SigInfo> = self.q.drain_filter(filter).collect();
// 筛选出的结果不能大于1个
assert!(filter_result.len() <= 1);
return (filter_result.pop(), still_pending);
}
/// @brief 从C的void*指针转换为static生命周期的可变引用
pub fn from_c_void(p: *mut c_void) -> &'static mut SigQueue {
let sq = p as *mut SigQueue;
let sq = unsafe { sq.as_mut::<'static>() }.unwrap();
return sq;
}
}
impl Default for SigQueue {
fn default() -> Self {
Self {
q: Default::default(),
}
}
}
///
/// 定义了不同架构下实现 Signal 要实现的接口
///
pub trait SignalArch {
/// 信号处理函数
///
/// ## 参数
///
/// - `frame` 中断栈帧
unsafe fn do_signal(frame: &mut TrapFrame);
fn sys_rt_sigreturn(trap_frame: &mut TrapFrame) -> u64;
}

View File

@ -1,15 +1,27 @@
use core::ffi::c_int;
use core::{
ffi::{c_int, c_void},
sync::atomic::compiler_fence,
};
use crate::{
arch::ipc::signal::{SigCode, SigFlags, SigSet, Signal},
filesystem::vfs::{
file::{File, FileMode},
FilePrivateData,
},
kerror, kwarn,
mm::VirtAddr,
process::{Pid, ProcessManager},
syscall::{user_access::UserBufferWriter, Syscall, SystemError},
};
use super::pipe::{LockedPipeInode, PipeFsPrivateData};
use super::{
pipe::{LockedPipeInode, PipeFsPrivateData},
signal_types::{
SaHandlerType, SigInfo, SigType, Sigaction, SigactionType, UserSigaction, USER_SIG_DFL,
USER_SIG_ERR, USER_SIG_IGN,
},
};
impl Syscall {
/// # 创建带参数的匿名管道
@ -52,26 +64,158 @@ impl Syscall {
}
}
pub fn kill(_pid: Pid, _sig: c_int) -> Result<usize, SystemError> {
// todo: 由于进程管理重构目前删除了signal功能将来重新实现它。
return Err(SystemError::ENOSYS);
pub fn kill(pid: Pid, sig: c_int) -> Result<usize, SystemError> {
let sig = Signal::from(sig);
if sig == Signal::INVALID {
// 传入的signal数值不合法
kwarn!("Not a valid signal number");
return Err(SystemError::EINVAL);
}
// 初始化signal info
let mut info = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(pid));
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let retval = sig
.send_signal_info(Some(&mut info), pid)
.map(|x| x as usize);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return retval;
}
/// @brief 用户程序用于设置信号处理动作的函数遵循posix2008
/// 通用信号注册函数
///
/// @param regs->r8 signumber 信号的编号
/// @param regs->r9 act 新的将要被设置的sigaction
/// @param regs->r10 oact 返回给用户的原本的sigaction内核将原本的sigaction的值拷贝给这个地址
/// ## 参数
///
/// - `sig` 信号的值
/// - `act` 用户空间传入的 Sigaction 指针
/// - `old_act` 用户空间传入的用来保存旧 Sigaction 的指针
/// - `from_user` 用来标识这个函数调用是否来自用户空间
///
/// @return int 错误码
#[no_mangle]
pub fn sigaction(
_sig: c_int,
_act: usize,
_old_act: usize,
_from_user: bool,
sig: c_int,
new_act: usize,
old_act: usize,
from_user: bool,
) -> Result<usize, SystemError> {
// todo: 由于进程管理重构目前删除了signal功能将来重新实现它。
return Err(SystemError::ENOSYS);
// 请注意用户态传进来的user_sigaction结构体类型请注意这个结构体与内核实际的不一样
let act: *mut UserSigaction = new_act as *mut UserSigaction;
let mut old_act = old_act as *mut UserSigaction;
let mut new_ka: Sigaction = Default::default();
let mut old_sigaction: Sigaction = Default::default();
// 如果传入的新的sigaction不为空
if !act.is_null() {
// 如果参数的范围不在用户空间,则返回错误
let r = UserBufferWriter::new(act, core::mem::size_of::<Sigaction>(), from_user);
if r.is_err() {
return Err(SystemError::EFAULT);
}
let mask: SigSet = unsafe { (*act).mask };
let input_sighandler = unsafe { (*act).handler as u64 };
match input_sighandler {
USER_SIG_DFL => {
new_ka = Sigaction::DEFAULT_SIGACTION.clone();
*new_ka.flags_mut() = unsafe { (*act).flags };
new_ka.set_restorer(None);
}
USER_SIG_IGN => {
new_ka = Sigaction::DEFAULT_SIGACTION_IGNORE.clone();
*new_ka.flags_mut() = unsafe { (*act).flags };
new_ka.set_restorer(None);
}
_ => {
// 从用户空间获得sigaction结构体
// TODO mask是default还是用户空间传入
new_ka = Sigaction::new(
SigactionType::SaHandler(SaHandlerType::SigCustomized(unsafe {
VirtAddr::new((*act).handler as usize)
})),
unsafe { (*act).flags },
SigSet::default(),
unsafe { Some(VirtAddr::new((*act).restorer as usize)) },
);
}
}
// TODO 如果为空,赋默认值?
// kdebug!("new_ka={:?}", new_ka);
// 如果用户手动给了sa_restorer那么就置位SA_FLAG_RESTORER否则报错。用户必须手动指定restorer
if new_ka.restorer().is_some() {
new_ka.flags_mut().insert(SigFlags::SA_RESTORER);
} else if new_ka.action().is_customized() {
kerror!(
"pid:{:?}: in sys_sigaction: User must manually sprcify a sa_restorer for signal {}.",
ProcessManager::current_pcb().pid(),
sig
);
return Err(SystemError::EINVAL);
}
*new_ka.mask_mut() = mask;
}
let sig = Signal::from(sig as i32);
// 如果给出的信号值不合法
if sig == Signal::INVALID {
return Err(SystemError::EINVAL);
}
let retval = super::signal::do_sigaction(
sig,
if act.is_null() {
None
} else {
Some(&mut new_ka)
},
if old_act.is_null() {
None
} else {
Some(&mut old_sigaction)
},
);
//
if (retval == Ok(())) && (!old_act.is_null()) {
let r =
UserBufferWriter::new(old_act, core::mem::size_of::<UserSigaction>(), from_user);
if r.is_err() {
return Err(SystemError::EFAULT);
}
let sigaction_handler: VirtAddr;
sigaction_handler = match old_sigaction.action() {
SigactionType::SaHandler(handler) => {
if let SaHandlerType::SigCustomized(hand) = handler {
hand
} else if handler.is_sig_ignore() {
VirtAddr::new(USER_SIG_IGN as usize)
} else if handler.is_sig_error() {
VirtAddr::new(USER_SIG_ERR as usize)
} else {
VirtAddr::new(USER_SIG_DFL as usize)
}
}
SigactionType::SaSigaction(_) => {
kerror!("unsupported type: SaSigaction");
VirtAddr::new(USER_SIG_DFL as usize)
}
};
unsafe {
(*old_act).handler = sigaction_handler.data() as *mut c_void;
(*old_act).flags = old_sigaction.flags();
(*old_act).mask = old_sigaction.mask();
if old_sigaction.restorer().is_some() {
(*old_act).restorer = old_sigaction.restorer().unwrap().data() as *mut c_void;
}
}
}
return retval.map(|_| 0);
}
}