tests: handle spurious EWOULDBLOCK in io_async_fd #6776
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Motivation
The
io_async_fd.rs
tests contain adrain()
function, which currently performs synchronous reads from a UDS socket until it returnsio::ErrorKind::WouldBlock
(i.e., errnoEWOULDBLOCK
/EAGAIN
). The intent behind this function is to ensure that all data has been drained from the UDS socket's buffer...which is what it appears to do...on Linux. On other systems, it appears that anEWOULDBLOCK
orEAGAIN
may be returned before enough data has been read from the UDS socket to result in the other end being notified that the socket is now writable. In particular, this appears to be the case on illumos, where the tests using this function hang forever (see this comment on PR #6769).To my knowledge, this behavior is still POSIX-compliant --- the reader will still be notified that the socket is readable, and if it were actually doing non-blocking IO, it would continue reading upon receipt of that notification. So, relying on
EWOULDBLOCK
to indicate that the socket has been sufficiently drained appears to rely on Linux/FreeBSD behavior that isn't necessarily portable to other Unices.Solution
This commit changes the
drain()
function to take an argument for the number of bytes written to the socket previously, and continue looping until it has read that many bytes, regardless of whetherEWOULDBLOCK
is returned. This should ensure that the socket is drained on all POSIX-compliant systems, and indeed, theio_async_fd::reset_writable
andio_async_fd::poll_fns
tests no longer hang forever on illumos.I think making this change is an appropriate solution to the test failure here, as the
drain()
function is part of the test, rather than the code in Tokio being tested, and (as I mentioned above) the use of blocking reads on a non-blocking socket without a mechanism to continue reading when the socket becomes readable again is not really something a real life program seems likely to do. Ensuring that all the written bytes have been read by passing in a byte count seems more faithful to what the test is actually trying to do here, anyway.Thanks to @jclulow for debugging what was going on here!
This change was cherry-picked from commit
f18d6ed from PR #6769, so that the fix can be merged separately.