usecrate::loom::sync::{Mutex, MutexGuard}; usecrate::runtime::signal::Handle as SignalHandle; usecrate::signal::unix::{signal_with_handle, SignalKind}; usecrate::sync::watch; use std::io; use std::process::ExitStatus;
/// An interface for waiting on a process to exit. pub(crate) trait Wait { /// Get the identifier for this process or diagnostics. #[allow(dead_code)] fn id(&self) -> u32; /// Try waiting for a process to exit in a non-blocking manner. fn try_wait(&mutself) -> io::Result<Option<ExitStatus>>;
}
impl<T: Wait> Wait for &mut T { fn id(&self) -> u32 {
(**self).id()
}
/// An interface for queueing up an orphaned process so that it can be reaped. pub(crate) trait OrphanQueue<T> { /// Adds an orphan to the queue. fn push_orphan(&self, orphan: T);
}
/// Attempts to reap every process in the queue, ignoring any errors and /// enqueueing any orphans which have not yet exited. pub(crate) fn reap_orphans(&self, handle: &SignalHandle) where
T: Wait,
{ // If someone else is holding the lock, they will be responsible for draining // the queue as necessary, so we can safely bail if that happens iflet Some(mut sigchild_guard) = self.sigchild.try_lock() { match &mut *sigchild_guard {
Some(sigchild) => { if sigchild.try_has_changed().and_then(Result::ok).is_some() {
drain_orphan_queue(self.queue.lock());
}
}
None => { let queue = self.queue.lock();
// Be lazy and only initialize the SIGCHLD listener if there // are any orphaned processes in the queue. if !queue.is_empty() { // An errors shouldn't really happen here, but if it does it // means that the signal driver isn't running, in // which case there isn't anything we can // register/initialize here, so we can try again later iflet Ok(sigchild) = signal_with_handle(SignalKind::child(), handle) {
*sigchild_guard = Some(sigchild);
drain_orphan_queue(queue);
}
}
}
}
}
}
}
fn drain_orphan_queue<T>(mut queue: MutexGuard<'_, Vec<T>>) where
T: Wait,
{ for i in (0..queue.len()).rev() { match queue[i].try_wait() {
Ok(None) => {}
Ok(Some(_)) | Err(_) => { // The stdlib handles interruption errors (EINTR) when polling a child process. // All other errors represent invalid inputs or pids that have already been // reaped, so we can drop the orphan in case an error is raised.
queue.swap_remove(i);
}
}
}
drop(queue);
}
#[cfg(all(test, not(loom)))] pub(crate) mod test { usesuper::*; usecrate::runtime::io::Driver as IoDriver; usecrate::runtime::signal::{Driver as SignalDriver, Handle as SignalHandle}; usecrate::sync::watch; use std::cell::{Cell, RefCell}; use std::io; use std::os::unix::process::ExitStatusExt; use std::process::ExitStatus; use std::rc::Rc;
#[test] fn drain_attempts_a_single_reap_of_all_queued_orphans() { let first_orphan = MockWait::new(0); let second_orphan = MockWait::new(1); let third_orphan = MockWait::new(2); let fourth_orphan = MockWait::with_err();
let first_waits = first_orphan.total_waits.clone(); let second_waits = second_orphan.total_waits.clone(); let third_waits = third_orphan.total_waits.clone(); let fourth_waits = fourth_orphan.total_waits.clone();
let orphanage = OrphanQueueImpl::new();
orphanage.push_orphan(first_orphan);
orphanage.push_orphan(third_orphan);
orphanage.push_orphan(second_orphan);
orphanage.push_orphan(fourth_orphan);
#[cfg_attr(miri, ignore)] // Miri does not support epoll. #[test] fn does_not_register_signal_if_queue_empty() { let (io_driver, io_handle) = IoDriver::new(1024).unwrap(); let signal_driver = SignalDriver::new(io_driver, &io_handle).unwrap(); let handle = signal_driver.handle();
let orphanage = OrphanQueueImpl::new();
assert!(orphanage.sigchild.lock().is_none()); // Sanity
// No register when queue empty
orphanage.reap_orphans(&handle);
assert!(orphanage.sigchild.lock().is_none());
let orphan = MockWait::new(2); let waits = orphan.total_waits.clone();
orphanage.push_orphan(orphan);
#[test] fn does_nothing_if_signal_could_not_be_registered() { let handle = SignalHandle::default();
let orphanage = OrphanQueueImpl::new();
assert!(orphanage.sigchild.lock().is_none());
let orphan = MockWait::new(2); let waits = orphan.total_waits.clone();
orphanage.push_orphan(orphan);
// Signal handler has "gone away", nothing to register or reap
orphanage.reap_orphans(&handle);
assert!(orphanage.sigchild.lock().is_none());
assert_eq!(waits.get(), 0);
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.