tokio-rs / tokio

A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ...
https://tokio.rs
MIT License
26.76k stars 2.47k forks source link

Need an interface to plug asynchronous Windows Handle types for serial ports #3396

Open jadamcrain opened 3 years ago

jadamcrain commented 3 years ago

Is your feature request related to a problem? Please describe. In Tokio 0.2, PollEvented was used in tokio-serial to make serial ports work asynchronously with Tokio.

Tokio 0.3/1.0 have removed all the mio types, and exposed only a unix-specifix AsyncFd type. So serial ports can be integrated asynchrnously on Linux, but not windows.

Describe the solution you'd like I'd like to see a parallel API to AsyncFd which is Windows-only allowing a windows Handle type to be registered.

To register a handle, I personally only need a single public method:

pub fn register<H, R >(inner: H) -> tokio::io::Result<R> where H: std::os::windows::io::AsRawHandle, R: AsyncRead + AsyncWrite + Unpin

Describe alternatives you've considered

I've considered running serial ports synchronously, after all there aren't 10K of them, but we are writing protocol libraries for SCADA systems using Tokio where the same protocol is used over TCP or serial. Our codebase uses generic fucntionality based on AsyncRead + AsyncWrite so this not tenable for us because our entire protocol stack is async.

I've also considered having my Windows serial port implementation fake async by delegating blocking operations to a dedicated thread, but this is not optimal in the long run.

Additional context Add any other context or screenshots about the feature request here.

Darksonn commented 3 years ago

This is something we do want to do. I imagine we can add an AsyncHandle type similar to how AsyncFd works. The details of its API need to be worked out though.

jadamcrain commented 3 years ago

Thanks, we'd be happy to help with this feature and iterate the API until we have something that everyone is happy with.

I don't have enough context to understand why AsyncFd requires all the types (guards, etc) and methods that it has. At the end of the day, all we wanted from AsyncFd was a way to get a type that was AsyncRead + AsyncWrite + Unpin. Another question I had was why there's isn't an implementation of these traits for AsyncFd included, i.e. why might an implementation need to customize these trait implementations?

Darksonn commented 3 years ago

The guards help make sure that the ready flag is cleared correctly when using try_io, because it should only be cleared if the read returns WouldBlock, which can be somewhat tricky. I believe the lack of IO traits is just to have a more minimal API.

carllerche commented 3 years ago

Adding AsyncHandle would be non trivial due to how IOCP works. It looks like the serial lib really only needs names pipes on windows? We should focus on getting a named pipe type in tokio.

Darksonn commented 3 years ago

For context, named pipes are being worked on in #3388.

DemiMarie commented 1 year ago

Adding AsyncHandle would be non trivial due to how IOCP works. It looks like the serial lib really only needs names pipes on windows? We should focus on getting a named pipe type in tokio.

Why is that?

Noah-Kennedy commented 1 year ago

My understanding is that it's because IOCP isn't based on readiness like kqueue or epoll, and is instead built around an operation itself being async and posting a completion when it finishes. This means it would need to have a very different API than, say, AsyncFd.

I think that this is still doable though.