diff --git a/libkernel/src/error.rs b/libkernel/src/error.rs index c51c82e..7f2776e 100644 --- a/libkernel/src/error.rs +++ b/libkernel/src/error.rs @@ -177,6 +177,9 @@ pub enum KernelError { #[error("No such process")] NoProcess, + #[error("No child process")] + NoChildProcess, + #[error("Operation timed out")] TimedOut, diff --git a/libkernel/src/error/syscall_error.rs b/libkernel/src/error/syscall_error.rs index 78b0152..d17f473 100644 --- a/libkernel/src/error/syscall_error.rs +++ b/libkernel/src/error/syscall_error.rs @@ -53,6 +53,7 @@ pub fn kern_err_to_syscall(err: KernelError) -> isize { KernelError::NotSupported => ENOSYS, KernelError::NoMemory => ENOMEM, KernelError::TimedOut => ETIMEDOUT, + KernelError::NoChildProcess => ECHILD, e => todo!("{e}"), } } diff --git a/src/process/thread_group/wait.rs b/src/process/thread_group/wait.rs index 59f5f62..b0e511a 100644 --- a/src/process/thread_group/wait.rs +++ b/src/process/thread_group/wait.rs @@ -170,7 +170,12 @@ pub async fn sys_wait4( let task = current_task_shared(); - let (tgid, child_state) = if flags.contains(WaitFlags::WNOHANG) { + let child_proc_count = task.process.children.lock_save_irq().iter().count(); + + let (tgid, child_state) = if child_proc_count == 0 || flags.contains(WaitFlags::WNOHANG) { + // Special case for no children. See if there are any pending child + // notification events without sleeping. If there are no children and no + // pending events, return ECHILD. let mut ret = None; task.process.child_notifiers.inner.update(|s| { ret = do_wait(s, pid, flags); @@ -178,8 +183,9 @@ pub async fn sys_wait4( }); match ret { - None => return Ok(0), Some(ret) => ret, + None if child_proc_count == 0 => return Err(KernelError::NoChildProcess), + None => return Ok(0), } } else { task.process