starry_api/imp/task/
wait.rs1use alloc::{sync::Arc, vec::Vec};
2use axerrno::{LinuxError, LinuxResult};
3use axprocess::{Pid, Process};
4use axtask::{TaskExtRef, current};
5use bitflags::bitflags;
6use linux_raw_sys::general::{
7 __WALL, __WCLONE, __WNOTHREAD, WCONTINUED, WEXITED, WNOHANG, WNOWAIT, WUNTRACED,
8};
9use starry_core::task::ProcessData;
10
11use crate::ptr::{UserPtr, nullable};
12
13bitflags! {
14 #[derive(Debug)]
15 struct WaitOptions: u32 {
16 const WNOHANG = WNOHANG;
18 const WUNTRACED = WUNTRACED;
21 const WEXITED = WEXITED;
23 const WCONTINUED = WCONTINUED;
26 const WNOWAIT = WNOWAIT;
28
29 const WNOTHREAD = __WNOTHREAD;
31 const WALL = __WALL;
33 const WCLONE = __WCLONE;
35 }
36}
37
38#[derive(Debug, Clone, Copy)]
39enum WaitPid {
40 Any,
42 Pid(Pid),
44 Pgid(Pid),
46}
47
48impl WaitPid {
49 fn apply(&self, child: &Arc<Process>) -> bool {
50 match self {
51 WaitPid::Any => true,
52 WaitPid::Pid(pid) => child.pid() == *pid,
53 WaitPid::Pgid(pgid) => child.group().pgid() == *pgid,
54 }
55 }
56}
57
58pub fn sys_waitpid(pid: i32, exit_code_ptr: UserPtr<i32>, options: u32) -> LinuxResult<isize> {
59 let options = WaitOptions::from_bits_truncate(options);
60 info!("sys_waitpid <= pid: {:?}, options: {:?}", pid, options);
61
62 let curr = current();
63 let proc_data = curr.task_ext().process_data();
64 let process = curr.task_ext().thread.process();
65
66 let pid = if pid == -1 {
67 WaitPid::Any
68 } else if pid == 0 {
69 WaitPid::Pgid(process.group().pgid())
70 } else if pid > 0 {
71 WaitPid::Pid(pid as _)
72 } else {
73 WaitPid::Pgid(-pid as _)
74 };
75
76 let children = process
77 .children()
78 .into_iter()
79 .filter(|child| pid.apply(child))
80 .filter(|child| {
81 options.contains(WaitOptions::WALL)
82 || (options.contains(WaitOptions::WCLONE)
83 == child.data::<ProcessData>().unwrap().is_clone_child())
84 })
85 .collect::<Vec<_>>();
86 if children.is_empty() {
87 return Err(LinuxError::ECHILD);
88 }
89
90 let exit_code = nullable!(exit_code_ptr.get_as_mut())?;
91 loop {
92 if let Some(child) = children.iter().find(|child| child.is_zombie()) {
93 if !options.contains(WaitOptions::WNOWAIT) {
94 child.free();
95 }
96 if let Some(exit_code) = exit_code {
97 *exit_code = child.exit_code();
98 }
99 return Ok(child.pid() as _);
100 } else if options.contains(WaitOptions::WNOHANG) {
101 return Ok(0);
102 } else {
103 proc_data.child_exit_wq.wait();
104 }
105 }
106}