Forráskód Böngészése

允许用户自定义信号处理函数 (#112)

* new: 用户注册信号处理函数,能够进入自定义的handler

* 修复忘了传信号的数字给用户的处理函数的bug

* new:sigreturn

* 删除注释
login 2 éve
szülő
commit
6efd474033

+ 1 - 0
.vscode/settings.json

@@ -164,6 +164,7 @@
         "wait.h": "c",
         "__libc__.h": "c",
         "ctype.h": "c",
+        "signal.h": "c",
         "mmio.h": "c",
         "stdint-gcc.h": "c",
         "acpi.h": "c",

+ 1 - 0
kernel/src/include/DragonOS/signal.h

@@ -112,6 +112,7 @@ struct sigaction
 #define SA_FLAG_IGN (1UL << 0)      // 当前sigaction表示忽略信号的动作
 #define SA_FLAG_DFL (1UL << 1)      // 当前sigaction表示系统默认的动作
 #define SA_FLAG_RESTORER (1UL << 2) // 当前sigaction具有用户指定的restorer
+#define SA_FLAG_IMMUTABLE (1UL << 3) // 当前sigaction不可被更改
 
 /**
  * 由于signal_struct总是和sighand_struct一起使用,并且信号处理的过程中必定会对sighand加锁,

+ 1 - 1
kernel/src/include/bindings/wrapper.h

@@ -16,13 +16,13 @@
 #include <common/crc7.h>
 #include <common/crc8.h>
 #include <common/gfp.h>
+#include <common/glib.h>
 #include <common/kfifo.h>
 #include <common/list.h>
 #include <common/lz4.h>
 #include <common/printk.h>
 #include <common/spinlock.h>
 #include <common/unistd.h>
-#include <common/glib.h>
 #include <driver/timers/rtc/rtc.h>
 #include <include/DragonOS/refcount.h>
 #include <include/DragonOS/signal.h>

+ 301 - 37
kernel/src/ipc/signal.rs

@@ -7,10 +7,11 @@ use crate::{
     },
     include::bindings::bindings::{
         pid_t, process_control_block, process_do_exit, process_find_pcb_by_pid, pt_regs,
-        spinlock_t, verify_area, EINVAL, ENOTSUP, EPERM, ESRCH, PF_EXITING, PF_KTHREAD,
-        PF_SIGNALED, PF_WAKEKILL, PROC_INTERRUPTIBLE, USER_CS, USER_DS, USER_MAX_LINEAR_ADDR,
+        spinlock_t, verify_area, EFAULT, EINVAL, ENOTSUP, EPERM, ESRCH, NULL, PF_EXITING,
+        PF_KTHREAD, PF_SIGNALED, PF_WAKEKILL, PROC_INTERRUPTIBLE, USER_CS, USER_DS,
+        USER_MAX_LINEAR_ADDR,
     },
-    ipc::signal_types::sigset_add,
+    ipc::signal_types::{sigset_add, user_sigaction},
     kBUG, kdebug, kerror, kwarn,
     libs::{
         ffi_convert::FFIBind2Rust,
@@ -19,7 +20,6 @@ use crate::{
             spin_unlock_irqrestore,
         },
     },
-    println,
     process::{
         pid::PidType,
         process::{process_is_stopped, process_kick, process_wake_up_state},
@@ -27,28 +27,34 @@ use crate::{
 };
 
 use super::signal_types::{
-    si_code_val, sigaction, sigaction__union_u, sigcontext, sigframe, sighand_struct, siginfo,
-    signal_struct, sigpending, sigset_clear, sigset_del, sigset_t, SignalNumber, MAX_SIG_NUM,
-    SA_FLAG_DFL, SA_FLAG_IGN, SA_FLAG_RESTORER, STACK_ALIGN, _NSIG_U64_CNT,
+    si_code_val, sig_is_member, sigaction, sigaction__union_u, sigcontext, sigframe,
+    sighand_struct, siginfo, signal_struct, sigpending, sigset_clear, sigset_del, sigset_delmask,
+    sigset_equal, sigset_init, sigset_t, SigQueue, SignalNumber, MAX_SIG_NUM, SA_ALL_FLAGS,
+    SA_FLAG_DFL, SA_FLAG_IGN, SA_FLAG_IMMUTABLE, SA_FLAG_RESTORER, STACK_ALIGN, USER_SIG_DFL,
+    USER_SIG_IGN, _NSIG_U64_CNT,
 };
 
 use super::signal_types::{__siginfo_union, __siginfo_union_data};
 
 /// 默认信号处理程序占位符(用于在sighand结构体中的action数组中占位)
 pub static DEFAULT_SIGACTION: sigaction = sigaction {
-    _u: sigaction__union_u { _sa_handler: None },
+    _u: sigaction__union_u {
+        _sa_handler: NULL as u64,
+    },
     sa_flags: SA_FLAG_DFL,
     sa_mask: 0,
-    sa_restorer: None,
+    sa_restorer: NULL as u64,
 };
 
 /// 默认的“忽略信号”的sigaction
 #[allow(dead_code)]
 pub static DEFAULT_SIGACTION_IGNORE: sigaction = sigaction {
-    _u: sigaction__union_u { _sa_handler: None },
+    _u: sigaction__union_u {
+        _sa_handler: NULL as u64,
+    },
     sa_flags: SA_FLAG_IGN,
     sa_mask: 0,
-    sa_restorer: None,
+    sa_restorer: NULL as u64,
 };
 
 /// @brief kill系统调用,向指定的进程发送信号
@@ -56,13 +62,6 @@ pub static DEFAULT_SIGACTION_IGNORE: sigaction = sigaction {
 /// @param regs->r9 sig 信号
 #[no_mangle]
 pub extern "C" fn sys_kill(regs: &pt_regs) -> u64 {
-    println!(
-        "sys kill, target pid={}, file={}, line={}",
-        regs.r8,
-        file!(),
-        line!()
-    );
-
     let pid: pid_t = regs.r8 as pid_t;
     let sig: SignalNumber = SignalNumber::from(regs.r9 as i32);
     if sig == SignalNumber::INVALID {
@@ -343,18 +342,6 @@ fn wants_signal(sig: SignalNumber, pcb: &process_control_block) -> bool {
     return !has_sig_pending(pcb);
 }
 
-/// @brief 判断指定的信号在sigset中的对应位是否被置位
-/// @return true: 给定的信号在sigset中被置位
-/// @return false: 给定的信号在sigset中没有被置位
-#[inline]
-fn sig_is_member(set: &sigset_t, _sig: SignalNumber) -> bool {
-    return if 1 & (set >> ((_sig as u32) - 1)) != 0 {
-        true
-    } else {
-        false
-    };
-}
-
 /// @brief 判断signal的处理是否可能使得整个进程组退出
 /// @return true 可能会导致退出(不一定)
 #[allow(dead_code)]
@@ -367,7 +354,7 @@ fn sig_fatal(pcb: &process_control_block, sig: SignalNumber) -> bool {
     };
 
     // 如果handler是空,采用默认函数,signal处理可能会导致进程退出。
-    if handler.is_none() {
+    if handler == NULL.into() {
         return true;
     } else {
         return false;
@@ -626,7 +613,7 @@ fn setup_frame(
 ) -> Result<i32, i32> {
     let mut err = 0;
     let frame: *mut sigframe = get_stack(ka, &regs, size_of::<sigframe>());
-
+    // kdebug!("frame=0x{:016x}", frame as usize);
     // 要求这个frame的地址位于用户空间,因此进行校验
     let access_check_ok = unsafe { verify_area(frame as u64, size_of::<sigframe>() as u64) };
     if !access_check_ok {
@@ -640,7 +627,7 @@ fn setup_frame(
         (*frame).arg0 = sig as u64;
         (*frame).arg1 = &((*frame).info) as *const siginfo as usize;
         (*frame).arg2 = &((*frame).context) as *const sigcontext as usize;
-        (*frame).handler = ka._u._sa_handler.unwrap() as *mut core::ffi::c_void;
+        (*frame).handler = ka._u._sa_handler as usize as *mut c_void;
     }
 
     // 将siginfo拷贝到用户栈
@@ -653,8 +640,7 @@ fn setup_frame(
     // 为了与Linux的兼容性,64位程序必须由用户自行指定restorer
     if ka.sa_flags & SA_FLAG_RESTORER != 0 {
         unsafe {
-            (*frame).ret_code_ptr =
-                (&mut ka.sa_restorer.unwrap()) as *mut unsafe extern "C" fn() as *mut c_void;
+            (*frame).ret_code_ptr = ka.sa_restorer as usize as *mut c_void;
         }
     } else {
         kerror!(
@@ -668,11 +654,13 @@ fn setup_frame(
         // todo: 在这里生成一个sigsegv,然后core dump
         return Err(1);
     }
-
+    // 传入信号处理函数的第一个参数
     regs.rdi = sig as u64;
     regs.rsi = unsafe { &(*frame).info as *const siginfo as u64 };
     regs.rsp = frame as u64;
-    regs.rip = unsafe { ka._u._sa_handler.unwrap() as *const unsafe extern "C" fn() as u64 };
+    regs.rip = unsafe { ka._u._sa_handler };
+
+    // todo: 传入新版的sa_sigaction的处理函数的第三个参数
 
     // 如果handler位于内核空间
     if regs.rip >= USER_MAX_LINEAR_ADDR {
@@ -737,6 +725,25 @@ fn setup_sigcontext(context: &mut sigcontext, mask: &sigset_t, regs: &pt_regs) -
     return Ok(0);
 }
 
+/// @brief 将指定的sigcontext恢复到当前进程的内核栈帧中,并将当前线程结构体的几个参数进行恢复
+///
+/// @param context 要被恢复的context
+/// @param regs 目标栈帧(也就是把context恢复到这个栈帧中)
+///
+/// @return bool true -> 成功恢复
+///              false -> 执行失败
+fn restore_sigcontext(context: *const sigcontext, regs: &mut pt_regs) -> bool {
+    let mut current_thread = current_pcb().thread;
+    unsafe {
+        *regs = (*context).regs;
+
+        (*current_thread).trap_num = (*context).trap_num;
+        (*current_thread).cr2 = (*context).cr2;
+        (*current_thread).err_code = (*context).err_code;
+    }
+    return true;
+}
+
 /// @brief 刷新指定进程的sighand的sigaction,将满足条件的sigaction恢复为Default
 ///     除非某个信号被设置为ignore且force_default为false,否则都不会将其恢复
 ///
@@ -759,3 +766,260 @@ pub fn flush_signal_handlers(pcb: *mut process_control_block, force_default: boo
     }
     compiler_fence(core::sync::atomic::Ordering::SeqCst);
 }
+
+/// @brief 用户程序用于设置信号处理动作的函数(遵循posix2008)
+///
+/// @param regs->r8 signumber 信号的编号
+/// @param regs->r9 act 新的,将要被设置的sigaction
+/// @param regs->r10 oact 返回给用户的原本的sigaction(内核将原本的sigaction的值拷贝给这个地址)
+///
+/// @return int 错误码
+#[no_mangle]
+pub extern "C" fn sys_sigaction(regs: &mut pt_regs) -> u64 {
+    // 请注意:用户态传进来的user_sigaction结构体类型,请注意,这个结构体与内核实际的不一样
+    let act = regs.r9 as usize as *mut user_sigaction;
+    let mut old_act = regs.r10 as usize as *mut user_sigaction;
+    let mut new_ka: sigaction = Default::default();
+    let mut old_ka: sigaction = Default::default();
+
+    // 如果传入的,新的sigaction不为空
+    if !act.is_null() {
+        // 如果参数的范围不在用户空间,则返回错误
+        if unsafe { !verify_area(act as usize as u64, size_of::<sigaction>() as u64) } {
+            return (-(EFAULT as i64)) as u64;
+        }
+        let mask: sigset_t = unsafe { (*act).sa_mask };
+        let _input_sah = unsafe { (*act).sa_handler as u64 };
+
+        match _input_sah {
+            USER_SIG_DFL | USER_SIG_IGN => {
+                if _input_sah == USER_SIG_DFL {
+                    new_ka = DEFAULT_SIGACTION;
+                    new_ka.sa_flags =
+                        (unsafe { (*act).sa_flags } & (!(SA_FLAG_DFL | SA_FLAG_IGN))) | SA_FLAG_DFL;
+                } else {
+                    new_ka = DEFAULT_SIGACTION_IGNORE;
+                    new_ka.sa_flags =
+                        (unsafe { (*act).sa_flags } & (!(SA_FLAG_DFL | SA_FLAG_IGN))) | SA_FLAG_IGN;
+                }
+
+                let sar = unsafe { (*act).sa_restorer };
+                new_ka.sa_restorer = sar as u64;
+            }
+            _ => {
+                // 从用户空间获得sigaction结构体
+                new_ka = sigaction {
+                    _u: sigaction__union_u {
+                        _sa_handler: unsafe { (*act).sa_handler as u64 },
+                    },
+                    sa_flags: unsafe { (*act).sa_flags },
+                    sa_mask: sigset_t::default(),
+                    sa_restorer: unsafe { (*act).sa_restorer as u64 },
+                };
+            }
+        }
+        // 如果用户手动给了sa_restorer,那么就置位SA_FLAG_RESTORER,否则报错。(用户必须手动指定restorer)
+        if new_ka.sa_restorer != NULL as u64 {
+            new_ka.sa_flags |= SA_FLAG_RESTORER;
+        } else {
+            kwarn!(
+                "pid:{}: in sys_sigaction: User must manually sprcify a sa_restorer for signal {}.",
+                current_pcb().pid,
+                regs.r8.clone()
+            );
+        }
+        sigset_init(&mut new_ka.sa_mask, mask);
+    }
+
+    let sig = SignalNumber::from(regs.r8 as i32);
+    // 如果给出的信号值不合法
+    if sig == SignalNumber::INVALID {
+        return (-(EINVAL as i64)) as u64;
+    }
+
+    let retval = do_sigaction(
+        sig,
+        if act.is_null() {
+            None
+        } else {
+            Some(&mut new_ka)
+        },
+        if old_act.is_null() {
+            None
+        } else {
+            Some(&mut old_ka)
+        },
+    );
+
+    // 将原本的sigaction拷贝到用户程序指定的地址
+    if (retval == 0) && (!old_act.is_null()) {
+        if unsafe { !verify_area(old_act as usize as u64, size_of::<sigaction>() as u64) } {
+            return (-(EFAULT as i64)) as u64;
+        }
+        // !!!!!!!!!!todo: 检查这里old_ka的mask,是否位SIG_IGN SIG_DFL,如果是,则将_sa_handler字段替换为对应的值
+        let sah: u64;
+        let flag = old_ka.sa_flags & (SA_FLAG_DFL | SA_FLAG_IGN);
+        match flag {
+            SA_FLAG_DFL => {
+                sah = USER_SIG_DFL;
+            }
+            SA_FLAG_IGN => {
+                sah = USER_SIG_IGN;
+            }
+            _ => sah = unsafe { old_ka._u._sa_handler },
+        }
+        unsafe {
+            (*old_act).sa_handler = sah as *mut c_void;
+            (*old_act).sa_flags = old_ka.sa_flags;
+            (*old_act).sa_mask = old_ka.sa_mask;
+            (*old_act).sa_restorer = old_ka.sa_restorer as *mut c_void;
+        }
+    }
+    return retval as u64;
+}
+
+fn do_sigaction(
+    sig: SignalNumber,
+    act: Option<&mut sigaction>,
+    old_act: Option<&mut sigaction>,
+) -> i32 {
+    let pcb = current_pcb();
+
+    // 指向当前信号的action的引用
+    let action =
+        sigaction::convert_mut(unsafe { &mut (*(pcb.sighand)).action[(sig as usize) - 1] })
+            .unwrap();
+
+    spin_lock_irq(unsafe { &mut (*(pcb.sighand)).siglock });
+
+    if (action.sa_flags & SA_FLAG_IMMUTABLE) != 0 {
+        spin_unlock_irq(unsafe { &mut (*(pcb.sighand)).siglock });
+        return -(EINVAL as i32);
+    }
+
+    // 如果需要保存原有的sigaction
+    // 写的这么恶心,还得感谢rust的所有权系统...old_act的所有权被传入了这个闭包之后,必须要把所有权返回给外面。(也许是我不会用才导致写的这么丑,但是它确实能跑)
+    let old_act: Option<&mut sigaction> = {
+        if old_act.is_some() {
+            let oa = old_act.unwrap();
+            *(oa) = *action;
+            Some(oa)
+        } else {
+            None
+        }
+    };
+
+    // 清除所有的脏的sa_flags位(也就是清除那些未使用的)
+    let act = {
+        if act.is_some() {
+            let ac = act.unwrap();
+            ac.sa_flags &= SA_ALL_FLAGS;
+            Some(ac)
+        } else {
+            None
+        }
+    };
+
+    if old_act.is_some() {
+        old_act.unwrap().sa_flags &= SA_ALL_FLAGS;
+    }
+
+    if act.is_some() {
+        let ac = act.unwrap();
+        // 将act.sa_mask的SIGKILL SIGSTOP的屏蔽清除
+        sigset_delmask(
+            &mut ac.sa_mask,
+            sigmask(SignalNumber::SIGKILL) | sigmask(SignalNumber::SIGSTOP),
+        );
+
+        // 将新的sigaction拷贝到进程的action中
+        *action = *ac;
+
+        /*
+        * 根据POSIX 3.3.1.3规定:
+        * 1.不管一个信号是否被阻塞,只要将其设置SIG_IGN,如果当前已经存在了正在pending的信号,那么就把这个信号忽略。
+        *
+        * 2.不管一个信号是否被阻塞,只要将其设置SIG_DFL,如果当前已经存在了正在pending的信号,
+              并且对这个信号的默认处理方式是忽略它,那么就会把pending的信号忽略。
+        */
+        if action.ignored(sig) {
+            let mut mask: sigset_t = 0;
+            sigset_clear(&mut mask);
+            sigset_add(&mut mask, sig);
+            let sq = pcb.sig_pending.sigqueue as *mut SigQueue;
+            let sq = unsafe { sq.as_mut::<'static>() }.unwrap();
+            sq.flush_by_mask(&mask);
+
+            // todo: 当有了多个线程后,在这里进行操作,把每个线程的sigqueue都进行刷新
+        }
+    }
+
+    spin_unlock_irq(unsafe { &mut (*(pcb.sighand)).siglock });
+    return 0;
+}
+
+/// @brief 对于给定的signal number,将u64中对应的位进行置位
+pub fn sigmask(sig: SignalNumber) -> u64 {
+    // 减1的原因是,sigset的第0位表示信号1
+    return 1u64 << ((sig as i32) - 1);
+}
+
+#[no_mangle]
+pub extern "C" fn sys_rt_sigreturn(regs: &mut pt_regs) -> u64 {
+    // kdebug!(
+    //     "sigreturn, pid={}, regs.rsp=0x{:018x}",
+    //     current_pcb().pid,
+    //     regs.rsp
+    // );
+    let frame = regs.rsp as usize as *mut sigframe;
+
+    // 如果当前的rsp不来自用户态,则认为产生了错误(或被SROP攻击)
+    if unsafe { !verify_area(frame as u64, size_of::<sigframe>() as u64) } {
+        // todo:这里改为生成一个sigsegv
+        // 退出进程
+        unsafe {
+            process_do_exit(SignalNumber::SIGSEGV as u64);
+        }
+    }
+
+    let mut sigmask: sigset_t = unsafe { (*frame).context.oldmask };
+    set_current_sig_blocked(&mut sigmask);
+
+    // 从用户栈恢复sigcontext
+    if restore_sigcontext(unsafe { &mut (*frame).context }, regs) == false {
+        // todo:这里改为生成一个sigsegv
+        // 退出进程
+        unsafe {
+            process_do_exit(SignalNumber::SIGSEGV as u64);
+        }
+    }
+
+    // 由于系统调用的返回值会被系统调用模块被存放在rax寄存器,因此,为了还原原来的那个系统调用的返回值,我们需要在这里返回恢复后的rax的值
+    return regs.rax;
+}
+
+fn set_current_sig_blocked(new_set: &mut sigset_t) {
+    sigset_delmask(
+        new_set,
+        sigmask(SignalNumber::SIGKILL) | sigmask(SignalNumber::SIGSTOP),
+    );
+
+    let mut pcb = current_pcb();
+
+    /*
+        如果当前pcb的sig_blocked和新的相等,那么就不用改变它。
+        请注意,一个进程的sig_blocked字段不能被其他进程修改!
+    */
+    if sigset_equal(&pcb.sig_blocked, new_set) {
+        return;
+    }
+
+    let lock: &mut spinlock_t = &mut sighand_struct::convert_mut(pcb.sighand).unwrap().siglock;
+    spin_lock_irq(lock);
+    // todo: 当一个进程有多个线程后,在这里需要设置每个线程的block字段,并且 retarget_shared_pending(虽然我还没搞明白linux这部分是干啥的)
+
+    // 设置当前进程的sig blocked
+    pcb.sig_blocked = *new_set;
+    recalc_sigpending();
+    spin_unlock_irq(lock);
+}

