mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-09-07 00:00:08 +02:00
process: avoid redundant effort to reap orphan processes (#3743)
This commit is contained in:
@@ -3,11 +3,8 @@
|
|||||||
//! Process driver
|
//! Process driver
|
||||||
|
|
||||||
use crate::park::Park;
|
use crate::park::Park;
|
||||||
use crate::process::unix::orphan::ReapOrphanQueue;
|
|
||||||
use crate::process::unix::GlobalOrphanQueue;
|
use crate::process::unix::GlobalOrphanQueue;
|
||||||
use crate::signal::unix::driver::Driver as SignalDriver;
|
use crate::signal::unix::driver::{Driver as SignalDriver, Handle as SignalHandle};
|
||||||
use crate::signal::unix::{signal_with_handle, SignalKind};
|
|
||||||
use crate::sync::watch;
|
|
||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -16,51 +13,20 @@ use std::time::Duration;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Driver {
|
pub(crate) struct Driver {
|
||||||
park: SignalDriver,
|
park: SignalDriver,
|
||||||
inner: CoreDriver<watch::Receiver<()>, GlobalOrphanQueue>,
|
signal_handle: SignalHandle,
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct CoreDriver<S, Q> {
|
|
||||||
sigchild: S,
|
|
||||||
orphan_queue: Q,
|
|
||||||
}
|
|
||||||
|
|
||||||
trait HasChanged {
|
|
||||||
fn has_changed(&mut self) -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> HasChanged for watch::Receiver<T> {
|
|
||||||
fn has_changed(&mut self) -> bool {
|
|
||||||
self.try_has_changed().and_then(Result::ok).is_some()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== impl CoreDriver =====
|
|
||||||
|
|
||||||
impl<S, Q> CoreDriver<S, Q>
|
|
||||||
where
|
|
||||||
S: HasChanged,
|
|
||||||
Q: ReapOrphanQueue,
|
|
||||||
{
|
|
||||||
fn process(&mut self) {
|
|
||||||
if self.sigchild.has_changed() {
|
|
||||||
self.orphan_queue.reap_orphans();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== impl Driver =====
|
// ===== impl Driver =====
|
||||||
|
|
||||||
impl Driver {
|
impl Driver {
|
||||||
/// Creates a new signal `Driver` instance that delegates wakeups to `park`.
|
/// Creates a new signal `Driver` instance that delegates wakeups to `park`.
|
||||||
pub(crate) fn new(park: SignalDriver) -> io::Result<Self> {
|
pub(crate) fn new(park: SignalDriver) -> Self {
|
||||||
let sigchild = signal_with_handle(SignalKind::child(), park.handle())?;
|
let signal_handle = park.handle();
|
||||||
let inner = CoreDriver {
|
|
||||||
sigchild,
|
|
||||||
orphan_queue: GlobalOrphanQueue,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Self { park, inner })
|
Self {
|
||||||
|
park,
|
||||||
|
signal_handle,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,13 +42,13 @@ impl Park for Driver {
|
|||||||
|
|
||||||
fn park(&mut self) -> Result<(), Self::Error> {
|
fn park(&mut self) -> Result<(), Self::Error> {
|
||||||
self.park.park()?;
|
self.park.park()?;
|
||||||
self.inner.process();
|
GlobalOrphanQueue::reap_orphans(&self.signal_handle);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error> {
|
fn park_timeout(&mut self, duration: Duration) -> Result<(), Self::Error> {
|
||||||
self.park.park_timeout(duration)?;
|
self.park.park_timeout(duration)?;
|
||||||
self.inner.process();
|
GlobalOrphanQueue::reap_orphans(&self.signal_handle);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,43 +56,3 @@ impl Park for Driver {
|
|||||||
self.park.shutdown()
|
self.park.shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
use crate::process::unix::orphan::test::MockQueue;
|
|
||||||
|
|
||||||
struct MockStream {
|
|
||||||
total_try_recv: usize,
|
|
||||||
values: Vec<Option<()>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MockStream {
|
|
||||||
fn new(values: Vec<Option<()>>) -> Self {
|
|
||||||
Self {
|
|
||||||
total_try_recv: 0,
|
|
||||||
values,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasChanged for MockStream {
|
|
||||||
fn has_changed(&mut self) -> bool {
|
|
||||||
self.total_try_recv += 1;
|
|
||||||
self.values.remove(0).is_some()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn no_reap_if_no_signal() {
|
|
||||||
let mut driver = CoreDriver {
|
|
||||||
sigchild: MockStream::new(vec![None]),
|
|
||||||
orphan_queue: MockQueue::<()>::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
driver.process();
|
|
||||||
|
|
||||||
assert_eq!(1, driver.sigchild.total_try_recv);
|
|
||||||
assert_eq!(0, driver.orphan_queue.total_reaps.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
pub(crate) mod driver;
|
pub(crate) mod driver;
|
||||||
|
|
||||||
pub(crate) mod orphan;
|
pub(crate) mod orphan;
|
||||||
use orphan::{OrphanQueue, OrphanQueueImpl, ReapOrphanQueue, Wait};
|
use orphan::{OrphanQueue, OrphanQueueImpl, Wait};
|
||||||
|
|
||||||
mod reap;
|
mod reap;
|
||||||
use reap::Reaper;
|
use reap::Reaper;
|
||||||
@@ -32,6 +32,7 @@ use reap::Reaper;
|
|||||||
use crate::io::PollEvented;
|
use crate::io::PollEvented;
|
||||||
use crate::process::kill::Kill;
|
use crate::process::kill::Kill;
|
||||||
use crate::process::SpawnedChild;
|
use crate::process::SpawnedChild;
|
||||||
|
use crate::signal::unix::driver::Handle as SignalHandle;
|
||||||
use crate::signal::unix::{signal, Signal, SignalKind};
|
use crate::signal::unix::{signal, Signal, SignalKind};
|
||||||
|
|
||||||
use mio::event::Source;
|
use mio::event::Source;
|
||||||
@@ -73,9 +74,9 @@ impl fmt::Debug for GlobalOrphanQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReapOrphanQueue for GlobalOrphanQueue {
|
impl GlobalOrphanQueue {
|
||||||
fn reap_orphans(&self) {
|
fn reap_orphans(handle: &SignalHandle) {
|
||||||
ORPHAN_QUEUE.reap_orphans()
|
ORPHAN_QUEUE.reap_orphans(handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
use crate::loom::sync::{Mutex, MutexGuard};
|
||||||
|
use crate::signal::unix::driver::Handle as SignalHandle;
|
||||||
|
use crate::signal::unix::{signal_with_handle, SignalKind};
|
||||||
|
use crate::sync::watch;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::process::ExitStatus;
|
use std::process::ExitStatus;
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
/// An interface for waiting on a process to exit.
|
/// An interface for waiting on a process to exit.
|
||||||
pub(crate) trait Wait {
|
pub(crate) trait Wait {
|
||||||
@@ -20,21 +23,8 @@ impl<T: Wait> Wait for &mut T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An interface for reaping a set of orphaned processes.
|
|
||||||
pub(crate) trait ReapOrphanQueue {
|
|
||||||
/// Attempts to reap every process in the queue, ignoring any errors and
|
|
||||||
/// enqueueing any orphans which have not yet exited.
|
|
||||||
fn reap_orphans(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ReapOrphanQueue> ReapOrphanQueue for &T {
|
|
||||||
fn reap_orphans(&self) {
|
|
||||||
(**self).reap_orphans()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An interface for queueing up an orphaned process so that it can be reaped.
|
/// An interface for queueing up an orphaned process so that it can be reaped.
|
||||||
pub(crate) trait OrphanQueue<T>: ReapOrphanQueue {
|
pub(crate) trait OrphanQueue<T> {
|
||||||
/// Adds an orphan to the queue.
|
/// Adds an orphan to the queue.
|
||||||
fn push_orphan(&self, orphan: T);
|
fn push_orphan(&self, orphan: T);
|
||||||
}
|
}
|
||||||
@@ -48,50 +38,91 @@ impl<T, O: OrphanQueue<T>> OrphanQueue<T> for &O {
|
|||||||
/// An implementation of `OrphanQueue`.
|
/// An implementation of `OrphanQueue`.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct OrphanQueueImpl<T> {
|
pub(crate) struct OrphanQueueImpl<T> {
|
||||||
|
sigchild: Mutex<Option<watch::Receiver<()>>>,
|
||||||
queue: Mutex<Vec<T>>,
|
queue: Mutex<Vec<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> OrphanQueueImpl<T> {
|
impl<T> OrphanQueueImpl<T> {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
sigchild: Mutex::new(None),
|
||||||
queue: Mutex::new(Vec::new()),
|
queue: Mutex::new(Vec::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.queue.lock().unwrap().len()
|
self.queue.lock().len()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Wait> OrphanQueue<T> for OrphanQueueImpl<T> {
|
pub(crate) fn push_orphan(&self, orphan: T)
|
||||||
fn push_orphan(&self, orphan: T) {
|
where
|
||||||
self.queue.lock().unwrap().push(orphan)
|
T: Wait,
|
||||||
|
{
|
||||||
|
self.queue.lock().push(orphan)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Wait> ReapOrphanQueue for OrphanQueueImpl<T> {
|
/// Attempts to reap every process in the queue, ignoring any errors and
|
||||||
fn reap_orphans(&self) {
|
/// enqueueing any orphans which have not yet exited.
|
||||||
let mut queue = self.queue.lock().unwrap();
|
pub(crate) fn reap_orphans(&self, handle: &SignalHandle)
|
||||||
let queue = &mut *queue;
|
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
|
||||||
|
if let 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();
|
||||||
|
|
||||||
for i in (0..queue.len()).rev() {
|
// Be lazy and only initialize the SIGCHLD listener if there
|
||||||
match queue[i].try_wait() {
|
// are any orphaned processes in the queue.
|
||||||
Ok(None) => {}
|
if !queue.is_empty() {
|
||||||
Ok(Some(_)) | Err(_) => {
|
// An errors shouldn't really happen here, but if it does it
|
||||||
// The stdlib handles interruption errors (EINTR) when polling a child process.
|
// means that the signal driver isn't running, in
|
||||||
// All other errors represent invalid inputs or pids that have already been
|
// which case there isn't anything we can
|
||||||
// reaped, so we can drop the orphan in case an error is raised.
|
// register/initialize here, so we can try again later
|
||||||
queue.swap_remove(i);
|
if let 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)))]
|
#[cfg(all(test, not(loom)))]
|
||||||
pub(crate) mod test {
|
pub(crate) mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::io::driver::Driver as IoDriver;
|
||||||
|
use crate::signal::unix::driver::{Driver as SignalDriver, Handle as SignalHandle};
|
||||||
|
use crate::sync::watch;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::os::unix::process::ExitStatusExt;
|
use std::os::unix::process::ExitStatusExt;
|
||||||
@@ -100,14 +131,12 @@ pub(crate) mod test {
|
|||||||
|
|
||||||
pub(crate) struct MockQueue<W> {
|
pub(crate) struct MockQueue<W> {
|
||||||
pub(crate) all_enqueued: RefCell<Vec<W>>,
|
pub(crate) all_enqueued: RefCell<Vec<W>>,
|
||||||
pub(crate) total_reaps: Cell<usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W> MockQueue<W> {
|
impl<W> MockQueue<W> {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
all_enqueued: RefCell::new(Vec::new()),
|
all_enqueued: RefCell::new(Vec::new()),
|
||||||
total_reaps: Cell::new(0),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,12 +147,6 @@ pub(crate) mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W> ReapOrphanQueue for MockQueue<W> {
|
|
||||||
fn reap_orphans(&self) {
|
|
||||||
self.total_reaps.set(self.total_reaps.get() + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MockWait {
|
struct MockWait {
|
||||||
total_waits: Rc<Cell<usize>>,
|
total_waits: Rc<Cell<usize>>,
|
||||||
num_wait_until_status: usize,
|
num_wait_until_status: usize,
|
||||||
@@ -191,27 +214,107 @@ pub(crate) mod test {
|
|||||||
|
|
||||||
assert_eq!(orphanage.len(), 4);
|
assert_eq!(orphanage.len(), 4);
|
||||||
|
|
||||||
orphanage.reap_orphans();
|
drain_orphan_queue(orphanage.queue.lock());
|
||||||
assert_eq!(orphanage.len(), 2);
|
assert_eq!(orphanage.len(), 2);
|
||||||
assert_eq!(first_waits.get(), 1);
|
assert_eq!(first_waits.get(), 1);
|
||||||
assert_eq!(second_waits.get(), 1);
|
assert_eq!(second_waits.get(), 1);
|
||||||
assert_eq!(third_waits.get(), 1);
|
assert_eq!(third_waits.get(), 1);
|
||||||
assert_eq!(fourth_waits.get(), 1);
|
assert_eq!(fourth_waits.get(), 1);
|
||||||
|
|
||||||
orphanage.reap_orphans();
|
drain_orphan_queue(orphanage.queue.lock());
|
||||||
assert_eq!(orphanage.len(), 1);
|
assert_eq!(orphanage.len(), 1);
|
||||||
assert_eq!(first_waits.get(), 1);
|
assert_eq!(first_waits.get(), 1);
|
||||||
assert_eq!(second_waits.get(), 2);
|
assert_eq!(second_waits.get(), 2);
|
||||||
assert_eq!(third_waits.get(), 2);
|
assert_eq!(third_waits.get(), 2);
|
||||||
assert_eq!(fourth_waits.get(), 1);
|
assert_eq!(fourth_waits.get(), 1);
|
||||||
|
|
||||||
orphanage.reap_orphans();
|
drain_orphan_queue(orphanage.queue.lock());
|
||||||
assert_eq!(orphanage.len(), 0);
|
assert_eq!(orphanage.len(), 0);
|
||||||
assert_eq!(first_waits.get(), 1);
|
assert_eq!(first_waits.get(), 1);
|
||||||
assert_eq!(second_waits.get(), 2);
|
assert_eq!(second_waits.get(), 2);
|
||||||
assert_eq!(third_waits.get(), 3);
|
assert_eq!(third_waits.get(), 3);
|
||||||
assert_eq!(fourth_waits.get(), 1);
|
assert_eq!(fourth_waits.get(), 1);
|
||||||
|
|
||||||
orphanage.reap_orphans(); // Safe to reap when empty
|
// Safe to reap when empty
|
||||||
|
drain_orphan_queue(orphanage.queue.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_reap_if_no_signal_received() {
|
||||||
|
let (tx, rx) = watch::channel(());
|
||||||
|
|
||||||
|
let handle = SignalHandle::default();
|
||||||
|
|
||||||
|
let orphanage = OrphanQueueImpl::new();
|
||||||
|
*orphanage.sigchild.lock() = Some(rx);
|
||||||
|
|
||||||
|
let orphan = MockWait::new(2);
|
||||||
|
let waits = orphan.total_waits.clone();
|
||||||
|
orphanage.push_orphan(orphan);
|
||||||
|
|
||||||
|
orphanage.reap_orphans(&handle);
|
||||||
|
assert_eq!(waits.get(), 0);
|
||||||
|
|
||||||
|
orphanage.reap_orphans(&handle);
|
||||||
|
assert_eq!(waits.get(), 0);
|
||||||
|
|
||||||
|
tx.send(()).unwrap();
|
||||||
|
orphanage.reap_orphans(&handle);
|
||||||
|
assert_eq!(waits.get(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_reap_if_signal_lock_held() {
|
||||||
|
let handle = SignalHandle::default();
|
||||||
|
|
||||||
|
let orphanage = OrphanQueueImpl::new();
|
||||||
|
let signal_guard = orphanage.sigchild.lock();
|
||||||
|
|
||||||
|
let orphan = MockWait::new(2);
|
||||||
|
let waits = orphan.total_waits.clone();
|
||||||
|
orphanage.push_orphan(orphan);
|
||||||
|
|
||||||
|
orphanage.reap_orphans(&handle);
|
||||||
|
assert_eq!(waits.get(), 0);
|
||||||
|
|
||||||
|
drop(signal_guard);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn does_not_register_signal_if_queue_empty() {
|
||||||
|
let signal_driver = IoDriver::new().and_then(SignalDriver::new).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);
|
||||||
|
|
||||||
|
orphanage.reap_orphans(&handle);
|
||||||
|
assert!(orphanage.sigchild.lock().is_some());
|
||||||
|
assert_eq!(waits.get(), 1); // Eager reap when registering listener
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -224,7 +224,6 @@ mod test {
|
|||||||
assert!(grim.poll_unpin(&mut context).is_pending());
|
assert!(grim.poll_unpin(&mut context).is_pending());
|
||||||
assert_eq!(1, grim.signal.total_polls);
|
assert_eq!(1, grim.signal.total_polls);
|
||||||
assert_eq!(1, grim.total_waits);
|
assert_eq!(1, grim.total_waits);
|
||||||
assert_eq!(0, grim.orphan_queue.total_reaps.get());
|
|
||||||
assert!(grim.orphan_queue.all_enqueued.borrow().is_empty());
|
assert!(grim.orphan_queue.all_enqueued.borrow().is_empty());
|
||||||
|
|
||||||
// Not yet exited, couldn't register interest the first time
|
// Not yet exited, couldn't register interest the first time
|
||||||
@@ -232,7 +231,6 @@ mod test {
|
|||||||
assert!(grim.poll_unpin(&mut context).is_pending());
|
assert!(grim.poll_unpin(&mut context).is_pending());
|
||||||
assert_eq!(3, grim.signal.total_polls);
|
assert_eq!(3, grim.signal.total_polls);
|
||||||
assert_eq!(3, grim.total_waits);
|
assert_eq!(3, grim.total_waits);
|
||||||
assert_eq!(0, grim.orphan_queue.total_reaps.get());
|
|
||||||
assert!(grim.orphan_queue.all_enqueued.borrow().is_empty());
|
assert!(grim.orphan_queue.all_enqueued.borrow().is_empty());
|
||||||
|
|
||||||
// Exited
|
// Exited
|
||||||
@@ -245,7 +243,6 @@ mod test {
|
|||||||
}
|
}
|
||||||
assert_eq!(4, grim.signal.total_polls);
|
assert_eq!(4, grim.signal.total_polls);
|
||||||
assert_eq!(4, grim.total_waits);
|
assert_eq!(4, grim.total_waits);
|
||||||
assert_eq!(0, grim.orphan_queue.total_reaps.get());
|
|
||||||
assert!(grim.orphan_queue.all_enqueued.borrow().is_empty());
|
assert!(grim.orphan_queue.all_enqueued.borrow().is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,7 +257,6 @@ mod test {
|
|||||||
|
|
||||||
grim.kill().unwrap();
|
grim.kill().unwrap();
|
||||||
assert_eq!(1, grim.total_kills);
|
assert_eq!(1, grim.total_kills);
|
||||||
assert_eq!(0, grim.orphan_queue.total_reaps.get());
|
|
||||||
assert!(grim.orphan_queue.all_enqueued.borrow().is_empty());
|
assert!(grim.orphan_queue.all_enqueued.borrow().is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +272,6 @@ mod test {
|
|||||||
|
|
||||||
drop(grim);
|
drop(grim);
|
||||||
|
|
||||||
assert_eq!(0, queue.total_reaps.get());
|
|
||||||
assert!(queue.all_enqueued.borrow().is_empty());
|
assert!(queue.all_enqueued.borrow().is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,7 +289,6 @@ mod test {
|
|||||||
let grim = Reaper::new(&mut mock, &queue, MockStream::new(vec![]));
|
let grim = Reaper::new(&mut mock, &queue, MockStream::new(vec![]));
|
||||||
drop(grim);
|
drop(grim);
|
||||||
|
|
||||||
assert_eq!(0, queue.total_reaps.get());
|
|
||||||
assert_eq!(1, queue.all_enqueued.borrow().len());
|
assert_eq!(1, queue.all_enqueued.borrow().len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ cfg_io_driver! {
|
|||||||
let io_handle = io_driver.handle();
|
let io_handle = io_driver.handle();
|
||||||
|
|
||||||
let (signal_driver, signal_handle) = create_signal_driver(io_driver)?;
|
let (signal_driver, signal_handle) = create_signal_driver(io_driver)?;
|
||||||
let process_driver = create_process_driver(signal_driver)?;
|
let process_driver = create_process_driver(signal_driver);
|
||||||
|
|
||||||
(Either::A(process_driver), Some(io_handle), signal_handle)
|
(Either::A(process_driver), Some(io_handle), signal_handle)
|
||||||
} else {
|
} else {
|
||||||
@@ -80,7 +80,7 @@ cfg_not_signal_internal! {
|
|||||||
cfg_process_driver! {
|
cfg_process_driver! {
|
||||||
type ProcessDriver = crate::process::unix::driver::Driver;
|
type ProcessDriver = crate::process::unix::driver::Driver;
|
||||||
|
|
||||||
fn create_process_driver(signal_driver: SignalDriver) -> io::Result<ProcessDriver> {
|
fn create_process_driver(signal_driver: SignalDriver) -> ProcessDriver {
|
||||||
crate::process::unix::driver::Driver::new(signal_driver)
|
crate::process::unix::driver::Driver::new(signal_driver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,8 +89,8 @@ cfg_not_process_driver! {
|
|||||||
cfg_io_driver! {
|
cfg_io_driver! {
|
||||||
type ProcessDriver = SignalDriver;
|
type ProcessDriver = SignalDriver;
|
||||||
|
|
||||||
fn create_process_driver(signal_driver: SignalDriver) -> io::Result<ProcessDriver> {
|
fn create_process_driver(signal_driver: SignalDriver) -> ProcessDriver {
|
||||||
Ok(signal_driver)
|
signal_driver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ fn action(globals: Pin<&'static Globals>, signal: libc::c_int) {
|
|||||||
///
|
///
|
||||||
/// This will register the signal handler if it hasn't already been registered,
|
/// This will register the signal handler if it hasn't already been registered,
|
||||||
/// returning any error along the way if that fails.
|
/// returning any error along the way if that fails.
|
||||||
fn signal_enable(signal: SignalKind, handle: Handle) -> io::Result<()> {
|
fn signal_enable(signal: SignalKind, handle: &Handle) -> io::Result<()> {
|
||||||
let signal = signal.0;
|
let signal = signal.0;
|
||||||
if signal < 0 || signal_hook_registry::FORBIDDEN.contains(&signal) {
|
if signal < 0 || signal_hook_registry::FORBIDDEN.contains(&signal) {
|
||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
@@ -357,7 +357,7 @@ pub struct Signal {
|
|||||||
/// * If the signal is one of
|
/// * If the signal is one of
|
||||||
/// [`signal_hook::FORBIDDEN`](fn@signal_hook_registry::register#panics)
|
/// [`signal_hook::FORBIDDEN`](fn@signal_hook_registry::register#panics)
|
||||||
pub fn signal(kind: SignalKind) -> io::Result<Signal> {
|
pub fn signal(kind: SignalKind) -> io::Result<Signal> {
|
||||||
let rx = signal_with_handle(kind, Handle::current())?;
|
let rx = signal_with_handle(kind, &Handle::current())?;
|
||||||
|
|
||||||
Ok(Signal {
|
Ok(Signal {
|
||||||
inner: RxFuture::new(rx),
|
inner: RxFuture::new(rx),
|
||||||
@@ -366,7 +366,7 @@ pub fn signal(kind: SignalKind) -> io::Result<Signal> {
|
|||||||
|
|
||||||
pub(crate) fn signal_with_handle(
|
pub(crate) fn signal_with_handle(
|
||||||
kind: SignalKind,
|
kind: SignalKind,
|
||||||
handle: Handle,
|
handle: &Handle,
|
||||||
) -> io::Result<watch::Receiver<()>> {
|
) -> io::Result<watch::Receiver<()>> {
|
||||||
// Turn the signal delivery on once we are ready for it
|
// Turn the signal delivery on once we are ready for it
|
||||||
signal_enable(kind, handle)?;
|
signal_enable(kind, handle)?;
|
||||||
@@ -462,14 +462,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn signal_enable_error_on_invalid_input() {
|
fn signal_enable_error_on_invalid_input() {
|
||||||
signal_enable(SignalKind::from_raw(-1), Handle::default()).unwrap_err();
|
signal_enable(SignalKind::from_raw(-1), &Handle::default()).unwrap_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn signal_enable_error_on_forbidden_input() {
|
fn signal_enable_error_on_forbidden_input() {
|
||||||
signal_enable(
|
signal_enable(
|
||||||
SignalKind::from_raw(signal_hook_registry::FORBIDDEN[0]),
|
SignalKind::from_raw(signal_hook_registry::FORBIDDEN[0]),
|
||||||
Handle::default(),
|
&Handle::default(),
|
||||||
)
|
)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user