diff --git a/kernel/aster-nix/src/process/process/mod.rs b/kernel/aster-nix/src/process/process/mod.rs index 4f5a2bd09..6274f2a43 100644 --- a/kernel/aster-nix/src/process/process/mod.rs +++ b/kernel/aster-nix/src/process/process/mod.rs @@ -49,7 +49,7 @@ pub type Pgid = u32; /// Session Id. pub type Sid = u32; -pub type ExitCode = i32; +pub type ExitCode = u32; pub(super) fn init() { timer_manager::init(); @@ -632,7 +632,7 @@ impl Process { *self.status.lock() = ProcessStatus::Zombie(term_status); } - pub fn exit_code(&self) -> Option { + pub fn exit_code(&self) -> Option { match &*self.status.lock() { ProcessStatus::Runnable | ProcessStatus::Uninit => None, ProcessStatus::Zombie(term_status) => Some(term_status.as_u32()), diff --git a/kernel/aster-nix/src/process/wait.rs b/kernel/aster-nix/src/process/wait.rs index 7312bd93d..d086ec847 100644 --- a/kernel/aster-nix/src/process/wait.rs +++ b/kernel/aster-nix/src/process/wait.rs @@ -27,9 +27,9 @@ impl WaitOptions { pub fn wait_child_exit( child_filter: ProcessFilter, wait_options: WaitOptions, -) -> Result<(Pid, ExitCode)> { +) -> Result>> { let current = current!(); - let (pid, exit_code) = current.children_pauser().pause_until(|| { + let zombie_child = current.children_pauser().pause_until(|| { let unwaited_children = current .children() .lock() @@ -54,29 +54,28 @@ pub fn wait_child_exit( if let Some(zombie_child) = zombie_child { let zombie_pid = zombie_child.pid(); - let exit_code = zombie_child.exit_code().unwrap(); if wait_options.contains(WaitOptions::WNOWAIT) { // does not reap child, directly return - return Some(Ok((zombie_pid, exit_code))); + return Some(Ok(Some(zombie_child.clone()))); } else { - let exit_code = reap_zombie_child(¤t, zombie_pid); - return Some(Ok((zombie_pid, exit_code))); + reap_zombie_child(¤t, zombie_pid); + return Some(Ok(Some(zombie_child.clone()))); } } if wait_options.contains(WaitOptions::WNOHANG) { - return Some(Ok((0, 0))); + return Some(Ok(None)); } // wait None })??; - Ok((pid, exit_code as _)) + Ok(zombie_child) } /// Free zombie child with pid, returns the exit code of child process. -fn reap_zombie_child(process: &Process, pid: Pid) -> u32 { +fn reap_zombie_child(process: &Process, pid: Pid) -> ExitCode { let child_process = process.children().lock().remove(&pid).unwrap(); assert!(child_process.is_zombie()); child_process.root_vmar().destroy_all().unwrap(); diff --git a/kernel/aster-nix/src/syscall/wait4.rs b/kernel/aster-nix/src/syscall/wait4.rs index 4e2b722f0..ba5fde989 100644 --- a/kernel/aster-nix/src/syscall/wait4.rs +++ b/kernel/aster-nix/src/syscall/wait4.rs @@ -1,13 +1,18 @@ // SPDX-License-Identifier: MPL-2.0 -use super::SyscallReturn; +use super::{getrusage::rusage_t, SyscallReturn}; use crate::{ prelude::*, process::{wait_child_exit, ProcessFilter, WaitOptions}, util::write_val_to_user, }; -pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u32) -> Result { +pub fn sys_wait4( + wait_pid: u64, + exit_status_ptr: u64, + wait_options: u32, + rusage_addr: Vaddr, +) -> Result { let wait_options = WaitOptions::from_bits(wait_options) .ok_or_else(|| Error::with_message(Errno::EINVAL, "unknown wait option"))?; debug!( @@ -16,9 +21,26 @@ pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u32) -> Resu ); debug!("wait4 current pid = {}", current!().pid()); let process_filter = ProcessFilter::from_id(wait_pid as _); - let (return_pid, exit_code) = wait_child_exit(process_filter, wait_options)?; - if return_pid != 0 && exit_status_ptr != 0 { + + let waited_process = wait_child_exit(process_filter, wait_options)?; + let Some(process) = waited_process else { + return Ok(SyscallReturn::Return(0 as _)); + }; + + let (return_pid, exit_code) = (process.pid(), process.exit_code().unwrap()); + if exit_status_ptr != 0 { write_val_to_user(exit_status_ptr as _, &exit_code)?; } + + if rusage_addr != 0 { + let rusage = rusage_t { + ru_utime: process.prof_clock().user_clock().read_time().into(), + ru_stime: process.prof_clock().kernel_clock().read_time().into(), + ..Default::default() + }; + + write_val_to_user(rusage_addr, &rusage)?; + } + Ok(SyscallReturn::Return(return_pid as _)) } diff --git a/kernel/aster-nix/src/syscall/waitid.rs b/kernel/aster-nix/src/syscall/waitid.rs index abd75dc23..34a1be36c 100644 --- a/kernel/aster-nix/src/syscall/waitid.rs +++ b/kernel/aster-nix/src/syscall/waitid.rs @@ -18,6 +18,7 @@ pub fn sys_waitid( // FIXME: what does infoq and rusage use for? let process_filter = ProcessFilter::from_which_and_id(which, upid); let wait_options = WaitOptions::from_bits(options as u32).expect("Unknown wait options"); - let (exit_code, pid) = wait_child_exit(process_filter, wait_options)?; + let waited_process = wait_child_exit(process_filter, wait_options)?; + let pid = waited_process.map_or(0, |process| process.pid()); Ok(SyscallReturn::Return(pid as _)) }