Add syscall ppoll

This commit is contained in:
jiangjianfeng
2025-04-16 08:44:06 +00:00
committed by Tate, Hongliang Tian
parent 1fe0fef410
commit 8815ca384f
12 changed files with 178 additions and 92 deletions

View File

@ -73,6 +73,7 @@ use crate::syscall::{
pause::sys_pause,
pipe::{sys_pipe, sys_pipe2},
poll::sys_poll,
ppoll::sys_ppoll,
prctl::sys_prctl,
pread64::sys_pread64,
preadv::{sys_preadv, sys_preadv2, sys_readv},
@ -336,6 +337,7 @@ impl_syscall_nums_and_dispatch_fn! {
SYS_FCHMODAT = 268 => sys_fchmodat(args[..3]);
SYS_FACCESSAT = 269 => sys_faccessat(args[..3]);
SYS_PSELECT6 = 270 => sys_pselect6(args[..6]);
SYS_PPOLL = 271 => sys_ppoll(args[..5]);
SYS_SET_ROBUST_LIST = 273 => sys_set_robust_list(args[..2]);
SYS_UTIMENSAT = 280 => sys_utimensat(args[..4]);
SYS_EPOLL_PWAIT = 281 => sys_epoll_pwait(args[..6]);

View File

@ -80,6 +80,7 @@ mod open;
mod pause;
mod pipe;
mod poll;
mod ppoll;
mod prctl;
mod pread64;
mod preadv;

View File

@ -10,10 +10,38 @@ use crate::{
file_table::{FileDesc, FileTable},
},
prelude::*,
process::signal::Poller,
process::{signal::Poller, ResourceType},
};
pub fn sys_poll(fds: Vaddr, nfds: u64, timeout: i32, ctx: &Context) -> Result<SyscallReturn> {
pub fn sys_poll(fds: Vaddr, nfds: u32, timeout: i32, ctx: &Context) -> Result<SyscallReturn> {
let timeout = if timeout >= 0 {
Some(Duration::from_millis(timeout as _))
} else {
None
};
do_sys_poll(fds, nfds, timeout, ctx)
}
pub fn do_sys_poll(
fds: Vaddr,
nfds: u32,
timeout: Option<Duration>,
ctx: &Context,
) -> Result<SyscallReturn> {
if nfds as u64
> ctx
.process
.resource_limits()
.get_rlimit(ResourceType::RLIMIT_NOFILE)
.get_cur()
{
return_errno_with_message!(
Errno::EINVAL,
"the `nfds` value exceeds the `RLIMIT_NOFILE` value"
)
}
let user_space = ctx.user_space();
let poll_fds = {
@ -33,12 +61,6 @@ pub fn sys_poll(fds: Vaddr, nfds: u64, timeout: i32, ctx: &Context) -> Result<Sy
poll_fds
};
let timeout = if timeout >= 0 {
Some(Duration::from_millis(timeout as _))
} else {
None
};
debug!(
"poll_fds = {:?}, nfds = {}, timeout = {:?}",
poll_fds, nfds, timeout

View File

@ -0,0 +1,48 @@
// SPDX-License-Identifier: MPL-2.0
use core::time::Duration;
use super::{poll::do_sys_poll, SyscallReturn};
use crate::{
prelude::*,
process::signal::{sig_mask::SigMask, with_sigmask_changed},
time::timespec_t,
};
pub fn sys_ppoll(
fds: Vaddr,
nfds: u32,
timespec_addr: Vaddr,
sigmask_addr: Vaddr,
sigmask_size: usize,
ctx: &Context,
) -> Result<SyscallReturn> {
let user_space = ctx.user_space();
let timeout = if timespec_addr != 0 {
let time_spec = user_space.read_val::<timespec_t>(timespec_addr)?;
Some(Duration::try_from(time_spec)?)
} else {
None
};
if sigmask_addr != 0 {
if sigmask_size != size_of::<SigMask>() {
return_errno_with_message!(Errno::EINVAL, "invalid sigmask size");
}
let sigmask = user_space.read_val::<SigMask>(sigmask_addr)?;
with_sigmask_changed(ctx, |_| sigmask, || do_sys_poll(fds, nfds, timeout, ctx))
} else {
do_sys_poll(fds, nfds, timeout, ctx)
}
// TODO: Write back the remaining time to `timespec_addr`.
//
// The ppoll system call should write back the remaining time,
// yet the function counterpart in libc hides this behavior to
// make the API more portable across different UNIX-like OSes.
// For the maximized Linux compatibility, we should follow Linux's behavior.
// But this cannot be readily achieved given how our internal synchronization primitives
// such as `Pause` and `WaitTimeout` work.
}

View File

@ -1,10 +1,13 @@
// SPDX-License-Identifier: MPL-2.0
use core::{sync::atomic::Ordering, time::Duration};
use core::time::Duration;
use super::{select::do_sys_select, SyscallReturn};
use crate::{
fs::file_table::FileDesc, prelude::*, process::signal::sig_mask::SigMask, time::timespec_t,
fs::file_table::FileDesc,
prelude::*,
process::signal::{sig_mask::SigMask, with_sigmask_changed},
time::timespec_t,
};
pub fn sys_pselect6(
@ -17,45 +20,34 @@ pub fn sys_pselect6(
ctx: &Context,
) -> Result<SyscallReturn> {
let user_space = ctx.user_space();
let old_simask = if sigmask_addr != 0 {
let sigmask_with_size: SigMaskWithSize = user_space.read_val(sigmask_addr)?;
if !sigmask_with_size.is_valid() {
return_errno_with_message!(Errno::EINVAL, "sigmask size is invalid")
}
let old_sigmask = ctx
.posix_thread
.sig_mask()
.swap(sigmask_with_size.sigmask, Ordering::Relaxed);
Some(old_sigmask)
} else {
None
};
let timeout = if timespec_addr != 0 {
let time_spec: timespec_t = user_space.read_val(timespec_addr)?;
let time_spec = user_space.read_val::<timespec_t>(timespec_addr)?;
Some(Duration::try_from(time_spec)?)
} else {
None
};
let res = do_sys_select(
nfds,
readfds_addr,
writefds_addr,
exceptfds_addr,
timeout,
ctx,
);
let operate = || {
do_sys_select(
nfds,
readfds_addr,
writefds_addr,
exceptfds_addr,
timeout,
ctx,
)
};
if let Some(old_mask) = old_simask {
ctx.posix_thread
.sig_mask()
.store(old_mask, Ordering::Relaxed);
if sigmask_addr != 0 {
let sigmask_with_size = user_space.read_val::<SigMaskWithSize>(sigmask_addr)?;
if !sigmask_with_size.is_valid() {
return_errno_with_message!(Errno::EINVAL, "sigmask size is invalid")
}
with_sigmask_changed(ctx, |_: SigMask| sigmask_with_size.sigmask, operate)
} else {
operate()
}
res
}
#[repr(C)]

View File

@ -8,7 +8,7 @@ use crate::{
process::signal::{
constants::{SIGKILL, SIGSTOP},
sig_mask::SigMask,
with_signal_blocked,
with_sigmask_changed,
},
};
@ -37,7 +37,11 @@ pub fn sys_rt_sigsuspend(
// Wait until receiving any signal
let waiter = Waiter::new_pair().0;
with_signal_blocked(ctx, sigmask, || waiter.pause_until(|| None::<()>))?;
with_sigmask_changed(
ctx,
|old_mask| old_mask + sigmask,
|| waiter.pause_until(|| None::<()>),
)?;
// This syscall should always return `Err(EINTR)`. This path should never be reached.
unreachable!("rt_sigsuspend always return EINTR");