+ 109 - 10
kernel/src/ipc/signal_types.rs

@@ -6,6 +6,7 @@ use core::fmt::Debug;
 
 use alloc::vec::Vec;
 
+use crate::include::bindings::bindings::NULL;
 // todo: 将这里更换为手动编写的ffi绑定
 use crate::include::bindings::bindings::atomic_t;
 use crate::include::bindings::bindings::pt_regs;
@@ -18,8 +19,12 @@ use crate::libs::refcount::RefCount;
 
 /// 请注意,sigset_t这个bitmap, 第0位表示sig=1的信号。也就是说,SignalNumber-1才是sigset_t中对应的位
 pub type sigset_t = u64;
-pub type __signalfn_t = ::core::option::Option<unsafe extern "C" fn(arg1: ::core::ffi::c_int)>;
+/// 存储信号处理函数的地址(来自用户态)
+pub type __signalfn_t = u64;
 pub type __sighandler_t = __signalfn_t;
+/// 存储信号处理恢复函数的地址(来自用户态)
+pub type __sigrestorer_fn_t = u64;
+pub type __sigrestorer_t = __sigrestorer_fn_t;
 
 /// 最大的信号数量(改动这个值的时候请同步到signal.h)
 pub const MAX_SIG_NUM: i32 = 64;
