diff --git a/docs/src/kernel/linux-compatibility.md b/docs/src/kernel/linux-compatibility.md index ae215fba8..55496dd93 100644 --- a/docs/src/kernel/linux-compatibility.md +++ b/docs/src/kernel/linux-compatibility.md @@ -150,7 +150,7 @@ provided by Linux on x86-64 architecture. | 127 | rt_sigpending | ❌ | | 128 | rt_sigtimedwait | ❌ | | 129 | rt_sigqueueinfo | ❌ | -| 130 | rt_sigsuspend | ❌ | +| 130 | rt_sigsuspend | ✅ | | 131 | sigaltstack | ✅ | | 132 | utime | ❌ | | 133 | mknod | ❌ | diff --git a/kernel/aster-nix/src/process/signal/sig_mask.rs b/kernel/aster-nix/src/process/signal/sig_mask.rs index d0565f13f..12440c7ec 100644 --- a/kernel/aster-nix/src/process/signal/sig_mask.rs +++ b/kernel/aster-nix/src/process/signal/sig_mask.rs @@ -1,8 +1,10 @@ // SPDX-License-Identifier: MPL-2.0 use super::{constants::MIN_STD_SIG_NUM, sig_num::SigNum}; +use crate::prelude::*; -#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Pod)] +#[repr(C)] pub struct SigMask { bits: u64, } diff --git a/kernel/aster-nix/src/syscall/mod.rs b/kernel/aster-nix/src/syscall/mod.rs index 82932211e..2739d4359 100644 --- a/kernel/aster-nix/src/syscall/mod.rs +++ b/kernel/aster-nix/src/syscall/mod.rs @@ -22,6 +22,7 @@ use self::{ listen::sys_listen, pread64::sys_pread64, recvfrom::sys_recvfrom, + rt_sigsuspend::sys_rt_sigsuspend, sendto::sys_sendto, setfsgid::sys_setfsgid, setfsuid::sys_setfsuid, @@ -191,6 +192,7 @@ mod rmdir; mod rt_sigaction; mod rt_sigprocmask; mod rt_sigreturn; +mod rt_sigsuspend; mod sched_yield; mod select; mod sendto; @@ -352,6 +354,7 @@ define_syscall_nums!( SYS_SETFSUID = 122, SYS_SETFSGID = 123, SYS_GETSID = 124, + SYS_RT_SIGSUSPEND = 130, SYS_SIGALTSTACK = 131, SYS_STATFS = 137, SYS_FSTATFS = 138, @@ -544,6 +547,7 @@ pub fn syscall_dispatch( SYS_SETFSUID => syscall_handler!(1, sys_setfsuid, args), SYS_SETFSGID => syscall_handler!(1, sys_setfsgid, args), SYS_GETSID => syscall_handler!(1, sys_getsid, args), + SYS_RT_SIGSUSPEND => syscall_handler!(2, sys_rt_sigsuspend, args), SYS_SIGALTSTACK => syscall_handler!(2, sys_sigaltstack, args), SYS_STATFS => syscall_handler!(2, sys_statfs, args), SYS_FSTATFS => syscall_handler!(2, sys_fstatfs, args), diff --git a/kernel/aster-nix/src/syscall/rt_sigsuspend.rs b/kernel/aster-nix/src/syscall/rt_sigsuspend.rs new file mode 100644 index 000000000..52d091b37 --- /dev/null +++ b/kernel/aster-nix/src/syscall/rt_sigsuspend.rs @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MPL-2.0 + +use super::{SyscallReturn, SYS_RT_SIGSUSPEND}; +use crate::{ + log_syscall_entry, + prelude::*, + process::signal::{ + constants::{SIGKILL, SIGSTOP}, + sig_mask::SigMask, + Pauser, + }, + util::read_val_from_user, +}; + +pub fn sys_rt_sigsuspend(sigmask_addr: Vaddr, sigmask_size: usize) -> Result { + log_syscall_entry!(SYS_RT_SIGSUSPEND); + debug!( + "sigmask_addr = 0x{:x}, sigmask_size = {}", + sigmask_addr, sigmask_size + ); + + debug_assert!(sigmask_size == core::mem::size_of::()); + if sigmask_size != core::mem::size_of::() { + return_errno_with_message!(Errno::EINVAL, "invalid sigmask size"); + } + + let sigmask = { + let mut mask: SigMask = read_val_from_user(sigmask_addr)?; + // It is not possible to block SIGKILL or SIGSTOP, + // specifying these signals in mask has no effect. + mask.remove_signal(SIGKILL); + mask.remove_signal(SIGSTOP); + mask + }; + + // Pause until receiving any signal + let pauser = Pauser::new_with_mask(sigmask); + pauser.pause_until(|| None::<()>)?; + + // This syscall should always return `Err(EINTR)`. This path should never be reached. + unreachable!("rt_sigsuspend always return EINTR"); +}