Support rt_sigtimedwait syscall
This commit is contained in:
parent
81da39400c
commit
53575b04cd
|
|
@ -148,7 +148,7 @@ which are summarized in the table below.
|
|||
| 125 | capget | ✅ | [⚠️](syscall-flag-coverage/namespaces-cgroups-and-security/#capget-and-capset) |
|
||||
| 126 | capset | ✅ | [⚠️](syscall-flag-coverage/namespaces-cgroups-and-security/#capget-and-capset) |
|
||||
| 127 | rt_sigpending | ✅ | 💯 |
|
||||
| 128 | rt_sigtimedwait | ❌ | N/A |
|
||||
| 128 | rt_sigtimedwait | ✅ | 💯 |
|
||||
| 129 | rt_sigqueueinfo | ❌ | N/A |
|
||||
| 130 | rt_sigsuspend | ✅ | 💯 |
|
||||
| 131 | sigaltstack | ✅ | ❓ |
|
||||
|
|
|
|||
|
|
@ -33,3 +33,6 @@ gettimeofday(tv, tz);
|
|||
|
||||
// Get time in seconds
|
||||
time(tloc);
|
||||
|
||||
// Synchronously wait for a signal with a timeout
|
||||
rt_sigtimedwait(set, info, timeout, sigsetsize);
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ use super::{
|
|||
rt_sigprocmask::sys_rt_sigprocmask,
|
||||
rt_sigreturn::sys_rt_sigreturn,
|
||||
rt_sigsuspend::sys_rt_sigsuspend,
|
||||
rt_sigtimedwait::sys_rt_sigtimedwait,
|
||||
sched_affinity::{sys_sched_getaffinity, sys_sched_setaffinity},
|
||||
sched_get_priority_max::sys_sched_get_priority_max,
|
||||
sched_get_priority_min::sys_sched_get_priority_min,
|
||||
|
|
@ -271,6 +272,7 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||
SYS_RT_SIGACTION = 134 => sys_rt_sigaction(args[..4]);
|
||||
SYS_RT_SIGPROCMASK = 135 => sys_rt_sigprocmask(args[..4]);
|
||||
SYS_RT_SIGPENDING = 136 => sys_rt_sigpending(args[..2]);
|
||||
SYS_RT_SIGTIMEDWAIT = 137 => sys_rt_sigtimedwait(args[..4]);
|
||||
SYS_RT_SIGRETURN = 139 => sys_rt_sigreturn(args[..0], &mut user_ctx);
|
||||
SYS_SET_PRIORITY = 140 => sys_set_priority(args[..3]);
|
||||
SYS_GET_PRIORITY = 141 => sys_get_priority(args[..2]);
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ use super::{
|
|||
rt_sigprocmask::sys_rt_sigprocmask,
|
||||
rt_sigreturn::sys_rt_sigreturn,
|
||||
rt_sigsuspend::sys_rt_sigsuspend,
|
||||
rt_sigtimedwait::sys_rt_sigtimedwait,
|
||||
sched_affinity::{sys_sched_getaffinity, sys_sched_setaffinity},
|
||||
sched_get_priority_max::sys_sched_get_priority_max,
|
||||
sched_get_priority_min::sys_sched_get_priority_min,
|
||||
|
|
@ -271,6 +272,7 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||
SYS_RT_SIGACTION = 134 => sys_rt_sigaction(args[..4]);
|
||||
SYS_RT_SIGPROCMASK = 135 => sys_rt_sigprocmask(args[..4]);
|
||||
SYS_RT_SIGPENDING = 136 => sys_rt_sigpending(args[..2]);
|
||||
SYS_RT_SIGTIMEDWAIT = 137 => sys_rt_sigtimedwait(args[..4]);
|
||||
SYS_RT_SIGRETURN = 139 => sys_rt_sigreturn(args[..0], &mut user_ctx);
|
||||
SYS_SET_PRIORITY = 140 => sys_set_priority(args[..3]);
|
||||
SYS_GET_PRIORITY = 141 => sys_get_priority(args[..2]);
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ use super::{
|
|||
rt_sigprocmask::sys_rt_sigprocmask,
|
||||
rt_sigreturn::sys_rt_sigreturn,
|
||||
rt_sigsuspend::sys_rt_sigsuspend,
|
||||
rt_sigtimedwait::sys_rt_sigtimedwait,
|
||||
sched_affinity::{sys_sched_getaffinity, sys_sched_setaffinity},
|
||||
sched_get_priority_max::sys_sched_get_priority_max,
|
||||
sched_get_priority_min::sys_sched_get_priority_min,
|
||||
|
|
@ -291,6 +292,7 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||
SYS_CAPGET = 125 => sys_capget(args[..2]);
|
||||
SYS_CAPSET = 126 => sys_capset(args[..2]);
|
||||
SYS_RT_SIGPENDING = 127 => sys_rt_sigpending(args[..2]);
|
||||
SYS_RT_SIGTIMEDWAIT = 128 => sys_rt_sigtimedwait(args[..4]);
|
||||
SYS_RT_SIGSUSPEND = 130 => sys_rt_sigsuspend(args[..2]);
|
||||
SYS_SIGALTSTACK = 131 => sys_sigaltstack(args[..2], &user_ctx);
|
||||
SYS_UTIME = 132 => sys_utime(args[..2]);
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ mod rt_sigpending;
|
|||
mod rt_sigprocmask;
|
||||
mod rt_sigreturn;
|
||||
mod rt_sigsuspend;
|
||||
mod rt_sigtimedwait;
|
||||
mod sched_affinity;
|
||||
mod sched_get_priority_max;
|
||||
mod sched_get_priority_min;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::{sync::atomic::Ordering, time::Duration};
|
||||
|
||||
use ostd::{mm::VmIo, sync::Waiter};
|
||||
|
||||
use super::SyscallReturn;
|
||||
use crate::{
|
||||
prelude::*,
|
||||
process::signal::{
|
||||
HandlePendingSignal,
|
||||
constants::{SIGKILL, SIGSTOP},
|
||||
sig_mask::{SigMask, SigSet},
|
||||
signals::Signal,
|
||||
with_sigmask_changed,
|
||||
},
|
||||
time::{timespec_t, wait::ManagedTimeout},
|
||||
};
|
||||
|
||||
pub fn sys_rt_sigtimedwait(
|
||||
set_ptr: Vaddr,
|
||||
info_ptr: Vaddr,
|
||||
timeout_ptr: Vaddr,
|
||||
sigset_size: usize,
|
||||
ctx: &Context,
|
||||
) -> Result<SyscallReturn> {
|
||||
debug!(
|
||||
"set_ptr = {:#?}, info_ptr = {:#?}, timeout_ptr = {:#?}, sigset_size = {}",
|
||||
set_ptr, info_ptr, timeout_ptr, sigset_size
|
||||
);
|
||||
|
||||
// Validate sigset size
|
||||
if sigset_size != size_of::<SigMask>() {
|
||||
return_errno_with_message!(Errno::EINVAL, "invalid sigset size");
|
||||
}
|
||||
|
||||
// Read the signal set
|
||||
let mask = {
|
||||
let mut set: SigSet = ctx.user_space().read_val(set_ptr)?;
|
||||
|
||||
// Remove SIGKILL and SIGSTOP as they cannot be waited for
|
||||
set -= SIGKILL;
|
||||
set -= SIGSTOP;
|
||||
|
||||
!set
|
||||
};
|
||||
|
||||
// Read timeout if provided
|
||||
let timeout = if timeout_ptr != 0 {
|
||||
let timespec: timespec_t = ctx.user_space().read_val(timeout_ptr)?;
|
||||
Some(Duration::try_from(timespec)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
debug!(
|
||||
"pid = {}, sig_mask = {:?}, timeout = {:?}",
|
||||
ctx.process.pid(),
|
||||
mask,
|
||||
timeout
|
||||
);
|
||||
|
||||
let block_list = ctx.posix_thread.sig_mask().load(Ordering::Relaxed);
|
||||
// Fast path: If a signal is already pending, dequeue and return it immediately.
|
||||
if let Some(signal) = dequeue_signal_with_checking_ignore(ctx, mask, block_list) {
|
||||
if info_ptr != 0 {
|
||||
let siginfo = signal.to_info();
|
||||
ctx.user_space().write_val(info_ptr, &siginfo)?;
|
||||
}
|
||||
|
||||
return Ok(SyscallReturn::Return(signal.num().as_u8() as _));
|
||||
}
|
||||
|
||||
with_sigmask_changed(
|
||||
ctx,
|
||||
|sig_mask| sig_mask & mask,
|
||||
|| {
|
||||
// Wait for a signal to arrive or timeout.
|
||||
let waiter = Waiter::new_pair().0;
|
||||
let signal = waiter
|
||||
.pause_until_or_timeout(
|
||||
|| dequeue_signal_with_checking_ignore(ctx, mask, block_list),
|
||||
timeout.map(ManagedTimeout::new),
|
||||
)
|
||||
.map_err(|e| {
|
||||
if e.error() == Errno::ETIME {
|
||||
Error::new(Errno::EAGAIN)
|
||||
} else {
|
||||
e
|
||||
}
|
||||
})?;
|
||||
|
||||
if info_ptr != 0 {
|
||||
let siginfo = signal.to_info();
|
||||
ctx.user_space().write_val(info_ptr, &siginfo)?;
|
||||
}
|
||||
|
||||
Ok(SyscallReturn::Return(signal.num().as_u8() as _))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Dequeue a signal from the thread's pending signal queue.
|
||||
///
|
||||
/// If the signal is ignored and not blocked, it will be dropped and
|
||||
/// the next signal will be checked.
|
||||
fn dequeue_signal_with_checking_ignore(
|
||||
ctx: &Context,
|
||||
mask: SigMask,
|
||||
block_list: SigMask,
|
||||
) -> Option<Box<dyn Signal>> {
|
||||
let sig_dispositions = ctx.process.sig_dispositions().lock();
|
||||
let sig_disposition = sig_dispositions.lock();
|
||||
while let Some(signal) = ctx.posix_thread.dequeue_signal(&mask) {
|
||||
// If the signal is ignored and not blocked, the signal will be directly dropped.
|
||||
if !block_list.contains(signal.num()) && sig_disposition.will_ignore(signal.as_ref()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return Some(signal);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
Loading…
Reference in New Issue