Skip to content

Commit

Permalink
std::io: retry write operation on ErrorKind::WouldBlock
Browse files Browse the repository at this point in the history
If writing to tty when O_NONBLOCK bit is set and the lock to
tty is held (e.g. multiple threads writing to console), the Linux kernel
returns -EAGAIN.
(https://elixir.bootlin.com/linux/v5.19/source/drivers/tty/tty_io.c#L952)

Not accounting for -EAGAIN (i.e. ErrorKind::WouldBlock), results in
a panic. Its better to retry the write as the other thread could have
release the lock by then.

Signed-off-by: Usama Arif <[email protected]>
Reviewed-by: Fam Zheng <[email protected]>
  • Loading branch information
uarif1 committed Aug 15, 2022
1 parent 9b4ea39 commit eb44672
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 15 deletions.
4 changes: 3 additions & 1 deletion library/std/src/io/buffered/bufwriter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,9 @@ impl<W: Write> BufWriter<W> {
));
}
Ok(n) => guard.consume(n),
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(ref e)
if e.kind() == io::ErrorKind::Interrupted
|| e.kind() == ErrorKind::WouldBlock => {}
Err(e) => return Err(e),
}
}
Expand Down
34 changes: 20 additions & 14 deletions library/std/src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1396,8 +1396,9 @@ pub trait Write {
/// It is **not** considered an error if the entire buffer could not be
/// written to this writer.
///
/// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the
/// write operation should be retried if there is nothing else to do.
/// An error of kind [`ErrorKind::Interrupted`] or [`ErrorKind::WouldBlock`]
/// is non-fatal and the write operation should be retried if there is
/// nothing else to do.
///
/// # Examples
///
Expand Down Expand Up @@ -1498,18 +1499,19 @@ pub trait Write {
/// Attempts to write an entire buffer into this writer.
///
/// This method will continuously call [`write`] until there is no more data
/// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
/// returned. This method will not return until the entire buffer has been
/// successfully written or such an error occurs. The first error that is
/// not of [`ErrorKind::Interrupted`] kind generated from this method will be
/// returned.
/// to be written or an error is returned that is not of kind [`ErrorKind::Interrupted`]
/// or [`ErrorKind::WouldBlock`]. This method will not return until the
/// entire buffer has been successfully written or such an error occurs. The
/// first error that is not of kind [`ErrorKind::Interrupted`] or
/// [`ErrorKind::WouldBlock`] generated from this method will be returned.
///
/// If the buffer contains no data, this will never call [`write`].
///
/// # Errors
///
/// This function will return the first error of
/// non-[`ErrorKind::Interrupted`] kind that [`write`] returns.
/// that [`write`] returns which is not of kind [`ErrorKind::Interrupted`]
/// or [`ErrorKind::WouldBlock`].
///
/// [`write`]: Write::write
///
Expand Down Expand Up @@ -1537,20 +1539,23 @@ pub trait Write {
));
}
Ok(n) => buf = &buf[n..],
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(ref e)
if e.kind() == ErrorKind::Interrupted || e.kind() == ErrorKind::WouldBlock => {}
Err(e) => return Err(e),
}
}

Ok(())
}

/// Attempts to write multiple buffers into this writer.
///
/// This method will continuously call [`write_vectored`] until there is no
/// more data to be written or an error of non-[`ErrorKind::Interrupted`]
/// kind is returned. This method will not return until all buffers have
/// been successfully written or such an error occurs. The first error that
/// is not of [`ErrorKind::Interrupted`] kind generated from this method
/// more data to be written or an error is returned that is not of kind
/// [`ErrorKind::Interrupted`] or [`ErrorKind::WouldBlock`]. This method will
/// not return until all buffers have been successfully written or such an
/// error occurs. The first error that is not of kind [`ErrorKind::Interrupted`]
/// or [`ErrorKind::WouldBlock`] generated from this method
/// will be returned.
///
/// If the buffer contains no data, this will never call [`write_vectored`].
Expand Down Expand Up @@ -1605,7 +1610,8 @@ pub trait Write {
));
}
Ok(n) => IoSlice::advance_slices(&mut bufs, n),
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(ref e)
if e.kind() == ErrorKind::Interrupted || e.kind() == ErrorKind::WouldBlock => {}
Err(e) => return Err(e),
}
}
Expand Down

0 comments on commit eb44672

Please sign in to comment.