feat: 实现ppoll系统调用并优化poll相关功能 (#1127)

- 新增ppoll系统调用,支持信号屏蔽和精确超时控制
- 优化poll系统调用,修复超时处理逻辑
- 新增ProcessControlBlock::has_pending_not_masked_signal方法,优化信号检测
- 添加Instant::saturating_sub方法,改进时间计算
- 新增rt_sigpending系统调用,支持获取待处理信号
- 添加ppoll测试程序,验证ppoll功能

Signed-off-by: longjin <longjin@DragonOS.org>
This commit is contained in:
LoGin
2025-04-02 21:10:52 +08:00
committed by GitHub
parent 91cc4adba9
commit 2d06264d79
11 changed files with 384 additions and 22 deletions

View File

@ -1,12 +1,18 @@
use core::ffi::c_int;
use crate::{
ipc::signal::{RestartBlock, RestartBlockData, RestartFn},
arch::ipc::signal::SigSet,
ipc::signal::{
restore_saved_sigmask_unless, set_user_sigmask, RestartBlock, RestartBlockData, RestartFn,
},
mm::VirtAddr,
net::event_poll::{EPollCtlOption, EPollEvent, EPollEventType, EventPoll},
process::ProcessManager,
syscall::{user_access::UserBufferWriter, Syscall},
time::{Duration, Instant},
syscall::{
user_access::{UserBufferReader, UserBufferWriter},
Syscall,
},
time::{Duration, Instant, PosixTimeSpec},
};
use super::vfs::file::{File, FileMode};
@ -32,11 +38,15 @@ impl<'a> PollAdapter<'a> {
}
fn add_pollfds(&self) -> Result<(), SystemError> {
for pollfd in self.poll_fds.iter() {
for (i, pollfd) in self.poll_fds.iter().enumerate() {
if pollfd.fd < 0 {
continue;
}
let mut epoll_event = EPollEvent::default();
let poll_flags = PollFlags::from_bits_truncate(pollfd.events);
let ep_events: EPollEventType = poll_flags.into();
epoll_event.set_events(ep_events.bits());
epoll_event.set_data(i as u64);
EventPoll::epoll_ctl_with_epfile(
self.ep_file.clone(),
@ -64,8 +74,13 @@ impl<'a> PollAdapter<'a> {
remain_timeout,
)?;
for (i, event) in epoll_events.iter().enumerate() {
self.poll_fds[i].revents = (event.events() & 0xffff) as u16;
for event in epoll_events.iter() {
let index = event.data() as usize;
if index >= self.poll_fds.len() {
log::warn!("poll_all_fds: Invalid index in epoll event: {}", index);
continue;
}
self.poll_fds[index].revents = (event.events() & 0xffff) as u16;
}
Ok(events)
@ -74,13 +89,14 @@ impl<'a> PollAdapter<'a> {
impl Syscall {
/// https://code.dragonos.org.cn/xref/linux-6.6.21/fs/select.c#1068
#[inline(never)]
pub fn poll(pollfd_ptr: usize, nfds: u32, timeout_ms: i32) -> Result<usize, SystemError> {
let pollfd_ptr = VirtAddr::new(pollfd_ptr);
let len = nfds as usize * core::mem::size_of::<PollFd>();
let mut timeout: Option<Instant> = None;
if timeout_ms >= 0 {
timeout = poll_select_set_timeout(timeout_ms);
timeout = poll_select_set_timeout(timeout_ms as u64);
}
let mut poll_fds_writer = UserBufferWriter::new(pollfd_ptr.as_ptr::<PollFd>(), len, true)?;
let mut r = do_sys_poll(poll_fds_writer.buffer(0)?, timeout);
@ -92,15 +108,58 @@ impl Syscall {
return r;
}
}
/// 计算超时的时刻
fn poll_select_set_timeout(timeout_ms: i32) -> Option<Instant> {
if timeout_ms == 0 {
return None;
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/select.c#1101
#[inline(never)]
pub fn ppoll(
pollfd_ptr: usize,
nfds: u32,
timespec_ptr: usize,
sigmask_ptr: usize,
) -> Result<usize, SystemError> {
let mut timeout_ts: Option<Instant> = None;
let mut sigmask: Option<SigSet> = None;
let pollfd_ptr = VirtAddr::new(pollfd_ptr);
let pollfds_len = nfds as usize * core::mem::size_of::<PollFd>();
let mut poll_fds_writer =
UserBufferWriter::new(pollfd_ptr.as_ptr::<PollFd>(), pollfds_len, true)?;
let poll_fds = poll_fds_writer.buffer(0)?;
if sigmask_ptr != 0 {
let sigmask_reader =
UserBufferReader::new(sigmask_ptr as *const SigSet, size_of::<SigSet>(), true)?;
sigmask = Some(*sigmask_reader.read_one_from_user(0)?);
}
if timespec_ptr != 0 {
let tsreader = UserBufferReader::new(
timespec_ptr as *const PosixTimeSpec,
size_of::<PosixTimeSpec>(),
true,
)?;
let ts: PosixTimeSpec = *tsreader.read_one_from_user(0)?;
let timeout_ms = ts.tv_sec * 1000 + ts.tv_nsec / 1_000_000;
if timeout_ms >= 0 {
timeout_ts =
Some(poll_select_set_timeout(timeout_ms as u64).ok_or(SystemError::EINVAL)?);
}
}
if let Some(mut sigmask) = sigmask {
set_user_sigmask(&mut sigmask);
}
// log::debug!(
// "ppoll: poll_fds: {:?}, nfds: {}, timeout_ts: {:?}sigmask: {:?}",
// poll_fds,
// nfds,
// timeout_ts,
// sigmask
// );
let r: Result<usize, SystemError> = do_sys_poll(poll_fds, timeout_ts);
return poll_select_finish(timeout_ts, timespec_ptr, PollTimeType::TimeSpec, r);
}
Some(Instant::now() + Duration::from_millis(timeout_ms as u64))
}
fn do_sys_poll(poll_fds: &mut [PollFd], timeout: Option<Instant>) -> Result<usize, SystemError> {
@ -115,6 +174,75 @@ fn do_sys_poll(poll_fds: &mut [PollFd], timeout: Option<Instant>) -> Result<usiz
Ok(nevents)
}
/// 计算超时的时刻
fn poll_select_set_timeout(timeout_ms: u64) -> Option<Instant> {
if timeout_ms == 0 {
return None;
}
Some(Instant::now() + Duration::from_millis(timeout_ms))
}
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/fs/select.c#298
fn poll_select_finish(
end_time: Option<Instant>,
user_time_ptr: usize,
poll_time_type: PollTimeType,
mut result: Result<usize, SystemError>,
) -> Result<usize, SystemError> {
restore_saved_sigmask_unless(result == Err(SystemError::ERESTARTNOHAND));
if user_time_ptr == 0 {
return result;
}
// todo: 处理sticky timeouts
if end_time.is_none() {
return result;
}
let end_time = end_time.unwrap();
// no update for zero timeout
if end_time.total_millis() <= 0 {
return result;
}
let ts = Instant::now();
let duration = end_time.saturating_sub(ts);
let rts: PosixTimeSpec = duration.into();
match poll_time_type {
PollTimeType::TimeSpec => {
let mut tswriter = UserBufferWriter::new(
user_time_ptr as *mut PosixTimeSpec,
size_of::<PosixTimeSpec>(),
true,
)?;
if tswriter.copy_one_to_user(&rts, 0).is_err() {
return result;
}
}
_ => todo!(),
}
if result == Err(SystemError::ERESTARTNOHAND) {
result = result.map_err(|_| SystemError::EINTR);
}
return result;
}
#[allow(unused)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum PollTimeType {
TimeVal,
OldTimeVal,
TimeSpec,
OldTimeSpec,
}
bitflags! {
pub struct PollFlags: u16 {
const POLLIN = 0x0001;

View File

@ -419,6 +419,16 @@ pub fn restore_saved_sigmask() {
}
}
pub fn restore_saved_sigmask_unless(interrupted: bool) {
if interrupted {
if !ProcessManager::current_pcb().has_pending_signal_fast() {
log::warn!("restore_saved_sigmask_unless: interrupted, but has NO pending signal");
}
} else {
restore_saved_sigmask();
}
}
/// 刷新指定进程的sighand的sigaction将满足条件的sigaction恢复为默认状态。
/// 除非某个信号被设置为忽略且 `force_default` 为 `false`,否则都不会将其恢复。
///

View File

@ -78,7 +78,11 @@ impl SignalStruct {
let mut r = Self {
inner: Box::<InnerSignalStruct>::default(),
};
let sig_ign = Sigaction::default();
let mut sig_ign = Sigaction::default();
// 收到忽略的信号,重启系统调用
// todo: 看看linux哪些
sig_ign.flags_mut().insert(SigFlags::SA_RESTART);
r.inner.handlers[Signal::SIGCHLD as usize - 1] = sig_ign;
r.inner.handlers[Signal::SIGURG as usize - 1] = sig_ign;
r.inner.handlers[Signal::SIGWINCH as usize - 1] = sig_ign;

View File

@ -562,4 +562,28 @@ impl Syscall {
return Ok(0);
}
}
#[inline(never)]
pub fn rt_sigpending(user_sigset_ptr: usize, sigsetsize: usize) -> Result<usize, SystemError> {
if sigsetsize != size_of::<SigSet>() {
return Err(SystemError::EINVAL);
}
let mut user_buffer_writer =
UserBufferWriter::new(user_sigset_ptr as *mut SigSet, size_of::<SigSet>(), true)?;
let pcb = ProcessManager::current_pcb();
let siginfo_guard = pcb.sig_info_irqsave();
let pending_set = siginfo_guard.sig_pending().signal();
let shared_pending_set = siginfo_guard.sig_shared_pending().signal();
let blocked_set = *siginfo_guard.sig_blocked();
drop(siginfo_guard);
let mut result = pending_set.union(shared_pending_set);
result = result.difference(blocked_set);
user_buffer_writer.copy_one_to_user(&result, 0)?;
Ok(0)
}
}

View File

@ -531,8 +531,10 @@ impl EventPoll {
continue;
}
// 如果有未处理的信号则返回错误
if current_pcb.has_pending_signal_fast() {
// 如果有未处理且未被屏蔽的信号则返回错误
if current_pcb.has_pending_signal_fast()
&& current_pcb.has_pending_not_masked_signal()
{
return Err(SystemError::ERESTARTSYS);
}
@ -858,6 +860,14 @@ impl EPollEvent {
pub fn events(&self) -> u32 {
self.events
}
pub fn set_data(&mut self, data: u64) {
self.data = data;
}
pub fn data(&self) -> u64 {
self.data
}
}
/// ## epoll_ctl函数的参数

View File

@ -1071,6 +1071,24 @@ impl ProcessControlBlock {
self.flags.get().contains(ProcessFlags::HAS_PENDING_SIGNAL)
}
/// 检查当前进程是否有未被阻塞的待处理信号。
///
/// 注:该函数较慢,因此需要与 has_pending_signal_fast 一起使用。
pub fn has_pending_not_masked_signal(&self) -> bool {
let sig_info = self.sig_info_irqsave();
let blocked: SigSet = *sig_info.sig_blocked();
let mut pending: SigSet = sig_info.sig_pending().signal();
drop(sig_info);
pending.remove(blocked);
// log::debug!(
// "pending and not masked:{:?}, masked: {:?}",
// pending,
// blocked
// );
let has_not_masked = !pending.is_empty();
return has_not_masked;
}
pub fn sig_struct(&self) -> SpinLockGuard<SignalStruct> {
self.sig_struct.lock_irqsave()
}

View File

@ -883,10 +883,7 @@ impl Syscall {
Self::poll(fds, nfds, timeout)
}
SYS_PPOLL => {
log::warn!("SYS_PPOLL has not yet been implemented");
Ok(0)
}
SYS_PPOLL => Self::ppoll(args[0], args[1] as u32, args[2], args[3]),
SYS_SETPGID => {
warn!("SYS_SETPGID has not yet been implemented");
@ -1233,6 +1230,7 @@ impl Syscall {
}
SYS_SETRLIMIT => Ok(0),
SYS_RESTART_SYSCALL => Self::restart_syscall(),
SYS_RT_SIGPENDING => Self::rt_sigpending(args[0], args[1]),
_ => panic!("Unsupported syscall ID: {}", syscall_num),
};

View File

@ -288,6 +288,23 @@ impl Instant {
let micros_diff = self.micros - earlier.micros;
Some(Duration::from_micros(micros_diff as u64))
}
/// Saturating subtraction. Computes `self - other`, returning [`Instant::ZERO`] if the result would be negative.
///
/// # Arguments
///
/// * `other` - The `Instant` to subtract from `self`.
///
/// # Returns
///
/// The duration between `self` and `other`, or [`Instant::ZERO`] if `other` is later than `self`.
pub fn saturating_sub(self, other: Instant) -> Duration {
if self.micros >= other.micros {
Duration::from_micros((self.micros - other.micros) as u64)
} else {
Duration::ZERO
}
}
}
impl fmt::Display for Instant {