Enhance waitid syscall support
This commit is contained in:
parent
4d52241c6c
commit
ef0382b164
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue