Handle native Mac extraction worker exit races

This commit is contained in:
karl committed 2026-10-23 09:49:17 +02:00
1 parent dd589e88ae
commit feec06bc41
3 files changed
+44 -27

No files matched your search

+21 -18
View File
@@ -50,29 +50,32 @@ enum Event {
#[cfg(target_os = "macos")]
fn check_resident_memory(child: &mut Child, maximum: u64) -> Result<(), ProcessError> {
let mut info = std::mem::MaybeUninit::<libc::proc_taskinfo>::uninit();
let size = std::mem::size_of::<libc::proc_taskinfo>();
// The child stays owned and unreaped until I/O completes. A failed query is
// accepted only when it has already exited; otherwise fail closed.
let read = unsafe {
libc::proc_pidinfo(
child.id() as i32,
libc::PROC_PIDTASKINFO,
0,
info.as_mut_ptr().cast(),
size as i32,
)
};
if read != size as i32 {
// Task info can disappear just before an exiting child becomes waitable.
// Retry that transition briefly; an alive uninspectable child fails closed.
for _ in 0..10 {
let mut info = std::mem::MaybeUninit::<libc::proc_taskinfo>::uninit();
let read = unsafe {
libc::proc_pidinfo(
child.id() as i32,
libc::PROC_PIDTASKINFO,
0,
info.as_mut_ptr().cast(),
size as i32,
)
};
if read == size as i32 {
if unsafe { info.assume_init() }.pti_resident_size > maximum {
return Err(failed("Extraction worker resident memory exceeds budget"));
}
return Ok(());
}
if child.try_wait().map_err(failed)?.is_some() {
return Ok(());
}
return Err(failed("Cannot inspect extraction memory usage"));
thread::sleep(Duration::from_millis(1));
}
if unsafe { info.assume_init() }.pti_resident_size > maximum {
return Err(failed("Extraction worker resident memory exceeds budget"));
}
Ok(())
Err(failed("Cannot inspect extraction memory usage"))
}
/// Includes pipe writes, response EOF and process exit in the same deadline.