mirror of
https://github.com/tokio-rs/tokio.git
synced 2025-09-28 12:10:37 +00:00
process: Unix: preregister for signal notifications before polling child
This commit is contained in:
parent
827e77e71e
commit
9290602815
38
src/unix.rs
38
src/unix.rs
@ -98,10 +98,10 @@ impl Child {
|
|||||||
|
|
||||||
pub fn poll_exit(&mut self) -> Poll<ExitStatus, io::Error> {
|
pub fn poll_exit(&mut self) -> Poll<ExitStatus, io::Error> {
|
||||||
loop {
|
loop {
|
||||||
// Ensure that once we've successfully waited we won't try to
|
// Ensure we don't register for additional notifications
|
||||||
// `kill` above.
|
// if the child has already finished.
|
||||||
if let Some(e) = try!(self.try_wait(false)) {
|
if self.reaped {
|
||||||
return Ok(e.into())
|
return Ok(Async::NotReady);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the child hasn't exited yet, then it's our responsibility to
|
// If the child hasn't exited yet, then it's our responsibility to
|
||||||
@ -110,8 +110,34 @@ impl Child {
|
|||||||
//
|
//
|
||||||
// As described in `spawn` above, we just indicate that we can
|
// As described in `spawn` above, we just indicate that we can
|
||||||
// next make progress once a SIGCHLD is received.
|
// next make progress once a SIGCHLD is received.
|
||||||
if try!(self.sigchld.poll()).is_not_ready() {
|
//
|
||||||
return Ok(Async::NotReady)
|
// However, we will register for a notification on the next signal
|
||||||
|
// BEFORE we poll the child. Otherwise it is possible that the child
|
||||||
|
// can exit and the signal can arrive after we last polled the child,
|
||||||
|
// but before we've registered for a notification on the next signal
|
||||||
|
// (this can cause a deadlock if there are no more spawned children
|
||||||
|
// which can generate a different signal for us). A side effect of
|
||||||
|
// pre-registering for signal notifications is that when the child
|
||||||
|
// exits, we will have already registered for an additional
|
||||||
|
// notification we don't need to consume. If another signal arrives,
|
||||||
|
// this future's task will be notified/woken up again. Since the
|
||||||
|
// futures model allows for spurious wake ups this extra wakeup
|
||||||
|
// should not cause significant issues with parent futures.
|
||||||
|
let registered_interest = try!(self.sigchld.poll()).is_not_ready();
|
||||||
|
|
||||||
|
if let Some(e) = try!(self.try_wait(false)) {
|
||||||
|
return Ok(e.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// If our attempt to poll for the next signal was not ready, then
|
||||||
|
// we've arranged for our task to get notified and we can bail out.
|
||||||
|
if registered_interest {
|
||||||
|
return Ok(Async::NotReady);
|
||||||
|
} else {
|
||||||
|
// Otherwise, if the signal stream delivered a signal to us, we
|
||||||
|
// won't get notified at the next signal, so we'll loop and try
|
||||||
|
// again.
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user