Browse Source

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

* 添加sigprocmask系统调用

---------

Signed-off-by: sparkzky <[email protected]>
Co-authored-by: longjin <[email protected]>
火花 3 months ago
parent
commit
6e85059fbc

+ 2 - 2
kernel/src/arch/x86_64/ipc/signal.rs

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

+ 129 - 16
kernel/src/ipc/signal.rs

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

+ 63 - 0
kernel/src/ipc/syscall.rs

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

+ 2 - 2
kernel/src/net/event_poll/syscall.rs

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

+ 14 - 0
kernel/src/process/mod.rs

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

+ 5 - 2
kernel/src/syscall/mod.rs

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

+ 1 - 0
user/apps/test-sigprocmask/.gitignore

@@ -0,0 +1 @@
+test-sigprocmask

+ 20 - 0
user/apps/test-sigprocmask/Makefile

@@ -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-sigprocmask main.c
+
+.PHONY: install clean
+install: all
+	mv test-sigprocmask $(DADK_CURRENT_BUILD_DIR)/test-sigprocmask
+
+clean:
+	rm test-sigprocmask *.o
+
+fmt:

+ 130 - 0
user/apps/test-sigprocmask/main.c

@@ -0,0 +1,130 @@
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define TEST_ASSERT(left, right, success_msg, fail_msg)                        \
+    do {                                                                       \
+        if ((left) == (right)) {                                               \
+            printf("[PASS] %s\n", success_msg);                                \
+        } else {                                                               \
+            printf("[FAIL] %s: Expected 0x%lx, but got 0x%lx\n",               \
+                   fail_msg,                                                   \
+                   (unsigned long)(right),                                     \
+                   (unsigned long)(left));                                     \
+        }                                                                      \
+    } while (0)
+
+
+static int signal_received = 0;
+
+void signal_handler(int signo) {
+    if (signo == SIGINT) {
+        printf("\nReceived SIGINT (Ctrl+C)\n");
+        signal_received = 1;
+    }
+}
+
+void print_signal_mask(const char *msg, const sigset_t *mask) {
+    printf("%s: ", msg);
+    for (int signo = 1; signo < NSIG; ++signo) {
+        if (sigismember(mask, signo)) {
+            printf("%d ", signo);
+        }
+    }
+    printf("\n");
+}
+
+// 获取当前屏蔽字的函数
+unsigned long get_signal_mask() {
+    sigset_t sigset;
+    if (sigprocmask(SIG_BLOCK, NULL, &sigset) == -1) {
+        perror("sigprocmask");
+        return -1; // 返回错误标记
+    }
+
+    // 将信号集编码为位掩码
+    unsigned long mask = 0;
+    for (int i = 1; i < NSIG; i++) {
+        if (sigismember(&sigset, i)) {
+            mask |= 1UL << (i - 1);
+        }
+    }
+    return mask;
+}
+
+int main() {
+    sigset_t new_mask, old_mask;
+    sigemptyset(&old_mask);
+
+    // 注册 SIGINT 的信号处理函数
+    if (signal(SIGINT, signal_handler) == SIG_ERR) {
+        perror("signal");
+        exit(EXIT_FAILURE);
+    }
+
+    signal_received = 0;
+    kill(getpid(), SIGINT);
+    TEST_ASSERT(signal_received, 1, "SIGINT was received", "SIGINT was not received");
+    signal_received = 0;
+
+    // 初始化新的信号集,并将 SIGINT 添加到其中
+    sigemptyset(&new_mask);
+    sigaddset(&new_mask, SIGINT);
+
+    // 打印 new_mask 的值
+    print_signal_mask("new_mask", &new_mask);
+
+    // 屏蔽 SIGINT
+    if (sigprocmask(SIG_BLOCK, &new_mask, &old_mask) < 0) {
+        perror("sigprocmask - SIG_BLOCK");
+        exit(EXIT_FAILURE);
+    }
+
+    // 打印 old_mask 的值
+    print_signal_mask("old_mask", &old_mask);
+
+    // 检查 SIGINT 是否被屏蔽
+    unsigned long actual_mask = get_signal_mask();
+    unsigned long expected_mask = (1UL << (SIGINT - 1));
+    TEST_ASSERT(actual_mask,
+                expected_mask,
+                "Signal mask is as expected",
+                "Signal mask mismatch");
+
+    printf("SIGINT is now blocked.\n");
+    signal_received = 0;
+    // 向当前进程发送 SIGINT
+    kill(getpid(), SIGINT);
+
+    // 等待 5 秒,以便测试 SIGINT 是否被屏蔽
+    sleep(5);
+    TEST_ASSERT(signal_received, 0, "SIGINT was blocked", "SIGINT was not blocked");
+    signal_received = 0;
+    // 恢复原来的信号屏蔽字
+    if (sigprocmask(SIG_SETMASK, &old_mask, &old_mask) < 0) {
+        perror("sigprocmask - SIG_SETMASK");
+        exit(EXIT_FAILURE);
+    }
+    print_signal_mask("old_mask returned", &old_mask);
+
+    // 检查 SIGINT 是否被解除屏蔽
+    actual_mask = get_signal_mask();
+    expected_mask = 0;
+    TEST_ASSERT(actual_mask,
+                expected_mask,
+                "Signal mask is as expected",
+                "Signal mask mismatch");
+
+    printf("SIGINT is now unblocked.\n");
+
+    signal_received = 0;
+    kill(getpid(), SIGINT);
+
+    // 等待 5 秒,以便测试 SIGINT 是否解除屏蔽
+    sleep(5);
+    TEST_ASSERT(signal_received, 1, "SIGINT was received", "SIGINT was not received");
+
+    printf("Exiting program.\n");
+    return 0;
+}

+ 41 - 0
user/dadk/config/test_sigprocmask_0_1_0.toml

@@ -0,0 +1,41 @@
+# 用户程序名称
+name = "test_sigprocmask"
+# 版本号
+version = "0.1.0"
+# 用户程序描述信息
+description = "一个用来测试sigprocmask能够正常运行的app"
+# (可选)默认: false 是否只构建一次,如果为true,DADK会在构建成功后,将构建结果缓存起来,下次构建时,直接使用缓存的构建结果
+build-once = false
+#  (可选) 默认: false 是否只安装一次,如果为true,DADK会在安装成功后,不再重复安装
+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-sigprocmask"
+# 构建相关信息
+[build]
+# (可选)构建命令
+build-command = "make install"
+# 安装相关信息
+[install]
+# (可选)安装到DragonOS的路径
+in-dragonos-path = "/bin"
+# 清除相关信息
+[clean]
+# (可选)清除命令
+clean-command = "make clean"
+# (可选)依赖项
+# 注意:如果没有依赖项,忽略此项,不允许只留一个[[depends]]
+# 由于原文件中依赖项为空,此处省略[[depends]]部分
+# (可选)环境变量
+# 由于原文件中环境变量为空,此处省略[[envs]]部分