@@ -70,14 +75,27 @@ impl core::fmt::Debug for sigaction__union_u {
 
 impl Default for sigaction__union_u {
     fn default() -> Self {
-        Self { _sa_handler: None }
+        Self {
+            _sa_handler: NULL as u64,
+        }
     }
 }
 
-// ============ sigaction结构体中的的sa_flags的可选值 ===========
-pub const SA_FLAG_IGN: u64 = 1u64 << 0; // 当前sigaction表示忽略信号的动作
-pub const SA_FLAG_DFL: u64 = 1u64 << 1; // 当前sigaction表示系统默认的动作
+// ============ sigaction结构体中的的sa_flags的可选值 begin ===========
+pub const SA_FLAG_DFL: u64 = 1u64 << 0; // 当前sigaction表示系统默认的动作
+pub const SA_FLAG_IGN: u64 = 1u64 << 1; // 当前sigaction表示忽略信号的动作
 pub const SA_FLAG_RESTORER: u64 = 1u64 << 2; // 当前sigaction具有用户指定的restorer
+pub const SA_FLAG_IMMUTABLE: u64 = 1u64 << 3; // 当前sigaction不可被更改
+
+/// 所有的sa_flags的mask。(用于去除那些不存在的sa_flags位)
+pub const SA_ALL_FLAGS: u64 = SA_FLAG_IGN | SA_FLAG_DFL | SA_FLAG_RESTORER | SA_FLAG_IMMUTABLE;
+
+// ============ sigaction结构体中的的sa_flags的可选值 end ===========
+
+/// 用户态程序传入的SIG_DFL的值
+pub const USER_SIG_DFL: u64 = 1u64 << 0;
+/// 用户态程序传入的SIG_IGN的值
+pub const USER_SIG_IGN: u64 = 1u64 << 1;
 
 /**
  * @brief 信号处理结构体
@@ -87,9 +105,9 @@ pub const SA_FLAG_RESTORER: u64 = 1u64 << 2; // 当前sigaction具有用户指
 pub struct sigaction {
     pub _u: sigaction__union_u,
     pub sa_flags: u64,
-    pub sa_mask: sigset_t,
+    pub sa_mask: sigset_t, // 为了可扩展性而设置的sa_mask
     /// 信号处理函数执行结束后,将会跳转到这个函数内进行执行,然后执行sigreturn系统调用
-    pub sa_restorer: ::core::option::Option<unsafe extern "C" fn()>,
+    pub sa_restorer: __sigrestorer_t,
 }
 
 impl Default for sigaction {
@@ -103,6 +121,30 @@ impl Default for sigaction {
     }
 }
 
+impl sigaction {
+    /// @brief 判断这个sigaction是否被忽略
+    pub fn ignored(&self, _sig: SignalNumber) -> bool {
+        if (self.sa_flags & SA_FLAG_IGN) != 0 {
+            return true;
+        }
+        // todo: 增加对sa_flags为SA_FLAG_DFL,但是默认处理函数为忽略的情况的判断
+
+        return false;
+    }
+}
+
+/// @brief 用户态传入的sigaction结构体(符合posix规范)
+/// 请注意,我们会在sys_sigaction函数里面将其转换成内核使用的sigaction结构体
+#[repr(C)]
+#[derive(Debug)]
+pub struct user_sigaction {
+    pub sa_handler: *mut core::ffi::c_void,
+    pub sa_sigaction: *mut core::ffi::c_void,
+    pub sa_mask: sigset_t,
+    pub sa_flags: u64,
+    pub sa_restorer: *mut core::ffi::c_void,
+}
+
 /**
  * 信号消息的结构体,作为参数传入sigaction结构体中指向的处理函数
  */
@@ -485,6 +527,23 @@ impl SigQueue {
 
         return (filter_result.pop(), still_pending);
     }
+
+    /// @brief 从sigqueue中删除mask中被置位的信号。也就是说,比如mask的第1位被置为1,那么就从sigqueue中删除所有signum为2的信号的信息。
+    pub fn flush_by_mask(&mut self, mask: &sigset_t) {
+        // 定义过滤器,从sigqueue中删除mask中被置位的信号
+        let filter = |x: &mut siginfo| {
+            if sig_is_member(mask, SignalNumber::from(unsafe { x._sinfo.data.si_signo })) {
+                true
+            } else {
+                false
+            }
+        };
+        let filter_result: Vec<siginfo> = self.q.drain_filter(filter).collect();
+        // 回收这些siginfo
+        for x in filter_result {
+            drop(x)
+        }
+    }
 }
 
 impl Default for SigQueue {
@@ -509,8 +568,8 @@ pub fn sigset_del(set: &mut sigset_t, sig: SignalNumber) {
 
 /// @brief 将指定的信号在sigset中的对应bit进行置位
 #[inline]
-pub fn sigset_add(set: &mut sigset_t, _sig: SignalNumber) {
-    *set |= 1 << ((_sig as u32) - 1);
+pub fn sigset_add(set: &mut sigset_t, sig: SignalNumber) {
+    *set |= 1 << ((sig as u32) - 1);
 }
 
 /// @brief 将sigset清零
@@ -519,6 +578,46 @@ pub fn sigset_clear(set: &mut sigset_t) {
     *set = 0;
 }
 
+/// @brief 将mask中置为1的位,在sigset中清零
+#[inline]
+pub fn sigset_delmask(set: &mut sigset_t, mask: u64) {
+    *set &= !mask;
+}
+
+/// @brief 判断两个sigset是否相等
+#[inline]
+pub fn sigset_equal(a: &sigset_t, b: &sigset_t) -> bool {
+    if _NSIG_U64_CNT == 1{
+        return *a == *b;
+    }
+    return false;
+}
+
+/// @brief 使用指定的值,初始化sigset(为支持将来超过64个signal留下接口)
+#[inline]
+pub fn sigset_init(new_set: &mut sigset_t, mask: u64) {
+    *new_set = mask;
+    match _NSIG_U64_CNT {
+        1 => {}
+        _ => {
+            // 暂时不支持大于64个信号
+            todo!();
+        }
+    };
+}
+
+/// @brief 判断指定的信号在sigset中的对应位是否被置位
+/// @return true: 给定的信号在sigset中被置位
+/// @return false: 给定的信号在sigset中没有被置位
+#[inline]
+pub fn sig_is_member(set: &sigset_t, _sig: SignalNumber) -> bool {
+    return if 1 & (set >> ((_sig as u32) - 1)) != 0 {
+        true
+    } else {
+        false
+    };
+}
+
 #[repr(C)]
 #[derive(Debug, Clone, Copy)]
 pub struct sigframe {
@@ -544,7 +643,7 @@ pub struct sigcontext {
 
     pub regs: pt_regs, // 暂存的系统调用/中断返回时,原本要弹出的内核栈帧
     pub trap_num: u64, // 用来保存线程结构体中的trap_num字段
-    pub oldmask: u64,  // 暂存的执行信号处理函数之前的sigmask
+    pub oldmask: u64,  // 暂存的执行信号处理函数之前的,被设置block的信号
     pub cr2: u64,      // 用来保存线程结构体中的cr2字段
     pub err_code: u64, // 用来保存线程结构体中的err_code字段
     // todo: 支持x87浮点处理器后,在这里增加浮点处理器的状态结构体指针

+ 5 - 1
kernel/src/syscall/syscall.c

@@ -20,6 +20,8 @@ extern uint64_t sys_mstat(struct pt_regs *regs);
 extern uint64_t sys_open(struct pt_regs *regs);
 extern uint64_t sys_unlink_at(struct pt_regs *regs);
 extern uint64_t sys_kill(struct pt_regs *regs);
+extern uint64_t sys_sigaction(struct pt_regs * regs);
+extern uint64_t sys_rt_sigreturn(struct pt_regs * regs);
 
 /**
  * @brief 导出系统调用处理函数的符号
@@ -586,6 +588,8 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] = {
     [21] = sys_mstat,
     [22] = sys_unlink_at,
     [23] = sys_kill,
-    [24 ... 254] = system_call_not_exists,
+    [24] = sys_sigaction,
+    [25] = sys_rt_sigreturn,
+    [26 ... 254] = system_call_not_exists,
     [255] = sys_ahci_end_req,
 };

+ 5 - 3
kernel/src/syscall/syscall_num.h

@@ -32,8 +32,10 @@
 #define SYS_CLOCK 19     // 获取当前cpu时间
 #define SYS_PIPE 20      // 创建管道
 
-#define SYS_MSTAT 21     // 获取系统的内存状态信息
-#define SYS_UNLINK_AT 22 // 删除文件夹/删除文件链接
-#define SYS_KILL 23 // kill一个进程(向这个进程发出信号)
+#define SYS_MSTAT 21        // 获取系统的内存状态信息
+#define SYS_UNLINK_AT 22    // 删除文件夹/删除文件链接
+#define SYS_KILL 23         // kill一个进程(向这个进程发出信号)
+#define SYS_SIGACTION 24    // 设置进程的信号处理动作
+#define SYS_RT_SIGRETURN 25 // 从信号处理函数返回
 
 #define SYS_AHCI_END_REQ 255 // AHCI DMA请求结束end_request的系统调用

+ 26 - 6
user/apps/test_signal/main.c

@@ -1,12 +1,12 @@
 /**
- * @file main.c 
+ * @file main.c
  * @author longjin (longjin@RinGoTek.cn)
  * @brief 测试signal用的程序
  * @version 0.1
  * @date 2022-12-06
- * 
+ *
  * @copyright Copyright (c) 2022
- * 
+ *
  */
 
 /**
@@ -14,8 +14,8 @@
  * 1.在DragonOS的控制台输入 exec bin/test_signal.elf &
  *      请注意,一定要输入末尾的 '&',否则进程不会后台运行
  * 2.然后kill对应的进程的pid (上一条命令执行后,将会输出这样一行:"[1] 生成的pid")
- * 
-*/
+ *
+ */
 
 #include <libc/src/math.h>
 #include <libc/src/stdio.h>
@@ -23,16 +23,36 @@
 #include <libc/src/time.h>
 #include <libc/src/unistd.h>
 
+#include <libc/src/include/signal.h>
+
+bool handle_ok = false;
+
+void handler(int sig)
+{
+    printf("handle %d\n", sig);
+    handle_ok = true;
+}
+
 int main()
 {
     printf("Test signal running...\n");
+    signal(SIGKILL, &handler);
+    printf("registered.\n");
+
     clock_t last = clock();
     while (1)
     {
-        if ((clock()-last)/CLOCKS_PER_SEC >= 1){
+        if ((clock() - last) / CLOCKS_PER_SEC >= 1)
+        {
             // printf("Test signal running\n");
             last = clock();
         }
+        if (handle_ok)
+        {
+            printf("Handle OK!\n");
+            handle_ok = false;
+        }
     }
+
     return 0;
 }

+ 10 - 31
user/libs/libc/src/Makefile

@@ -11,6 +11,15 @@ ifeq ($(ARCH), __x86_64__)
 libc_sub_dirs += sysdeps/x86_64
 endif
 
+libc_objs:= $(shell find ./*.c)
+
+ECHO:
+	@echo "$@"
+
+
+$(libc_objs): ECHO
+	$(CC) $(CFLAGS) -c $@ -o $@.o
+
 clean:
 	cargo clean
 	rm -rf $(GARBAGE)
@@ -20,7 +29,7 @@ clean:
 		cd .. ;\
 	done
 
-libc: unistd.o fcntl.o malloc.o errno.o printf.o stdlib.o ctype.o string.o dirent.o time.o libc_rust
+libc: $(libc_objs) libc_rust
 	@list='$(libc_sub_dirs)'; for subdir in $$list; do \
     		echo "make all in $$subdir";\
     		cd $$subdir;\
@@ -28,36 +37,6 @@ libc: unistd.o fcntl.o malloc.o errno.o printf.o stdlib.o ctype.o string.o diren
     		cd ..;\
 	done
 
-unistd.o: unistd.c
-	$(CC) $(CFLAGS) -c unistd.c -o unistd.o
-
-fcntl.o: fcntl.c
-	$(CC) $(CFLAGS) -c fcntl.c -o fcntl.o
-
-malloc.o: malloc.c
-	$(CC) $(CFLAGS) -c malloc.c -o malloc.o
-
-errno.o: errno.c
-	$(CC) $(CFLAGS) -c errno.c -o errno.o
-
-printf.o: printf.c
-	$(CC) $(CFLAGS) -c printf.c -o printf.o
-
-stdlib.o: stdlib.c
-	$(CC) $(CFLAGS) -c stdlib.c -o stdlib.o
-	
-ctype.o: ctype.c
-	$(CC) $(CFLAGS) -c ctype.c -o ctype.o
-
-string.o: string.c
-	$(CC) $(CFLAGS) -c string.c -o string.o
-
-dirent.o: dirent.c
-	$(CC) $(CFLAGS) -c dirent.c -o dirent.o
-
-time.o: time.c
-	$(CC) $(CFLAGS) -c time.c -o time.o
-
 libc_rust:
 	rustup default nightly
 	cargo +nightly build --release --target ./x86_64-unknown-none.json

+ 50 - 1
user/libs/libc/src/include/signal.h

@@ -1,4 +1,5 @@
 #pragma once
+#include <libc/src/unistd.h>
 
 #define SIGHUP 1
 #define SIGINT 2
@@ -37,4 +38,52 @@
 
 /* These should not be considered constants from userland.  */
 #define SIGRTMIN 32
-#define SIGRTMAX MAX_SIG_NUM
+#define SIGRTMAX MAX_SIG_NUM
+
+typedef void (*__sighandler_t) (int);
+
+// 注意,该结构体最大16字节
+union __sifields {
+    /* kill() */
+    struct
+    {
+        pid_t _pid; /* 信号发送者的pid */
+    } _kill;
+};
+
+// 注意,该结构体最大大小为32字节
+#define __SIGINFO                                                                                                      \
+    struct                                                                                                             \
+    {                                                                                                                  \
+        int32_t si_signo; /* signal number */                                                                          \
+        int32_t si_code;                                                                                               \
+        int32_t si_errno;                                                                                              \
+        uint32_t reserved; /* 保留备用 */                                                                          \
+        union __sifields _sifields;                                                                                    \
+    }
+
+typedef struct
+{
+    union {
+        __SIGINFO;
+        uint64_t padding[4]; // 让siginfo占用32字节大小
+    };
+} siginfo_t;
+
+typedef struct
+{
+    uint64_t set;
+} sigset_t;
+
+struct sigaction
+{
+    // sa_handler和sa_sigaction二选1
+    __sighandler_t sa_handler;
+    void (*sa_sigaction)(int, siginfo_t *, void *);
+    sigset_t sa_mask;
+    uint64_t sa_flags;
+    void (*sa_restorer)(void);
+};
+
+int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
+int signal(int signum, __sighandler_t handler);

+ 44 - 0
user/libs/libc/src/signal.c

@@ -0,0 +1,44 @@
+#include <libc/src/include/signal.h>
+#include <libc/src/printf.h>
+#include <libc/src/stddef.h>
+#include <libsystem/syscall.h>
+
+#pragma GCC push_options
+#pragma GCC optimize("O0")
+void __libc_sa_restorer()
+{
+    // 在这里发起sigreturn,请注意,由于内核需要读取到原来的do_signal时保存的栈帧,因此这里不能发生函数调用(会导致函数压栈),只能够这样来完成sigreturn
+    __asm__ __volatile__("int $0x80   \n\t" ::"a"(SYS_RT_SIGRETURN) : "memory");
+}
+#pragma GCC pop_options
+
+/**
+ * @brief 设置信号处理动作(简单版本)
+ * 
+ * @param signum 
+ * @param handler 
+ * @return int 
+ */
+int signal(int signum, __sighandler_t handler)
+{
+    struct sigaction sa = {0};
+    sa.sa_handler = handler;
+    // 由于DragonOS必须由用户程序指定一个sa_restorer,因此这里设置为libc的sa_restorer
+    sa.sa_restorer = &__libc_sa_restorer;
+    // printf("handler address: %#018lx\n", handler);
+    // printf("restorer address: %#018lx\n", &__libc_sa_restorer);
+    sigaction(SIGKILL, &sa, NULL);
+}
+
+/**
+ * @brief 设置信号处理动作
+ * 
+ * @param signum 信号
+ * @param act 处理动作(不可为NULL)
+ * @param oldact 返回的旧的处理动作(若为NULL,则不返回)
+ * @return int 错误码(遵循posix)
+ */
+int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
+{
+    return syscall_invoke(SYS_SIGACTION, (uint64_t)signum, (uint64_t)act, (uint64_t)oldact, 0, 0, 0, 0, 0);
+}

+ 13 - 10
user/libs/libsystem/syscall.h

@@ -15,20 +15,22 @@
 #define SYS_BRK 9
 #define SYS_SBRK 10
 
-#define SYS_REBOOT 11   // 重启
-#define SYS_CHDIR 12    // 切换工作目录
+#define SYS_REBOOT 11    // 重启
+#define SYS_CHDIR 12     // 切换工作目录
 #define SYS_GET_DENTS 13 // 获取目录中的数据
-#define SYS_EXECVE 14 // 执行新的应用程序
-#define SYS_WAIT4 15 // 等待进程退出
-#define SYS_EXIT 16 // 进程退出
-#define SYS_MKDIR 17 // 创建文件夹
+#define SYS_EXECVE 14    // 执行新的应用程序
+#define SYS_WAIT4 15     // 等待进程退出
+#define SYS_EXIT 16      // 进程退出
+#define SYS_MKDIR 17     // 创建文件夹
 #define SYS_NANOSLEEP 18 // 纳秒级休眠
-#define SYS_CLOCK 19 // 获取当前cpu时间
+#define SYS_CLOCK 19     // 获取当前cpu时间
 #define SYS_PIPE 20
 
-#define SYS_MSTAT 21    // 获取系统的内存状态信息
+#define SYS_MSTAT 21        // 获取系统的内存状态信息
 #define SYS_UNLINK_AT 22    // 删除文件夹/删除文件链接
-#define SYS_KILL 23 // kill一个进程(向这个进程发出信号)
+#define SYS_KILL 23         // kill一个进程(向这个进程发出信号)
+#define SYS_SIGACTION 24    // 设置进程的信号处理动作
+#define SYS_RT_SIGRETURN 25 // 从信号处理函数返回
 
 /**
  * @brief 用户态系统调用函数
@@ -44,4 +46,5 @@
  * @param arg7
  * @return long
  */
-long syscall_invoke(uint64_t syscall_id, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7);
+long syscall_invoke(uint64_t syscall_id, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4,
+                    uint64_t arg5, uint64_t arg6, uint64_t arg7);