feat:添加sigprocmask系统调用 (#1046)

* 添加sigprocmask系统调用

---------

Signed-off-by: sparkzky <sparkhhhhhhhhh@outlook.com>
Co-authored-by: longjin <longjin@DragonOS.org>
This commit is contained in:
火花
2024-12-07 16:36:55 +08:00
committed by GitHub
parent 4f8f269baf
commit 6e85059fbc
10 changed files with 407 additions and 22 deletions

View File

@ -12,7 +12,7 @@ use crate::{
},
exception::InterruptArch,
ipc::{
signal::set_current_sig_blocked,
signal::set_current_blocked,
signal_types::{SaHandlerType, SigInfo, Sigaction, SigactionType, SignalArch},
},
mm::MemoryManagementArch,
@ -511,7 +511,7 @@ impl SignalArch for X86_64SignalArch {
return trap_frame.rax;
}
let mut sigmask: SigSet = unsafe { (*frame).context.oldmask };
set_current_sig_blocked(&mut sigmask);
set_current_blocked(&mut sigmask);
// 从用户栈恢复sigcontext
if !unsafe { &mut (*frame).context }.restore_sigcontext(trap_frame) {
error!("unable to restore sigcontext");

View File

@ -441,18 +441,46 @@ pub(super) fn do_sigaction(
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) {
let to_remove: SigSet =
<Signal as Into<SigSet>>::into(Signal::SIGKILL) | Signal::SIGSTOP.into();
new_set.remove(to_remove);
//TODO 把这个散装函数用 sigsetops 替换掉
let pcb = ProcessManager::current_pcb();
/// https://code.dragonos.org.cn/xref/linux-6.6.21/include/uapi/asm-generic/signal-defs.h#72
/// 对应SIG_BLOCKSIG_UNBLOCKSIG_SETMASK
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SigHow {
Block = 0,
Unblock = 1,
SetMask = 2,
}
impl TryFrom<i32> for SigHow {
type Error = SystemError;
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
0 => Ok(SigHow::Block),
1 => Ok(SigHow::Unblock),
2 => Ok(SigHow::SetMask),
_ => Err(SystemError::EINVAL),
}
}
}
fn __set_task_blocked(pcb: &Arc<ProcessControlBlock>, new_set: &SigSet) {
//todo 还有一个对线程组是否为空的判断,进程组、线程组实现之后,需要更改这里。
if pcb.has_pending_signal() {
let mut newblocked = *new_set;
let guard = pcb.sig_info_irqsave();
newblocked.remove(*guard.sig_block());
drop(guard);
// 从主线程开始去遍历
if let Some(group_leader) = pcb.threads_read_irqsave().group_leader() {
retarget_shared_pending(group_leader, newblocked);
}
}
*pcb.sig_info_mut().sig_block_mut() = *new_set;
recalc_sigpending();
}
fn __set_current_blocked(new_set: &SigSet) {
let pcb = ProcessManager::current_pcb();
/*
如果当前pcb的sig_blocked和新的相等那么就不用改变它。
请注意一个进程的sig_blocked字段不能被其他进程修改
@ -460,12 +488,97 @@ pub fn set_current_sig_blocked(new_set: &mut SigSet) {
if pcb.sig_info_irqsave().sig_block().eq(new_set) {
return;
}
let guard = pcb.sig_struct_irqsave();
// todo: 当一个进程有多个线程后在这里需要设置每个线程的block字段并且 retarget_shared_pending虽然我还没搞明白linux这部分是干啥的
// 设置当前进程的sig blocked
*pcb.sig_info_mut().sig_block_mut() = *new_set;
recalc_sigpending();
__set_task_blocked(&pcb, new_set);
drop(guard);
}
fn retarget_shared_pending(pcb: Arc<ProcessControlBlock>, which: SigSet) {
let retarget = pcb.sig_info_irqsave().sig_shared_pending().signal();
retarget.intersects(which);
if retarget.is_empty() {
return;
}
// 对于线程组中的每一个线程都要执行的函数
let thread_handling_function = |pcb: Arc<ProcessControlBlock>, retarget: &SigSet| {
if retarget.is_empty() {
return;
}
if pcb.flags().contains(ProcessFlags::EXITING) {
return;
}
let blocked = pcb.sig_info_irqsave().sig_shared_pending().signal();
if retarget.difference(blocked).is_empty() {
return;
}
retarget.intersects(blocked);
if !pcb.has_pending_signal() {
let guard = pcb.sig_struct_irqsave();
signal_wake_up(pcb.clone(), guard, false);
}
// 之前的对retarget的判断移动到最前面因为对于当前线程的线程的处理已经结束对于后面的线程在一开始判断retarget为空即可结束处理
// debug!("handle done");
};
// 暴力遍历每一个线程找到相同的tgid
let tgid = pcb.tgid();
for &pid in pcb.children_read_irqsave().iter() {
if let Some(child) = ProcessManager::find(pid) {
if child.tgid() == tgid {
thread_handling_function(child, &retarget);
}
}
}
// debug!("retarget_shared_pending done!");
}
/// 设置当前进程的屏蔽信号 (sig_block)
///
/// ## 参数
///
/// - `new_set` 新的屏蔽信号bitmap的值
pub fn set_current_blocked(new_set: &mut SigSet) {
let to_remove: SigSet =
<Signal as Into<SigSet>>::into(Signal::SIGKILL) | Signal::SIGSTOP.into();
new_set.remove(to_remove);
__set_current_blocked(new_set);
}
/// 设置当前进程的屏蔽信号 (sig_block)
///
/// ## 参数
///
/// - `how` 设置方式
/// - `new_set` 新的屏蔽信号bitmap的值
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 mut res_set = oset;
drop(guard);
match how {
SigHow::Block => {
// debug!("SIG_BLOCK\tGoing to insert is: {}", set.bits());
res_set.insert(set);
}
SigHow::Unblock => {
res_set.remove(set);
}
SigHow::SetMask => {
// debug!("SIG_SETMASK\tGoing to set is: {}", set.bits());
res_set = set;
}
}
__set_current_blocked(&res_set);
Ok(oset)
}

View File

@ -35,6 +35,7 @@ use crate::{
use super::{
pipe::{LockedPipeInode, PipeFsPrivateData},
shm::{ShmCtlCmd, ShmFlags, ShmId, ShmKey},
signal::{set_sigprocmask, SigHow},
signal_types::{
SaHandlerType, SigInfo, SigType, Sigaction, SigactionType, UserSigaction, USER_SIG_DFL,
USER_SIG_ERR, USER_SIG_IGN,
@ -504,4 +505,66 @@ impl Syscall {
ShmCtlCmd::Default => Err(SystemError::EINVAL),
}
}
/// # SYS_SIGPROCMASK系统调用函数用于设置或查询当前进程的信号屏蔽字
///
/// ## 参数
///
/// - `how`: 指示如何修改信号屏蔽字
/// - `nset`: 新的信号屏蔽字
/// - `oset`: 旧的信号屏蔽字的指针由于可以是NULL所以用Option包装
/// - `sigsetsize`: 信号集的大小
///
/// ## 返回值
///
/// 成功0
/// 失败:错误码
///
/// ## 说明
/// 根据 https://man7.org/linux/man-pages/man2/sigprocmask.2.html 传进来的oldset和newset都是指针类型这里选择传入usize然后转换为u64的指针类型
pub fn rt_sigprocmask(
how: i32,
newset: usize,
oldset: usize,
sigsetsize: usize,
) -> Result<usize, SystemError> {
// 对应oset传进来一个NULL的情况
let oset = if oldset == 0 { None } else { Some(oldset) };
let nset = if newset == 0 { None } else { Some(newset) };
if sigsetsize != size_of::<SigSet>() {
return Err(SystemError::EFAULT);
}
let sighow = SigHow::try_from(how)?;
let mut new_set = SigSet::default();
if let Some(nset) = nset {
let reader = UserBufferReader::new(
VirtAddr::new(nset).as_ptr::<u64>(),
core::mem::size_of::<u64>(),
true,
)?;
let nset = reader.read_one_from_user::<u64>(0)?;
new_set = SigSet::from_bits_truncate(*nset);
// debug!("Get Newset: {}", &new_set.bits());
let to_remove: SigSet =
<Signal as Into<SigSet>>::into(Signal::SIGKILL) | Signal::SIGSTOP.into();
new_set.remove(to_remove);
}
let oldset_to_return = set_sigprocmask(sighow, new_set)?;
if let Some(oldset) = oset {
// debug!("Get Oldset to return: {}", &oldset_to_return.bits());
let mut writer = UserBufferWriter::new(
VirtAddr::new(oldset).as_ptr::<u64>(),
core::mem::size_of::<u64>(),
true,
)?;
writer.copy_one_to_user::<u64>(&oldset_to_return.bits(), 0)?;
}
Ok(0)
}
}

View File

@ -3,7 +3,7 @@ use system_error::SystemError;
use crate::{
arch::ipc::signal::SigSet,
filesystem::vfs::file::FileMode,
ipc::signal::set_current_sig_blocked,
ipc::signal::set_current_blocked,
mm::VirtAddr,
syscall::{
user_access::{UserBufferReader, UserBufferWriter},
@ -96,7 +96,7 @@ impl Syscall {
sigmask: &mut SigSet,
) -> Result<usize, SystemError> {
// 设置屏蔽的信号
set_current_sig_blocked(sigmask);
set_current_blocked(sigmask);
let wait_ret = Self::epoll_wait(epfd, epoll_event, max_events, timespec);

View File

@ -1061,6 +1061,14 @@ impl ProcessControlBlock {
fn exit_files(&self) {
self.basic.write_irqsave().set_fd_table(None);
}
pub fn children_read_irqsave(&self) -> RwLockReadGuard<Vec<Pid>> {
self.children.read_irqsave()
}
pub fn threads_read_irqsave(&self) -> RwLockReadGuard<ThreadInfo> {
self.thread.read_irqsave()
}
}
impl Drop for ProcessControlBlock {
@ -1092,6 +1100,12 @@ pub struct ThreadInfo {
group_leader: Weak<ProcessControlBlock>,
}
impl Default for ThreadInfo {
fn default() -> Self {
Self::new()
}
}
impl ThreadInfo {
pub fn new() -> Self {
Self {

View File

@ -879,8 +879,11 @@ impl Syscall {
}
SYS_RT_SIGPROCMASK => {
warn!("SYS_RT_SIGPROCMASK has not yet been implemented");
Ok(0)
let how = args[0] as i32;
let nset = args[1];
let oset = args[2];
let sigsetsize = args[3];
Self::rt_sigprocmask(how, nset, oset, sigsetsize)
}
SYS_TKILL => {