Skip to content

Feature request: Allow I/O multiplexing without threads #235

@andy0130tw

Description

@andy0130tw

I am making a WASM-based language service running completely within VS Code powered by the WASM execution engine extension. During the porting process, I noticed some missing feature that kept my language server from establishing the connection properly. After much investigation, I pinpointed the concrete requirements in WASI Preview 1's I/O handling to enable proper cooperative I/O multiplexing in WebAssembly programs without resorting to the threads extension.

First of all, I admit my use case is niche. The language server of interest, Agda language server, is written in Haskell and can be compiled with the Glasgow Haskell Compiler (GHC). Its WASM backend (specifically its runtime, RTS) does not yet have thread support. Without a threaded RTS, the Haskell program can still operate concurrently, but given an average best-effort WASI implementation, it is likely unable to maintain a duplex communication with the client.

Specifically, I propose changes on VS Code's WASM execution engine to (1.) provide a nonblocking way to read stdin-pipes and (2.) implement the blocking behavior in poll_oneoff to better align with POSIX-like I/O expectations on multiplexing.

1. Non-blocking stdin reads

  • Current behavior: fd_read() on stdin blocks indefinitely when no input is available, leading to starvation.
  • Proposed behavior: Allow fd_read() on stdin to return EAGAIN (WasiError.again) when no input is available, enabling non-blocking operation.
  • Benefits: This change prevents runtime softlocks in cooperative schedulers, enables standard non-blocking I/O patterns, without affecting existing program expecting blocking behavior. I expect this to be a minor interface change.

2. Correct poll_oneoff blocking on stdin

  • Current behavior: poll_oneoff returns immediately even when subscriptions expect blocking on stdin readiness.
  • Proposed behavior: poll_oneoff should block when subscriptions specify waiting for stdin to become readable and there is no clock event present, resembling the POSIX select() semantics.
  • Benefits: This enables proper event-driven I/O multiplexing, fixes broken assumptions in runtimes that rely on blocking poll behavior, and improves WASI's fidelity to standard I/O models. This would be very complex compared to 1., but since my only concern is stdin, it is possible to apply enough hacks just for my use case.

References

Here is my study of non-blocking reads on various WASM runtimes. A PoC implementation can be found in the fork agda-web/vscode-wasm. I am available to provide more context and assist the shaping if needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature-requestRequest for new features or functionality

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions