asterinas/kernel/src/syscall/waitid.rs

90 lines
2.7 KiB
Rust
Raw Normal View History

2024-01-03 03:22:36 +00:00
// SPDX-License-Identifier: MPL-2.0
2025-12-04 05:57:54 +00:00
use ostd::mm::VmIo;
use super::SyscallReturn;
use crate::{
prelude::*,
2025-07-21 10:37:48 +00:00
process::{
do_wait,
signal::{
c_types::siginfo_t,
constants::{CLD_CONTINUED, CLD_EXITED, CLD_KILLED, CLD_STOPPED, SIGCHLD, SIGCONT},
},
ProcessFilter, WaitOptions, WaitStatus,
},
};
2022-09-27 11:51:18 +00:00
pub fn sys_waitid(
which: u64,
upid: u64,
2025-07-21 10:37:48 +00:00
infoq_addr: u64,
2022-09-27 11:51:18 +00:00
options: u64,
_rusage_addr: u64,
ctx: &Context,
) -> Result<SyscallReturn> {
2025-07-21 10:37:48 +00:00
// FIXME: what does rusage use for?
2025-06-05 07:25:07 +00:00
let process_filter = ProcessFilter::from_which_and_id(which, upid as _, ctx)?;
2024-08-21 12:56:03 +00:00
let wait_options = WaitOptions::from_bits(options as u32)
.ok_or(Error::with_message(Errno::EINVAL, "invalid options"))?;
2025-07-21 10:37:48 +00:00
// 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"
);
}
2025-06-12 03:11:16 +00:00
let wait_status =
do_wait(process_filter, wait_options, ctx).map_err(|err| match err.error() {
2024-12-16 03:32:37 +00:00
Errno::EINTR => Error::new(Errno::ERESTARTSYS),
_ => err,
})?;
2025-07-21 10:37:48 +00:00
let Some(wait_status) = wait_status else {
return Ok(SyscallReturn::Return(0));
};
2025-06-05 07:25:07 +00:00
if infoq_addr != 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();
2025-07-21 10:37:48 +00:00
2025-06-05 07:25:07 +00:00
let mut siginfo = siginfo_t::new(SIGCHLD, si_code);
siginfo.set_pid_uid(pid, uid);
siginfo.set_status(si_status);
2025-07-21 10:37:48 +00:00
2025-06-05 07:25:07 +00:00
siginfo
};
2025-07-21 10:37:48 +00:00
2025-06-05 07:25:07 +00:00
ctx.user_space().write_val(infoq_addr as usize, &siginfo)?;
}
2025-07-21 10:37:48 +00:00
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),
}
2022-09-27 11:51:18 +00:00
}