Repository navigation
[wasi] Fix event loop hook duplication and idle socket spinning - #136395
Merged
Merged
Conversation
CheckPollables re-registered a poll hook once per pollable it subscribed, so a connected socket (input + output pollables) doubled its hook entries every iteration until memory ran out, and hooks with no pollables were dropped. Re-register each live hook once. A connected socket also always subscribed to its output stream, which is almost always writable, so the event loop never blocked and spun with any idle connection. Only subscribe to directions with a waiting operation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
|
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara |
Contributor
|
Tagging subscribers to this area: @JulieLeeMSFT, @VSadov |
pavelsavara
approved these changes
Oct 26, 2026
lewing
added a commit
that referenced
this pull request
Oct 30, 2026
Enables `SocketsHttpHandler`, `System.Net.WebSockets` and `ClientWebSocket` on WASI over wasi:sockets. WASI has no `System.Net.Security`, so only `http://` and `ws://` work. This lets WASI apps and tools (for example a `dotnet watch` agent) talk to a local server without wasi:http, which can't upgrade a connection to a WebSocket. The main parts: 1. **Enable SocketsHttpHandler and WebSockets on WASI.** `HttpClientHandler` on WASI now follows the mobile `UseNativeHttpHandler` pattern. The default is still `WasiHttpHandler`, and `WasiApp.targets` defaults `UseNativeHttpHandler=true`, so the SDK passes the switch to ILLink and `SocketsHttpHandler` is trimmed away. A trimmed hello-world `HttpClient` app keeps `System.Net.Http.dll` at ~289 KB by default, and ~631 KB with `UseNativeHttpHandler=false`. 2. **Tests.** Enables the `SocketsHttpHandler` functional tests, `System.Net.WebSockets.Tests` and `System.Net.WebSockets.Client.Tests` on CoreCLR WASI. - TLS- and MD5-dependent tests are gated on new `PlatformDetection.IsTlsSupported`/`IsMD5Supported` capability probes rather than `IsWasi`, so they light up if either becomes available. - `LoopbackProxyServer` is now async and doesn't block in `Dispose` without threads. - `Configuration.Certificates` no longer fails fast when TLS isn't supported. Its PFX files can't be decrypted on WASI. - HTTP decompression tests now run on WASI too, including Brotli and Zstandard (#136257). The WASI socket and event loop fixes these tests depend on were split out and have merged: zero-byte receives (#136394), event loop hook duplication and idle-socket spinning (#136395), and UDP `ReceiveAsync` (#136250). Known gaps and follow-ups: - Mono WASI builds the same libraries but doesn't run these tests. - The functional tests use `UseNativeHttpHandler=false`, so they no longer exercise the default `HttpClientHandler` over `WasiHttpHandler` path on WASI. - A bound UDP socket still always subscribes to its outgoing stream, so it can keep the event loop busy. - A zero-byte receive can complete early once after its data is drained, because wasmtime keeps a socket readable until a read would block. wasmtime treats this as by design (bytecodealliance/wasmtime#9667); the following real read waits correctly. - `HttpClient.DefaultProxy` on WASI now reads the standard proxy environment variables, as on Unix. Validated locally on CoreCLR WASI (Release) with the `System.Net.Http` functional, `System.Net.Sockets`, `System.Net.WebSockets` and `System.Net.WebSockets.Client` tests, plus macOS runs of the changed shared test infrastructure. > [!NOTE] > This PR description was generated with GitHub Copilot. --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Split out of #136234 at a reviewer's request.
Two bugs in the WASI event loop's socket poll hooks:
WasiEventLoop.CheckPollablesre-added each poll hook once per pollable it subscribed, not once per hook. A connected TCP socket subscribes two pollables (input and output), so its hook doubled on every pass. Hooks that subscribed nothing were dropped for good. The fix tracks the live hooks and re-adds each one once.BeforePollHookalways subscribed the output stream, which is almost always writable, so any idle connection keptpollfrom blocking. It now subscribes input or output only when_readQueueor_writeQueuehas a waiting operation (newOperationQueue.IsWaiting). The hook runs before every poll, so operations enqueued later are picked up on the next pass.Found running System.Net.WebSockets.Client.Tests with SocketsHttpHandler enabled on WASI (#136234). That run ran out of memory inside the event loop. With the fix, the suite ran 391 tests with no OOM, and idle CPU of the wasmtime process dropped from about 99% to 0%. Main has no HTTP/2 or WebSockets client on WASI, so that exact repro needs #136234.
Validation (CoreCLR WASI Release, wasmtime 49.0.1), System.Net.Sockets functional tests: no new failures with the fix (one extra candidate test was included in both runs and later removed).
Instrumenting
CheckPollableson main showed the hook count going 1 → 2 → 7 → 124 → 31,744 within 16 passes while 4 connected sockets waited on receives. The Sockets tests don't keep connections alive long enough to OOM. Two candidate regression tests (idle TCP pairs with pending receives, and a UDP receive before any datagram) both passed on main, so no new test is included.Known gap (follow-up): the UDP
BOUND_STREAMING/CONNECTEDpath still always subscribes the outgoing datagram stream.Note
This PR was generated with GitHub Copilot.