Add syscall rt_sigpending

This commit is contained in:
anbo 2024-06-03 15:03:15 +08:00 committed by Tate, Hongliang Tian
parent 6c34db52b3
commit 901bccadfe
8 changed files with 167 additions and 5 deletions

View File

@ -147,7 +147,7 @@ provided by Linux on x86-64 architecture.
| 124 | getsid | ✅ |
| 125 | capget | ❌ |
| 126 | capset | ❌ |
| 127 | rt_sigpending | |
| 127 | rt_sigpending | |
| 128 | rt_sigtimedwait | ❌ |
| 129 | rt_sigqueueinfo | ❌ |
| 130 | rt_sigsuspend | ✅ |

View File

@ -8,8 +8,11 @@ use super::{
do_exit_group,
kill::SignalSenderIds,
signal::{
sig_mask::SigMask, sig_num::SigNum, sig_queues::SigQueues, signals::Signal, SigEvents,
SigEventsFilter, SigStack,
sig_mask::{SigMask, SigSet},
sig_num::SigNum,
sig_queues::SigQueues,
signals::Signal,
SigEvents, SigEventsFilter, SigStack,
},
Credentials, Process, TermStatus,
};
@ -82,6 +85,10 @@ impl PosixThread {
&self.sig_mask
}
pub fn sig_pending(&self) -> SigSet {
self.sig_queues.sig_pending()
}
pub fn has_pending_signal(&self) -> bool {
!self.sig_queues.is_empty()
}

View File

