diff --git a/src/process/thread_group/wait.rs b/src/process/thread_group/wait.rs index eef9aac..c989a81 100644 --- a/src/process/thread_group/wait.rs +++ b/src/process/thread_group/wait.rs @@ -1,3 +1,7 @@ +use super::{ + Pgid, Tgid, ThreadGroup, + signal::{InterruptResult, Interruptable, SigId}, +}; use crate::clock::timespec::TimeSpec; use crate::memory::uaccess::copy_to_user; use crate::sched::current::current_task_shared; @@ -10,10 +14,6 @@ use libkernel::{ memory::address::TUA, }; -use super::Tgid; -use super::signal::SigId; -use super::{Pgid, ThreadGroup}; - pub type PidT = i32; #[repr(C)] @@ -201,11 +201,17 @@ pub async fn sys_wait4( None => return Ok(0), } } else { - task.process + match task + .process .child_notifiers .inner .wait_until(|state| do_wait(state, pid, flags)) + .interruptable() .await + { + InterruptResult::Interrupted => return Err(KernelError::Interrupted), + InterruptResult::Uninterrupted(r) => r, + } }; if !stat_addr.is_null() { diff --git a/usertest/src/main.rs b/usertest/src/main.rs index c5f1064..6e10c3d 100644 --- a/usertest/src/main.rs +++ b/usertest/src/main.rs @@ -7,7 +7,9 @@ use std::{ }; use futex_bitset::test_futex_bitset; -use signals::{test_interruptible_nanosleep, test_interruptible_read_pipe}; +use signals::{ + test_interruptible_nanosleep, test_interruptible_read_pipe, test_interruptible_waitpid, +}; mod futex_bitset; mod signals; @@ -824,6 +826,7 @@ fn main() { run_test(test_thread_with_name); run_test(test_interruptible_nanosleep); run_test(test_interruptible_read_pipe); + run_test(test_interruptible_waitpid); let end = std::time::Instant::now(); println!("All tests passed in {} ms", (end - start).as_millis()); } diff --git a/usertest/src/signals.rs b/usertest/src/signals.rs index 53ed685..295396a 100644 --- a/usertest/src/signals.rs +++ b/usertest/src/signals.rs @@ -112,3 +112,49 @@ pub fn test_interruptible_read_pipe() { } println!(" OK"); } + +pub fn test_interruptible_waitpid() { + print!("Testing interruptible waitpid ..."); + + register_handler(libc::SIGALRM, false); + + unsafe { + let ppid = libc::getpid(); + let cpid = libc::fork(); + + if cpid == 0 { + // in child. + let req = libc::timespec { + tv_sec: 1, + tv_nsec: 0, + }; + + libc::nanosleep(&req, ptr::null_mut()); + libc::kill(ppid, libc::SIGALRM); + let req = libc::timespec { + tv_sec: 10, + tv_nsec: 0, + }; + libc::nanosleep(&req, ptr::null_mut()); + libc::exit(0); + }; + + // parent. + let mut status = 0; + let ret = libc::waitpid(cpid, &mut status, 0); // Blocking wait + let err = std::io::Error::last_os_error(); + + if ret == -1 && err.raw_os_error() == Some(libc::EINTR) { + // Now we must actually kill/wait the child to clean up zombies + libc::kill(cpid, libc::SIGKILL); + libc::waitpid(cpid, &mut status, 0); + } else { + panic!( + "waitpid returned {:?} (errno: {:?}) instead of -1/EINTR", + ret, + err.raw_os_error() + ); + } + } + println!(" OK"); +}