Skip to content
This repository has been archived by the owner. It is now read-only.

EINTR handling #37

Closed
sunshowers opened this Issue Apr 9, 2017 · 14 comments

Comments

Projects
None yet
3 participants
@sunshowers
Copy link

sunshowers commented Apr 9, 2017

I wanted to bring EINTR (ErrorKind::Interrupted) handling up as a general topic.

Traditionally, EINTR on Unix systems has meant that a signal has interrupted this syscall. Usually, the operation can be immediately retried (unlike EAGAIN/EWOULDBLOCK/WouldBlock which would have to be retried later).

How should tokio-io handle EINTR, if at all? For example, this call in FramedWrite::poll_complete can fail with ErrorKind::Interrupted -- this means that a stream forwarding to a FramedWrite can fail with EINTR at this point. This means that a Forward future when run with Core::run will fail and consume the stream and sink, even though it can just be immediately retried.

  • Should FramedWrite retry on ErrorKind::Interrupted?
  • Should try_nb! retry on ErrorKind::Interrupted?

More general questions (perhaps more appropriate for other crates):

  • Should Forward futures have some way to return the stream and sink on error as well?
  • How should this general pattern (Core::run gets passed a future which errored out, but the future is still valid and poll can still be called on it) be handled?
@carllerche

This comment has been minimized.

Copy link
Member

carllerche commented Apr 9, 2017

@sunshowers sunshowers closed this Apr 9, 2017

@sunshowers sunshowers reopened this Apr 9, 2017

@sunshowers

This comment has been minimized.

Copy link
Author

sunshowers commented Apr 9, 2017

(Whoops didn't mean to close this)

That would require every AsyncRead and AsyncWrite to do its own EINTR handling, which means like much of the standard library like File would have to be wrapped.

@alexcrichton

This comment has been minimized.

Copy link
Contributor

alexcrichton commented Apr 10, 2017

Yeah the intention is definitely that no one worries about EINTR handling in general. The standard library chose to expose EINTR from read and write functions but not higher level conveniences like read_to_end and such.

I think it's reasonable to follow a similar pattern in tokio where all combinators and such handle Interrupted, but the raw functions don't handle it (as they're just proxying to libstd)

@carllerche

This comment has been minimized.

Copy link
Member

carllerche commented Apr 10, 2017

Do we even want to have EINTR in read / write. I see how this makes sense for std which is providing an API to use without a runtime but with tokio you are running in context of an executor and you probably don't want the thread to hit interrupts in the first place.

I was thinking of swallowing EINTR in Read / write impls on TcpStream.

@sunshowers

This comment has been minimized.

Copy link
Author

sunshowers commented Apr 10, 2017

OK, so it turns out that tokio-io must handle EINTR. Here's why:

  1. The documentation for Write::write says that

A call to write represents at most one attempt to write to any wrapped object.

  1. This means that if one has a buffered writer and the buffer is full, the only valid thing to do on write is to write out the internal buffer, then return an error which tells the caller to retry.

  2. The only error universally recognized as "retry immediately" is ErrorKind::Interrupted.

@sunshowers

This comment has been minimized.

Copy link
Author

sunshowers commented Apr 10, 2017

That's what zstd-rs does here. (flate2-rs and bzip2-rs are actually in violation of the contract for Write::write -- I'll file issues for both of them shortly.)

@sunshowers

This comment has been minimized.

Copy link
Author

sunshowers commented Apr 10, 2017

sunshowers added a commit to sunshowers/tokio-io that referenced this issue Apr 10, 2017

handle ErrorKind::Interrupted in try_nb!
As discussed in tokio-rs#37, `tokio-io` must handle `ErrorKind::Interrupted` errors at
some level. `try_nb!` neatly solves this problem for all consumers, both
internal and external, and prevents this class of bugs from being made.

This loop would be much cleaner with the loop-break-value feature
(rust-lang/rfcs#1624), but that is still experimental.

Closes tokio-rs#37.
@alexcrichton

This comment has been minimized.

Copy link
Contributor

alexcrichton commented Apr 10, 2017

Thanks for filing issues @sid0!

Note that the comment in the docs there was largely targeted at atomicity. Basically if you successfully write any bytes then that must be reported back. I think it's fine, semantically, for an auto-retry to happen on EINTR.

@carllerche you bring up a good point, tokio is less libstd-esque. I'd be fine auto-retrying on EINTR on TcpStream/TcpListener/UdpSocket.

@sunshowers

This comment has been minimized.

Copy link
Author

sunshowers commented Apr 10, 2017

Basically if you successfully write any bytes then that must be reported back. I think it's fine, semantically, for an auto-retry to happen on EINTR.

So this wasn't clear to me from the docs at all. If that is truly the intent then the docs should probably be updated to reflect that.

I've opened up a topic on the internals board about that: https://internals.rust-lang.org/t/std-io-write-a-call-to-write-represents-at-most-one-attempt-to-write-to-any-wrapped-object/5068

@carllerche

This comment has been minimized.

Copy link
Member

carllerche commented Dec 14, 2017

What is the conclusion of this issue? Are there any action items?

@sunshowers

This comment has been minimized.

Copy link
Author

sunshowers commented Dec 14, 2017

Yeah -- it should be documented that AsyncWrite instances should never propagate ErrorKind::Interrupted errors and should instead retry.

@carllerche carllerche added this to the v0.2 milestone Dec 15, 2017

@carllerche

This comment has been minimized.

Copy link
Member

carllerche commented Dec 15, 2017

Would you be able to write up a PR with the doc changes and maybe check if tokio-core handles EINTR?

@sunshowers

This comment has been minimized.

Copy link
Author

sunshowers commented Dec 15, 2017

Would you be able to write up a PR with the doc changes and maybe check if tokio-core handles EINTR?

Probably not any time soon, I'm afraid.

@carllerche carllerche referenced this issue Feb 1, 2018

Closed

EINTR handling #98

@carllerche

This comment has been minimized.

Copy link
Member

carllerche commented Feb 1, 2018

The tokio-io crate has been moved into the tokio git repo.

I created a new issue over there. See link above.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.