Skip to content

runtime/wasm: support blocking primitives (based on #100) - #102

Closed
cpunion wants to merge 6 commits into
codex/fork-wasm-wasi-single-worker-20260801from
codex/fork-wasm-blocking-primitives-20260801
Closed

runtime/wasm: support blocking primitives (based on #100)#102
cpunion wants to merge 6 commits into
codex/fork-wasm-wasi-single-worker-20260801from
codex/fork-wasm-blocking-primitives-20260801

Conversation

@cpunion

@cpunion cpunion commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Depends on #100.

Fork-only staging PR for xgo-dev#2152. The base branch is the validated W staging head, so this PR shows only the B increment and does not add CI load to xgo-dev/llgo. The old upstream xgo-dev#2198 draft remains frozen.

Problem

#100 can schedule multiple goroutines on one wasm worker, but channels and standard synchronization still use pthread waits. A blocking receive, Mutex, WaitGroup, Cond, or semaphore can therefore sleep the only M instead of parking only the current G; default P1 also must not depend on WASI pthread imports.

Implementation

  • Split channel locking/wakeup behind target-selected adapters: default single-worker wasm stores an opaque scheduler waiter, while native and explicit P1 threads retain pthread mutex/condition behavior.
  • Implement wasm semaphore and notify-list queues that park and ready Gs through the scheduler boundary. This covers channels, select, Mutex, RWMutex, WaitGroup, Cond, Once, Pool, atomic.Value, and sync.Map.
  • Keep the queue state inside the runtime/sync layer. The scheduler exposes only SchedulerWaiter; it does not learn channel, semaphore, or notify-list policy.
  • Preserve Go 1.24 and Go 1.25+ WaitGroup link signatures in separate source-selected files.
  • Extend the existing internal/sync source patches to Go 1.24 and retain the LLGo-compatible result lowering used by HashTrieMap.
  • Correct pthread attribute Init/Destroy declarations to their C ABI signatures and cover the changed wrappers.
  • Exercise the same blocking fixture from J32, J64, and default P1; use the standalone fixture for explicit LLGO_WASI_THREADS=1 compatibility.

The lock-free Go maps used for wasm wait queues are valid only for the default one-M single-worker backend selected by these files. Explicit threads select the pthread implementation. Multi-worker synchronization remains a later M1/M2 stage.

Validation

All local commands used GOMAXPROCS=2, GOMEMLIMIT=6GiB, -p=1, fresh -a builds, and LLGO_BUILD_CACHE=off where applicable.

  • Focused source-patch/type-model tests pass; effectiveTypeSizes is 100% covered and buildSourcePatchOverlayForGOROOT is 84.6% covered.
  • runtime/internal/clite/pthread/sync, runtime/internal/runtime, and runtime/internal/lib/runtime pass/build; all six changed pthread attribute methods are 100% covered.
  • J32 (-target wasm), J64 (GOOS=js GOARCH=wasm), and P1 (GOOS=wasip1 GOARCH=wasm) execute the complete scheduler plus blocking fixture.
  • All three profiles produce the expected deadlock diagnostic; P1 passes wasm-tools validate --features all and runs under Wasmtime.
  • Explicit LLGO_WASI_THREADS=1 P1 builds the blocking fixture.
  • The native blocking fixture builds and runs. A representative empty native binary is unchanged at 84,864 B with identical section sizes.
  • A representative Cortex-M4 empty ELF is byte-identical to runtime/wasm: add WASI single-worker scheduler (based on xgo-dev #2192, #2208) #100 at 1,804 B (text/data/bss = 140/0/10).
  • Base runtime/wasm: add WASI single-worker scheduler (based on xgo-dev #2192, #2208) #100 head 50866cd89 has 39 passing checks across Ubuntu/macOS, Go 1.24/1.26, wasm runtime, LTO, coverage, release artifacts, and embedded targets; only release publication is intentionally skipped.
  • Current B head 8a406388b also has 39 passing checks across the same complete matrix; only release publication is intentionally skipped.

Independent diff over #100: 19 files, +892/-70. No previously runnable test is skipped or ignored.

@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

LLGo baseline benchmarks

8a406388ba6a | workflow run | long-term charts

Program measurements

Platform Workload File size vs main Build vs main Run vs main
Linux cprintf 18784 B +1.3% (worse) 363.243 ms -11.9% (better) 1.381 ms -11.0% (better)
Linux fmtprintf 2219248 B +0.3% (worse) 3.327 s -13.7% (better) 2.752 ms -16.3% (better)
Linux println 71744 B -1.3% (better) 359.165 ms -10.2% (better) 1.674 ms +0.0% (worse)
macOS cprintf 84672 B +0.0% 637.440 ms +53.8% (worse) 4.014 ms +11.9% (worse)
macOS fmtprintf 2361968 B +0.7% (worse) 3.809 s -3.3% (better) 20.755 ms -11.2% (better)
macOS println 125712 B -1.0% (better) 538.008 ms +29.8% (worse) 4.247 ms -41.5% (better)
Core language and compiler benchmarks
Platform Benchmark ns/op vs main
Linux BenchmarkLookupPCRandom 12.280 ns/op -8.9% (better)
Linux BenchmarkMergeCompilerFlags 146.600 ns/op -5.1% (better)
Linux BenchmarkMergeLinkerFlags 94.570 ns/op -6.6% (better)
Linux BenchmarkChannelBuffered 36.270 ns/op +4.3% (worse)
Linux BenchmarkChannelHandoff 25001 ns/op -22.0% (better)
Linux BenchmarkDefer 42.780 ns/op -24.0% (better)
Linux BenchmarkDirectCall 1.760 ns/op +12.6% (worse)
Linux BenchmarkGlobalRead 1.757 ns/op +12.6% (worse)
Linux BenchmarkGlobalWrite 2.806 ns/op +12.5% (worse)
Linux BenchmarkGoroutine 30887 ns/op -59.1% (better)
Linux BenchmarkInterfaceCall 8.791 ns/op +12.8% (worse)
Linux BenchmarkRuntimeGetG 1.759 ns/op -66.9% (better)
macOS BenchmarkLookupPCRandom 14.200 ns/op +14.1% (worse)
macOS BenchmarkMergeCompilerFlags 137.400 ns/op +10.4% (worse)
macOS BenchmarkMergeLinkerFlags 88.310 ns/op +27.3% (worse)
macOS BenchmarkChannelBuffered 24.260 ns/op -12.5% (better)
macOS BenchmarkChannelHandoff 7787 ns/op +11.1% (worse)
macOS BenchmarkDefer 31.740 ns/op -15.2% (better)
macOS BenchmarkDirectCall 1.055 ns/op -27.4% (better)
macOS BenchmarkGlobalRead 1.088 ns/op -10.2% (better)
macOS BenchmarkGlobalWrite 1.051 ns/op -29.3% (better)
macOS BenchmarkGoroutine 52665 ns/op +66.4% (worse)
macOS BenchmarkInterfaceCall 4.615 ns/op -14.5% (better)
macOS BenchmarkRuntimeGetG 2.184 ns/op -15.3% (better)

Compared only with the latest matching platform in the main series.

Warning

  • Persistent publishing is unavailable because no data token is configured.

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