Enhance waitid syscall support

This commit is contained in:
Chen Chengjun 2025-07-21 10:37:48 +00:00 committed by Tate, Hongliang Tian
parent 4d52241c6c
commit ef0382b164
5 changed files with 94 additions and 15 deletions

View File

@ -31,7 +31,7 @@ pub use process_vm::{renew_vm_and_map, MAX_LEN_STRING_ARG, MAX_NR_STRING_ARGS};
pub use program_loader::{check_executable_file, ProgramToLoad};
pub use rlimit::ResourceType;
pub use term_status::TermStatus;
pub use wait::{do_wait, WaitOptions};
pub use wait::{do_wait, WaitOptions, WaitStatus};
pub(super) fn init() {
process::init();

View File

@ -57,6 +57,18 @@ impl siginfo_t {
self.siginfo_fields.sigfault.addr = si_addr;
}
pub fn set_pid_uid(&mut self, pid: Pid, uid: Uid) {
let pid_uid = siginfo_common_first_t {
piduid: siginfo_piduid_t { pid, uid },
};
self.siginfo_fields.common.first = pid_uid;
}
pub fn set_status(&mut self, status: i32) {
self.siginfo_fields.common.second.sigchild.status = status;
}
pub fn si_addr(&self) -> Vaddr {
read_union_field!(self, Self, siginfo_fields.sigfault.addr)
}

View File

@ -12,6 +12,7 @@ use crate::{
process_table,
signal::sig_num::SigNum,
status::StopWaitStatus,
Uid,
},
time::clocks::ProfClock,
};
@ -32,6 +33,8 @@ bitflags! {
impl WaitOptions {
pub fn check(&self) -> Result<()> {
// FIXME: The syscall `waitid` allows using WNOWAIT with
// WSTOPPED or WCONTINUED
if self.intersects(WaitOptions::WSTOPPED | WaitOptions::WCONTINUED)
&& self.contains(WaitOptions::WNOWAIT)
{
@ -120,16 +123,17 @@ pub enum WaitStatus {
}
impl WaitStatus {
pub fn pid(&self) -> u32 {
pub fn pid(&self) -> Pid {
self.process().pid()
}
pub fn status_code(&self) -> u32 {
match self {
Self::Zombie(process) => process.status().exit_code(),
Self::Stop(_, sig_num) => ((sig_num.as_u8() as u32) << 8) | 0x7f,
Self::Continue(_) => 0xffff,
}
pub fn uid(&self) -> Uid {
self.process()
.main_thread()
.as_posix_thread()
.unwrap()
.credentials()
.ruid()
}
pub fn prof_clock(&self) -> &Arc<ProfClock> {

View File

@ -3,7 +3,7 @@
use super::{getrusage::rusage_t, SyscallReturn};
use crate::{
prelude::*,
process::{do_wait, ProcessFilter, WaitOptions},
process::{do_wait, ProcessFilter, WaitOptions, WaitStatus},
};
pub fn sys_wait4(
@ -31,7 +31,7 @@ pub fn sys_wait4(
return Ok(SyscallReturn::Return(0 as _));
};
let (return_pid, status_code) = (wait_status.pid(), wait_status.status_code());
let (return_pid, status_code) = (wait_status.pid(), calculate_status_code(&wait_status));
if status_ptr != 0 {
ctx.user_space().write_val(status_ptr as _, &status_code)?;
}
@ -48,3 +48,11 @@ pub fn sys_wait4(
Ok(SyscallReturn::Return(return_pid as _))
}
fn calculate_status_code(wait_status: &WaitStatus) -> u32 {
match wait_status {
WaitStatus::Zombie(process) => process.status().exit_code(),
WaitStatus::Stop(_, sig_num) => ((sig_num.as_u8() as u32) << 8) | 0x7f,
WaitStatus::Continue(_) => 0xffff,
}
}

View File

@ -3,28 +3,83 @@
use super::SyscallReturn;
use crate::{
prelude::*,
process::{do_wait, ProcessFilter, WaitOptions},
process::{
do_wait,
signal::{
c_types::siginfo_t,
constants::{CLD_CONTINUED, CLD_EXITED, CLD_KILLED, CLD_STOPPED, SIGCHLD, SIGCONT},
},
ProcessFilter, WaitOptions, WaitStatus,
},
};
pub fn sys_waitid(
which: u64,
upid: u64,
_infoq_addr: u64,
infoq_addr: u64,
options: u64,
_rusage_addr: u64,
ctx: &Context,
) -> Result<SyscallReturn> {
// FIXME: what does infoq and rusage use for?
// FIXME: what does rusage use for?
let process_filter = ProcessFilter::from_which_and_id(which, upid as _)?;
let wait_options = WaitOptions::from_bits(options as u32)
.ok_or(Error::with_message(Errno::EINVAL, "invalid options"))?;
// Check for waitid options
if !wait_options
.intersects(WaitOptions::WSTOPPED | WaitOptions::WCONTINUED | WaitOptions::WEXITED)
{
return_errno_with_message!(
Errno::EINVAL,
"at least one of WSTOPPED, WCONTINUED, or WEXITED should be specified"
);
}
let wait_status =
do_wait(process_filter, wait_options, ctx).map_err(|err| match err.error() {
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
let pid = wait_status.map_or(0, |wait_status| wait_status.pid());
Ok(SyscallReturn::Return(pid as _))
let Some(wait_status) = wait_status else {
return Ok(SyscallReturn::Return(0));
};
let siginfo = {
let (si_code, si_status) = calculate_si_code_and_si_status(&wait_status);
let pid = wait_status.pid();
let uid = wait_status.uid();
let mut siginfo = siginfo_t::new(SIGCHLD, si_code);
siginfo.set_pid_uid(pid, uid);
siginfo.set_status(si_status);
siginfo
};
ctx.user_space().write_val(infoq_addr as usize, &siginfo)?;
Ok(SyscallReturn::Return(0))
}
fn calculate_si_code_and_si_status(wait_status: &WaitStatus) -> (i32, i32) {
// TODO: Add supports for `CLD_DUMPED` and `CLD_TRAPPED`.
match wait_status {
WaitStatus::Zombie(process) => {
const NORMAL_EXIT_MASK: u32 = 0xff;
let exit_code = process.status().exit_code();
// If the process exits normally, the lowest 8 bits of `status_code`
// will be zero. In this case, we return the actual exit code by
// shifting the `status_code` right by 8 bits.
if (exit_code & NORMAL_EXIT_MASK) == 0 {
(CLD_EXITED, (exit_code >> 8) as i32)
} else {
(CLD_KILLED, exit_code as i32)
}
}
WaitStatus::Stop(_process, signum) => (CLD_STOPPED, signum.as_u8() as i32),
WaitStatus::Continue(_) => (CLD_CONTINUED, SIGCONT.as_u8() as i32),
}
}