starry_api/imp/task/
wait.rsuse alloc::{sync::Arc, vec::Vec};
use axerrno::{LinuxError, LinuxResult};
use axprocess::{Pid, Process};
use axtask::{TaskExtRef, current};
use bitflags::bitflags;
use linux_raw_sys::general::{
__WALL, __WCLONE, __WNOTHREAD, WCONTINUED, WEXITED, WNOHANG, WNOWAIT, WUNTRACED,
};
use macro_rules_attribute::apply;
use crate::{
ptr::{PtrWrapper, UserPtr},
syscall_instrument,
};
bitflags! {
#[derive(Debug)]
struct WaitOptions: u32 {
const WNOHANG = WNOHANG;
const WUNTRACED = WUNTRACED;
const WEXITED = WEXITED;
const WCONTINUED = WCONTINUED;
const WNOWAIT = WNOWAIT;
const WNOTHREAD = __WNOTHREAD;
const WALL = __WALL;
const WCLONE = __WCLONE;
}
}
#[derive(Debug, Clone, Copy)]
enum WaitPid {
Any,
Pid(Pid),
Pgid(Pid),
}
impl WaitPid {
fn apply(&self, child: &Arc<Process>) -> bool {
match self {
WaitPid::Any => true,
WaitPid::Pid(pid) => child.pid() == *pid,
WaitPid::Pgid(pgid) => child.group().pgid() == *pgid,
}
}
}
#[apply(syscall_instrument)]
pub fn sys_waitpid(pid: i32, exit_code_ptr: UserPtr<i32>, options: u32) -> LinuxResult<isize> {
let options = WaitOptions::from_bits_truncate(options);
info!("sys_waitpid <= pid: {:?}, options: {:?}", pid, options);
let curr = current();
let process = curr.task_ext().thread.process();
let pid = if pid == -1 {
WaitPid::Any
} else if pid == 0 {
WaitPid::Pgid(process.group().pgid())
} else if pid > 0 {
WaitPid::Pid(pid as _)
} else {
WaitPid::Pgid(-pid as _)
};
let children = process
.children()
.into_iter()
.filter(|child| pid.apply(child))
.collect::<Vec<_>>();
if children.is_empty() {
return Err(LinuxError::ECHILD);
}
let exit_code = exit_code_ptr.nullable(UserPtr::get)?;
loop {
if let Some(child) = children.iter().find(|child| child.is_zombie()) {
if !options.contains(WaitOptions::WNOWAIT) {
child.free();
}
if let Some(exit_code) = exit_code {
unsafe { exit_code.write(child.exit_code()) };
}
return Ok(child.pid() as _);
} else if options.contains(WaitOptions::WNOHANG) {
return Ok(0);
} else {
crate::sys_sched_yield()?;
}
}
}