tokio-rs / tokio

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

Support stdin/stdout (io-std feature) in WASM #6516

Open Timmmm opened 7 months ago

Timmmm commented 7 months ago

The wasm32-wasi target does support stdio, however Tokio implements stdin/stdout by spawning a new thread and using blocking IO:

cfg_io_std! {
    /// A handle to the standard input stream of a process.
    ///
    /// The handle implements the [`AsyncRead`] trait, but beware that concurrent
    /// reads of `Stdin` must be executed with care.
    ///
    /// This handle is best used for non-interactive uses, such as when a file
    /// is piped into the application. For technical reasons, `stdin` is
    /// implemented by using an ordinary blocking read on a separate thread, and
    /// it is impossible to cancel that read. This can make shutdown of the
    /// runtime hang until the user presses enter.
    ///
    /// For interactive uses, it is recommended to spawn a thread dedicated to
    /// user input and use blocking IO directly in that thread.
    ///
    /// Created by the [`stdin`] function.
    ///
    /// [`stdin`]: fn@stdin
    /// [`AsyncRead`]: trait@AsyncRead
    #[derive(Debug)]
    pub struct Stdin {
        std: Blocking<std::io::Stdin>,
    }

I did try patching Tokio to allow io-std anyway, and as you would expect you get this error:

thread 'main' panicked at D:\workspace\tokio\tokio\src\io\blocking.rs:70:46:
OS can't spawn worker thread: operation not supported on this platform

It doesn't give a useful backtrace, but I don't think we need one. WebAssembly doesn't support threads yet so this clearly isn't going to work.

However if you look at the WASI spec, stdin/stdout are streams which can return a pollable object which I think means they can work natively with Rust's async support (though I'm a Rust async neophyte so I may be wrong).

Darksonn commented 7 months ago

I suppose they probably work with #6510.

But it sounds like we could have a different implementation of this for wasm.

FrankReh commented 7 months ago

@Timmmm Are you asking about this in terms of getting tokio to support wasip2 down the road where a Pollable could be used by the tokio guest to recognize when data was available on stdin? Or do the semantics of wasip1 already provide a way to create a Future that is tied to the state of the stdin being ready to read?

Tokio's Stdin has to support the AsyncRead trait and I don't see how that would be done given just the original WASI definition which is now called WASI Preview 1. But I'm no expert and almost asked about this on the ByteAlliance Zulip channel but thought I would ask here first.

Darksonn commented 7 months ago

Ah, yes, please be aware that we only support preview 1 right now. So if this is a feature for some newer version of wasm, then this cannot happen until after #6323.

Timmmm commented 7 months ago

Ah yeah I didn't notice this is only in preview 2. Guess it will have to wait!

FrankReh commented 7 months ago

Yes, I'm eagerly watching how pollables are added to tokio for Preview 2 myself. I think a lot of the current-thread runtime can be made to work within a Wasm Component environment.