Stream: wasi

Topic: 0-length stream writes with files and stdio


view this post on Zulip Roman Volosatovs (Aug 28 2025 at 14:53):

with recent spec changes, 0-length stream writes are used to await "readiness" and, from what I understand, the expectation is that a non-zero-length write following a 0-length write is non-blocking. This works great for e.g. TCP sockets that have a well-defined and clear way of querying the readiness, however, how is this feature expected to be implemented for files and/or stdio?
It appears that the only way to provide this functionality in the host would be buffering the data in the host and have a dedicated worker thread/task performing I/O

With this approach stream.write returning would not guarantee that the data has reached the kernel. In case of stdio, for example, that would mean that println("hello, world") returning does not guarantee that "hello, world" has even attempted to be written to the terminal.

wasi:filesystem defines sync, which seems to be the place where we could hook in to await the "flush" of file worker's buffer, but we would need to introduce a similar construct to wasi:cli.

Personally, I have been under impression that we wanted to avoid buffering in the host - and if so, how would we implement the expected behavior for 0-length writes?

cc @Alex Crichton @Joel Dice

related:

This PR relaxes the rules for stream.{read,write} to accept lengths of 0. This can be useful for signalling and querying readiness which in turn can be used to implement non-blocking POSIX operati...
Am I correct to say that: when stream.write returns BLOCKED, it continues to have access to the provided memory buffer until the write either finishes or is canceled? If so, does this mean wasi-lib...
This changes the host APIs for dealing with futures and streams from a "rendezvous"-style API to a callback-oriented one. Previously you would create e.g. a StreamReader/StreamWriter pair...

view this post on Zulip Joel Dice (Aug 28 2025 at 15:02):

cc @Luke Wagner @Dave Bakker (badeend), who came up with the zero-length read/write semantics, I believe.

view this post on Zulip Lann Martin (Aug 28 2025 at 15:24):

Does AsyncWrite::poll_write(..., &[]) not await readiness for files or stdout?

view this post on Zulip Roman Volosatovs (Aug 28 2025 at 15:27):

it appears that at least for files it actually might https://github.com/tokio-rs/tokio/blob/925c614c89d0a26777a334612e2ed6ad0e7935c3/tokio/src/fs/file.rs#L721-L791

A runtime for writing reliable asynchronous applications with Rust. Provides I/O, networking, scheduling, timers, ... - tokio-rs/tokio

view this post on Zulip Lann Martin (Aug 28 2025 at 15:30):

It appears to buffer by default, but maybe that is complete ready enough from a guest's perspective?

view this post on Zulip Roman Volosatovs (Aug 28 2025 at 15:32):

I've just had a quick chat with @Luke Wagner about it and it appears that only 0-length reads are expected to have these semantics, 0-length writes to files/stdio are free to return immediately

I think the empty poll_write is certainly "good enough"


Last updated: Dec 06 2025 at 06:05 UTC