Skip to content

runtime/wasm: add timers and host event wakeups (based on #2198) - #2204

Draft
cpunion wants to merge 37 commits into
xgo-dev:mainfrom
cpunion:codex/wasm-timers-host-wakeup
Draft

runtime/wasm: add timers and host event wakeups (based on #2198)#2204
cpunion wants to merge 37 commits into
xgo-dev:mainfrom
cpunion:codex/wasm-timers-host-wakeup

Conversation

@cpunion

@cpunion cpunion commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Depends on #2198.

Problem

The single-worker wasm runtime can park goroutines, but it has no host event source for time. time.Sleep, timers, tickers, timeout selects, and AfterFunc therefore cannot suspend one G while allowing the worker to run another G and later resume the timer owner.

Implementation

  • Add a private runtime/internal/wasmevent min-heap with stable timer ordering, Stop/Reset semantics, periodic deadline catch-up, and a lazy dispatch layer. Packages that never use time retain only a small dormant dispatch path.
  • Poll due events from the wasm scheduler. When the run queue is empty, wait through the host adapter; callbacks run only after control returns to the scheduler, so there is no synchronous Go re-entry during Asyncify unwind/rewind.
  • Use emscripten_sleep for J32/J64 host wakeups and poll(NULL, 0, timeout) for default WASI Preview 1. Keep the existing explicit LLGO_WASI_THREADS=1 timer backend unchanged.
  • Use a monotonic clock for runtime deadlines while retaining normal wall-clock/time-zone behavior for time.Now.
  • Add standard-library //go:wasmimport lowering so WASI libc/runtime declarations retain their official host module/name.
  • Update the Emscripten embind adapter for both legacy and current unified EM_INVOKER contracts.

The compiler, scheduler, timer queue, and host adapters remain separate. No new target or build tag is introduced, and native/embedded source selection is unchanged. Static wasm defer dispatch is supplied by the inherited #2208 dependency and is not part of this PR-specific diff.

Semantics covered

The shared J32, J64, and P1 acceptance fixture covers:

  • wall clock and local time zone
  • time.Sleep
  • active, stopped, reset, and expired Timer behavior
  • Ticker
  • AfterFunc waking a channel waiter
  • timeout select

Validation

Local macOS validation uses GOMAXPROCS=2, GOMEMLIMIT=3GiB, and -p=1 where applicable:

  • changed cl/ssa import, locality, and defer tests: pass
  • nested runtime timer queue and dispatch tests: pass
  • J32/J64/P1 timer fixtures: execute successfully with wasm timers ok
  • P1 wasm-tools validate --features all: pass
  • Codecov patch coverage: 97.29730% (gate passes)
  • The latest main/ssa/wasm: use static defer continuation dispatch #2208 dependency stack passes the full GitHub Ubuntu/macOS matrix and Codecov

Earlier broader validation also covered -O0, -O3, ThinLTO, explicit P1 pthread compatibility, the full nested runtime module, and bounded Ubuntu tests.

Coverage highlights:

  • runtime/internal/wasmevent: 93.9%
  • lazy dispatch functions: 100%
  • wasmImportByDoc: 100%
  • SetWasmImport: 100%

Cost

On Apple M4 Max with GOMAXPROCS=2, queue Reset+RunDue is 13.51-14.87 ns/op, 0 B/op, 0 allocs/op.

Against #2198, a no-time J32 scheduler fixture grows from 416,551 to 418,082 bytes with -pclntab=none: +1,531 bytes (+0.37%). With the default pclntab it grows from 568,087 to 571,522 bytes: +3,435 bytes (+0.60%, including metadata). Native output size remains unchanged apart from worktree-path metadata, and the representative bare-metal ELF is byte-identical.

The PR-specific diff above #2198 is 24 files, 1,048 insertions, and 45 deletions.

@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 97.29730% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/build/wasm_postlink.go 95.23% 2 Missing and 1 partial ⚠️
internal/build/build.go 85.71% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

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.

1 participant