Skip to content

Skip the signal watcher on wasip1 - #2

Open
arena-ai-coding-agent[bot] wants to merge 1 commit into
mainfrom
fix/wasip1-signal-watcher
Open

Skip the signal watcher on wasip1#2
arena-ai-coding-agent[bot] wants to merge 1 commit into
mainfrom
fix/wasip1-signal-watcher

Conversation

@arena-ai-coding-agent

Copy link
Copy Markdown

Fixes microsoft#63862

Problem

tsc --lsp --stdio (and the --api server) call signal.NotifyContext unconditionally at startup. On wasip1, signals are never delivered, so Go's signal-watcher goroutine busy-spins (it never gets to idle in single-threaded Wasm). That starves the scheduler: the LSP stdin reader, parked waiting for input, never wakes, so a full LSP session under node:wasi hangs after answering initialize, spinning at 100% CPU. CLI invocations (tsc -p) are unaffected for the same reason — they exit before the waiter matters.

Implementation

  • Add a small notifyContext helper in tsc/cmd/tsc/notify.go.
  • On wasip1 it returns context.WithCancel(parent) — since no signal can arrive, cancellation can only come from the returned CancelFunc, so this is equivalent and avoids the busy loop entirely.
  • All other platforms delegate to signal.NotifyContext, so behavior is unchanged.
  • Route all three call sites (main.go, lsp.go, api.go) through the helper.

Tests

No automated test is added: exercising the wasip1 path requires a wasip1 binary run under a WASI host (the issue includes a minimal node:wasi repro driver, which confirms the hang before the patch and a working initialize/publishDiagnostics/hover/shutdown session after). Native signal handling paths are untouched. The full CI suite runs on this PR.

AI assistance disclosure

This patch was authored with AI assistance and has been read and reviewed by the submitting operator before submission.

PR checklist
  • Fixes a tracked issue
  • Branch is up to date with main
  • npx hereby test (running via CI)
  • npx hereby lint (running via CI)
  • npx hereby check:format (running via CI)
  • Change is minimal and reviewed

On wasip1, no signal can ever be delivered, but Go's signal watcher
goroutine busy-spins (it never idles in single-threaded Wasm). That
starves the scheduler, so e.g. the LSP stdin reader never wakes and a
running `tsc --lsp --stdio` under node:wasi hangs after responding to
`initialize`.

Since cancellation can only come from the returned CancelFunc on
wasip1, an ordinary context.WithCancel is equivalent and lets the
runtime idle in poll_oneoff instead of burning a core.

Fixes microsoft#63862

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

wasip1: LSP over node:wasi hangs after initialize — signal watcher starves the scheduler (fix included)

0 participants