[go: up one dir, main page]

Waiter

Struct Waiter 

Source
pub struct Waiter { /* private fields */ }
Expand description

An object that buffers SIGCHLD signals so that you can wait on them reliably.

Waiter can’t tell you which process woke you up, so you usually need to wait in a loop and poll your Child each time through. One way to make sure you don’t miss a signal (and potentially wait forever) is to create a Waiter before you spawn your child process, like this:

let mut waiter = sigchld::Waiter::new()?;
// Any SIGCHLD after this point will be buffered by the Waiter.
let mut child = std::process::Command::new("sleep").arg("1").spawn()?;
loop {
    waiter.wait()?;
    // *Some* child has exited. Check whether it was our child.
    if child.try_wait()?.is_some() {
        break;
    }
}
// Our child has exited.

If you create a Waiter after your child is already running, then you need to poll the child at least once before you wait:

let mut child = std::process::Command::new("sleep").arg("1").spawn()?;
// If SIGCHLD arrives here, before the Waiter is created, we could miss it.
let mut waiter = sigchld::Waiter::new()?;
while child.try_wait()?.is_none() {
    // Now we know the child didn't exit before we created the Waiter.
    waiter.wait()?;
}
// Our child has exited.

The following order of operations is broken. You could miss SIGCHLD and wait forever:

let mut child = std::process::Command::new("sleep").arg("1").spawn()?;
// If SIGCHLD arrives now, before the Waiter is created, we could miss it.
let mut waiter = sigchld::Waiter::new()?;
// OOPS: If we missed SIGCHLD, we'll wait forever.
waiter.wait()?;

Most applications will prefer higher-level APIs like shared_child or duct, where you don’t have to worry about this sort of mistake. This crate is intended more as a building block for those APIs.

Implementations§

Source§

impl Waiter

Source

pub fn new() -> Result<Self>

Create a Waiter.

Any SIGCHLD signals that arrive after a Waiter is created, but before a call to wait, wait_timeout, or wait_deadline, will be buffered. In that case the next call to one of those methods will return immediately. Note that each wait clears the entire buffer, so a single wakeup could indicate that multiple signals arrived. In other words, signals can be “coalesced”.

Source

pub fn wait(&mut self) -> Result<()>

Block the current thread until any SIGCHLD signal arrives.

If any SIGCHLD signals have arrived since the Waiter was created, this function will return immediately. This avoids a race condition where the child exits right after you call Child::try_wait but right before you call this function.

This function does not reap any exited children. Child process cleanup is only done by Child::wait or Child::try_wait.

This function is not currently susceptible to “spurious wakeups” (i.e. returning early for no reason), but this property isn’t guaranteed, and future versions might be. Getting woken up early by an unrelated child process exiting (e.g. one spawned by some unknown library code running on another thread) is similar to a spurious wakeup, and you might need to be defensive and wait in a loop either way.

Source

pub fn wait_timeout(&mut self, timeout: Duration) -> Result<bool>

Block the current thread until either any SIGCHLD signal arrives or a timeout passes. Return true if a signal arrived before the timeout.

If any SIGCHLD signals have arrived since the Waiter was created, this function will return immediately. This avoids a race condition where the child exits right after you call Child::try_wait but right before you call this function.

This function does not reap any exited children. Child process cleanup is only done by Child::wait or Child::try_wait.

This function is not currently susceptible to “spurious wakeups” (i.e. returning early for no reason), but this property isn’t guaranteed, and future versions might be. Getting woken up early by an unrelated child process exiting (e.g. one spawned by some unknown library code running on another thread) is similar to a spurious wakeup, and you might need to be defensive and wait in a loop either way.

Source

pub fn wait_deadline(&mut self, deadline: Instant) -> Result<bool>

Block the current thread until either any SIGCHLD signal arrives or a deadline passes. Return true if a signal arrived before the deadline.

If any SIGCHLD signals have arrived since the Waiter was created, this function will return immediately. This avoids a race condition where the child exits right after you call Child::try_wait but right before you call this function.

This function does not reap any exited children. Child process cleanup is only done by Child::wait or Child::try_wait.

This function is not currently susceptible to “spurious wakeups” (i.e. returning early for no reason), but this property isn’t guaranteed, and future versions might be. Getting woken up early by an unrelated child process exiting (e.g. one spawned by some unknown library code running on another thread) is similar to a spurious wakeup, and you might need to be defensive and wait in a loop either way.

Trait Implementations§

Source§

impl Debug for Waiter

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Drop for Waiter

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

§

impl Freeze for Waiter

§

impl RefUnwindSafe for Waiter

§

impl Send for Waiter

§

impl Sync for Waiter

§

impl Unpin for Waiter

§

impl UnwindSafe for Waiter

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.