syscalls: wait4: make interruptable()

Make the `sys_wait4` system call interruptable via signal delivery.

Also include some a test in `usertest` to ensure proper functionality.
This commit is contained in:
Matthew Leach
2026-01-16 20:14:28 +00:00
parent ecdfd360d1
commit bc5d1cd91e
3 changed files with 61 additions and 6 deletions

View File

@@ -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() {

View File

@@ -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());
}

View File

@@ -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");
}