From c6623cec2d414f2c662f036e63a8340506fb3304 Mon Sep 17 00:00:00 2001 From: Michal 'vorner' Vaner Date: Sat, 15 Jul 2023 10:26:18 +0200 Subject: [PATCH] Deal with stray `Pending` due to race condition Fixes #148. --- src/iterator/backend.rs | 2 +- src/iterator/mod.rs | 23 +++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/iterator/backend.rs b/src/iterator/backend.rs index 2ed4bf9..faadbab 100644 --- a/src/iterator/backend.rs +++ b/src/iterator/backend.rs @@ -446,7 +446,7 @@ impl SignalIterator { /// [`PollResult::Pending`] and assume it will be called again at a later point in time. /// The callback may be called any number of times by this function. /// - /// If the iterator was closed by the [`close`][Handle::close] method of the associtated + /// If the iterator was closed by the [`close`][Handle::close] method of the associated /// [`Handle`] this method will return [`PollResult::Closed`]. pub fn poll_signal(&mut self, has_signals: &mut F) -> PollResult where diff --git a/src/iterator/mod.rs b/src/iterator/mod.rs index 1dafc26..5e07744 100644 --- a/src/iterator/mod.rs +++ b/src/iterator/mod.rs @@ -302,16 +302,19 @@ impl<'a, E: Exfiltrator> Iterator for Forever<'a, E> { type Item = E::Output; fn next(&mut self) -> Option { - match self.0.poll_signal(&mut SignalsInfo::::has_signals) { - PollResult::Signal(result) => Some(result), - PollResult::Closed => None, - PollResult::Pending => unreachable!( - "Because of the blocking has_signals method the \ - poll_signal method never returns Poll::Pending but blocks until a signal arrived" - ), - // Users can't manipulate the internal file descriptors and the way we use them - // shouldn't produce any errors. So it is OK to panic. - PollResult::Err(error) => panic!("Unexpected error: {}", error), + loop { + match self.0.poll_signal(&mut SignalsInfo::::has_signals) { + PollResult::Signal(result) => break Some(result), + PollResult::Closed => break None, + // In theory, the poll_signal should not return PollResult::Pending. Nevertheless, + // there's a race condition - if the other side closes the pipe/socket after + // checking for it being closed, then the `read` there returns 0 as EOF. That + // appears as pending here. Next time we should get Closed. + PollResult::Pending => continue, + // Users can't manipulate the internal file descriptors and the way we use them + // shouldn't produce any errors. So it is OK to panic. + PollResult::Err(error) => panic!("Unexpected error: {}", error), + } } } }