-
Notifications
You must be signed in to change notification settings - Fork 60
Description
I am using serial-rs on Linux (both Ubuntu and OpenWRT), so this mostly only applies to serial-unix.
I use the Calloop event loop for event-driven systems. Under the hood (on Linux), Calloop basically uses epoll() with whatever file descriptors it extracts from things that implement AsRawFd. The general contract of epoll() in edge-triggered mode (which is what I tend to use) is:
- wait until
epoll_await()tells you to write - try to write N bytes from a buffer
- keep trying this until
write()returns-1and errno isEAGAIN - go back to
epoll_await()
This relies on the fd being opened in non-blocking mode. In blocking mode, you will never get EAGAIN, write() will simply block until all bytes are written.
In tty.rs you do indeed open the fd as non-blocking. But very shortly after, you clear this flag. This makes it impossible to use serial and enjoy non-blocking writes.
So for example, if I try to write N bytes from a buffer, this call eventually comes down to your implementation of io::Write. You call ppoll() with the timeout and then attempt the write. But even if the timeout is zero, the write will potentially block until all bytes are written.
The workaround we have for this at the moment is to write one byte at a time. That way any time spent blocking on write() is quite short and potentially, but not always, detected beforehand by ppoll().
Versions: Rust 1.53, serial 0.4.0,
Tried on: Ubuntu 20.10 and 21.04, OpenWRT (ramips + musl).