mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-18 12:16:31 +00:00
feat:添加sigprocmask系统调用 (#1046)
* 添加sigprocmask系统调用 --------- Signed-off-by: sparkzky <sparkhhhhhhhhh@outlook.com> Co-authored-by: longjin <longjin@DragonOS.org>
This commit is contained in:
@ -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");
|
||||
|
@ -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_BLOCK,SIG_UNBLOCK,SIG_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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 => {
|
||||
|
Reference in New Issue
Block a user