@ -3,9 +3,12 @@
use super::{constants::MIN_STD_SIG_NUM, sig_num::SigNum};
use crate::prelude::*;
/// A signal mask.
pub type SigMask = SigSet;
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Pod)]
#[repr(C)]
pub struct SigMask {
pub struct SigSet {
bits: u64,
}

View File

@ -3,7 +3,11 @@
use core::sync::atomic::{AtomicUsize, Ordering};
use super::{
constants::*, sig_mask::SigMask, sig_num::SigNum, signals::Signal, SigEvents, SigEventsFilter,
constants::*,
sig_mask::{SigMask, SigSet},
sig_num::SigNum,
signals::Signal,
SigEvents, SigEventsFilter,
};
use crate::{
events::{Observer, Subject},
@ -57,6 +61,11 @@ impl SigQueues {
signal
}
pub fn sig_pending(&self) -> SigSet {
let queues = self.queues.lock();
queues.sig_pending()
}
pub fn register_observer(
&self,
observer: Weak<dyn Observer<SigEvents>>,
@ -191,4 +200,24 @@ impl Queues {
let idx = (signum.as_u8() - MIN_RT_SIG_NUM) as usize;
&mut self.rt_queues[idx]
}
fn sig_pending(&self) -> SigSet {
let mut pending = SigSet::new_empty();
// Process standard signal queues
for (idx, signal) in self.std_queues.iter().enumerate() {
if signal.is_some() {
pending.add_signal(SigNum::from_u8(idx as u8 + MIN_STD_SIG_NUM));
}
}
// Process real-time signal queues
for (idx, signals) in self.rt_queues.iter().enumerate() {
if !signals.is_empty() {
pending.add_signal(SigNum::from_u8(idx as u8 + MIN_RT_SIG_NUM));
}
}
pending
}
}

View File

@ -69,6 +69,7 @@ use crate::syscall::{
rename::{sys_rename, sys_renameat},
rmdir::sys_rmdir,
rt_sigaction::sys_rt_sigaction,
rt_sigpending::sys_rt_sigpending,
rt_sigprocmask::sys_rt_sigprocmask,
rt_sigreturn::sys_rt_sigreturn,
rt_sigsuspend::sys_rt_sigsuspend,
@ -208,6 +209,7 @@ impl_syscall_nums_and_dispatch_fn! {
SYS_SETFSUID = 122 => sys_setfsuid(args[..1]);
SYS_SETFSGID = 123 => sys_setfsgid(args[..1]);
SYS_GETSID = 124 => sys_getsid(args[..1]);
SYS_RT_SIGPENDING = 127 => sys_rt_sigpending(args[..2]);
SYS_RT_SIGSUSPEND = 130 => sys_rt_sigsuspend(args[..2]);
SYS_SIGALTSTACK = 131 => sys_sigaltstack(args[..2]);
SYS_STATFS = 137 => sys_statfs(args[..2]);

View File

@ -76,6 +76,7 @@ mod recvfrom;
mod rename;
mod rmdir;
mod rt_sigaction;
mod rt_sigpending;
mod rt_sigprocmask;
mod rt_sigreturn;
mod rt_sigsuspend;

View File

@ -0,0 +1,30 @@
// SPDX-License-Identifier: MPL-2.0
use super::SyscallReturn;
use crate::{prelude::*, process::posix_thread::PosixThreadExt, util::write_val_to_user};
pub fn sys_rt_sigpending(u_set_ptr: Vaddr, sigset_size: usize) -> Result<SyscallReturn> {
debug!(
"u_set_ptr = 0x{:x}, sigset_size = {}",
u_set_ptr, sigset_size
);
if sigset_size != 8 {
return_errno_with_message!(Errno::EINVAL, "sigset size is not equal to 8")
}
do_rt_sigpending(u_set_ptr, sigset_size)?;
Ok(SyscallReturn::Return(0))
}
fn do_rt_sigpending(set_ptr: Vaddr, sigset_size: usize) -> Result<()> {
let current_thread = current_thread!();
let posix_thread = current_thread.as_posix_thread().unwrap();
let combined_signals = {
let sig_mask_value = posix_thread.sig_mask().lock().as_u64();
let sig_pending_value = posix_thread.sig_pending().as_u64();
sig_mask_value & sig_pending_value
};
write_val_to_user(set_ptr, &combined_signals)?;
Ok(())
}

View File

@ -364,6 +364,95 @@ int test_sigaltstack()
return 0;
}
// ============================================================================
// Test sigpending
// ============================================================================
int test_sigpending()
{
int ret;
// Set up signal handler for SIGSEGV and SIGIO
struct sigaction new_action, old_sigsegv_action, old_sigio_action;
memset(&new_action, 0, sizeof(struct sigaction));
memset(&old_sigsegv_action, 0, sizeof(struct sigaction));
new_action.sa_sigaction = handle_sigsegv;
new_action.sa_flags = SA_SIGINFO;
if (sigaction(SIGSEGV, &new_action, &old_sigsegv_action) < 0) {
THROW_ERROR("registering new signal handler failed");
}
if (old_sigsegv_action.sa_handler != SIG_DFL) {
THROW_ERROR("unexpected old sig handler");
}
memset(&new_action, 0, sizeof(struct sigaction));
memset(&old_sigio_action, 0, sizeof(struct sigaction));
new_action.sa_sigaction = handle_sigio;
new_action.sa_flags = SA_SIGINFO | SA_NODEFER;
if (sigaction(SIGIO, &new_action, &old_sigio_action) < 0) {
THROW_ERROR("registering new signal handler failed");
}
if (old_sigio_action.sa_handler != SIG_DFL) {
THROW_ERROR("unexpected old sig handler");
}
// Block SIGSEGV and SIGIO
sigset_t new_set, old_set, pending_set;
sigfillset(&new_set);
sigaddset(&new_set, SIGSEGV);
sigaddset(&new_set, SIGIO);
if ((ret = sigprocmask(SIG_BLOCK, &new_set, &old_set)) < 0) {
THROW_ERROR("sigprocmask failed unexpectedly");
}
// Send SIGSEGV and SIGIO signals to the current process twice
kill(getpid(), SIGSEGV);
kill(getpid(), SIGSEGV); // Repeat
kill(getpid(), SIGIO);
kill(getpid(), SIGIO); // Repeat
// Check for pending signals
if (sigpending(&pending_set) < 0) {
THROW_ERROR("sigpending failed unexpectedly");
}
if (!sigismember(&pending_set, SIGSEGV)) {
THROW_ERROR("SIGSEGV is not pending");
}
if (!sigismember(&pending_set, SIGIO)) {
THROW_ERROR("SIGIO (real-time signal) is not pending");
}
// Unblock all signals and check if pending signals are cleared
if (sigprocmask(SIG_SETMASK, &old_set, NULL) < 0) {
THROW_ERROR(
"sigprocmask failed unexpectedly, failed to restore signal mask");
}
// Fetch and check pending signals after unblocking
if (sigpending(&pending_set) < 0) {
THROW_ERROR("sigpending failed unexpectedly");
}
if (sigismember(&pending_set, SIGSEGV)) {
THROW_ERROR("SIGSEGV is pending");
}
if (sigismember(&pending_set, SIGIO)) {
THROW_ERROR("SIGIO (real-time signal) is pending");
}
// Restore old sigaction
if (sigaction(SIGSEGV, &old_sigsegv_action, NULL) < 0) {
THROW_ERROR("restoring old signal handler failed");
}
if (sigaction(SIGIO, &old_sigio_action, NULL) < 0) {
THROW_ERROR("restoring old signal handler failed");
}
return 0;
}
int main()
{
test_sigprocmask();
@ -372,5 +461,6 @@ int main()
test_handle_sigsegv();
test_sigchld();
test_sigaltstack();
test_sigpending();
return 0;
}