Skip to content

test: avoid scheduler races in context waits - #2451

Merged
xushiwei merged 2 commits into
xgo-dev:mainfrom
cpunion:codex/context-test-scheduler-race-20260830
Aug 30, 2026
Merged

xushiwei merged 2 commits into
xgo-dev:mainfrom
cpunion:codex/context-test-scheduler-race-20260830

Conversation

@cpunion

@cpunion cpunion commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • check already-canceled contexts synchronously instead of racing Done against a newly created short timer
  • give asynchronous AfterFunc delivery a realistic bound and recheck the success channel if the timeout case is selected
  • apply the synchronous assertion consistently to cancel and past-deadline cases

This changes tests only; it does not relax or modify context, timer, or scheduler semantics.

Why

The Windows MinGW full-test lane in cpunion#208 reported TestAfterFunc and TestWithTimeoutCause, then passed unchanged on rerun. WithTimeoutCause(parent, -time.Hour, cause) closes Done before returning. In the old assertion, time.After(10ms) was created while entering the select; if the test goroutine was descheduled long enough, both channels were ready and Go could legally choose the timeout case. The 100ms asynchronous callback bound had the same scheduler sensitivity.

The immediate cases now verify the stronger contract directly with a nonblocking receive. The asynchronous helper also checks Done again before reporting a timeout, so a random select choice cannot produce a false failure.

Validation

  • go test ./test/std/context -count=100
  • go test -race ./test/std/context -count=10
  • unchanged failed jobs from cpunion/llgo#208 both passed on rerun: macOS LLGo and Windows MinGW full tests

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: avoid scheduler races in context waits

Focused, well-scoped change to test/std/context/context_test.go. It introduces two helpers — requireDone (non-blocking "must already be done") and waitDone (wait up to a timeout, with a recheck) — and replaces the ad-hoc select { case <-ch: ... case <-time.After(...) } patterns.

Assessment: The refactor is correct and improves the tests.

  • requireDone is the right (stricter) check at the four synchronous-cancellation sites: an explicit cancel(...) or a past deadline/timeout cancels the context before the constructor/cancel call returns, so a non-blocking select with default is appropriate and would catch a regression where cancellation is not synchronous.
  • waitDone correctly uses time.NewTimer + defer timer.Stop() (no leaked timer) and rechecks done after the timer fires to avoid a false timeout when select picks the timer branch even though done became ready.
  • Happy-path runtime is unaffected: the larger bounds only apply on the failure path; on success the <-done branch is taken immediately.
  • No security or performance concerns.

Two minor, non-blocking notes are inline below.

Comment thread test/std/context/context_test.go Outdated
Comment thread test/std/context/context_test.go
@github-actions

Copy link
Copy Markdown

LLGo baseline benchmarks

cd564c6d258e | workflow run | long-term charts

Program measurements

Platform Workload File size vs base Text size vs base Build vs base Run vs base
Linux cprintf 19496 B 0 B / +0.0% 387 B 0 B / +0.0% 357.014 ms +4.735 ms / +1.3% (worse) 1.338 ms -33.78 us / -2.5% (better)
Linux cprintf-lto 19328 B 0 B / +0.0% 368 B 0 B / +0.0% 369.691 ms +18.55 ms / +5.3% (worse) 1.404 ms -257.9 us / -15.5% (better)
Linux fmtprintf 1607888 B -8 B / -0.0004975% (better) 490042 B 0 B / +0.0% 2.435 s +4.893 ms / +0.2% (worse) 3.449 ms -100.9 us / -2.8% (better)
Linux fmtprintf-lto 1485616 B 0 B / +0.0% 450888 B 0 B / +0.0% 8.232 s +187.8 ms / +2.3% (worse) 3.402 ms +48.95 us / +1.5% (worse)
Linux println 62344 B 0 B / +0.0% 15286 B 0 B / +0.0% 338.747 ms -3.426 ms / -1.0% (better) 1.717 ms +7.881 us / +0.5% (worse)
Linux println-lto 54160 B 0 B / +0.0% 12914 B 0 B / +0.0% 532.185 ms +12.37 ms / +2.4% (worse) 1.743 ms +19.52 us / +1.1% (worse)
macOS cprintf 84480 B 0 B / +0.0% 16733 B 0 B / +0.0% 489.452 ms -8.041 ms / -1.6% (better) 3.488 ms 0 ns / +0.0%
macOS cprintf-lto 100704 B 0 B / +0.0% 16713 B 0 B / +0.0% 718.485 ms +160.5 ms / +28.8% (worse) 3.790 ms -4.662 ms / -55.2% (better)
macOS fmtprintf 1470304 B 0 B / +0.0% 867088 B 0 B / +0.0% 3.206 s +274.5 ms / +9.4% (worse) 7.059 ms -1.214 ms / -14.7% (better)
macOS fmtprintf-lto 1175536 B 0 B / +0.0% 862804 B 0 B / +0.0% 8.651 s -1.16 s / -11.8% (better) 8.553 ms +1.436 ms / +20.2% (worse)
macOS println 114784 B 0 B / +0.0% 35181 B 0 B / +0.0% 578.547 ms -276.9 ms / -32.4% (better) 4.788 ms -1.498 ms / -23.8% (better)
macOS println-lto 118656 B 0 B / +0.0% 32833 B 0 B / +0.0% 757.851 ms -282.4 ms / -27.2% (better) 4.494 ms -969.3 us / -17.7% (better)
Windows MinGW cprintf 20480 B 0 B / +0.0% 4662 B 0 B / +0.0% 890.689 ms +92.65 ms / +11.6% (worse) 3.918 ms +591.8 us / +17.8% (worse)
Windows MinGW cprintf-lto 18432 B 0 B / +0.0% 4582 B 0 B / +0.0% 908.830 ms +81.43 ms / +9.8% (worse) 3.860 ms +411.6 us / +11.9% (worse)
Windows MinGW fmtprintf 1936384 B 0 B / +0.0% 597398 B 0 B / +0.0% 3.683 s +251.1 ms / +7.3% (worse) 9.119 ms +1.066 ms / +13.2% (worse)
Windows MinGW fmtprintf-lto 1990656 B 0 B / +0.0% 590870 B 0 B / +0.0% 9.940 s +660.6 ms / +7.1% (worse) 8.069 ms +393.8 us / +5.1% (worse)
Windows MinGW println 74240 B 0 B / +0.0% 25062 B 0 B / +0.0% 852.072 ms -399.4 us / -0.04685% (better) 6.876 ms +370.6 us / +5.7% (worse)
Windows MinGW println-lto 67584 B 0 B / +0.0% 21734 B 0 B / +0.0% 1.084 s +81.85 ms / +8.2% (worse) 7.011 ms +211 us / +3.1% (worse)
Windows MSVC cprintf 12288 B 0 B / +0.0% 4438 B 0 B / +0.0% 560.287 ms +33.57 ms / +6.4% (worse) 3.448 ms +29.1 us / +0.9% (worse)
Windows MSVC cprintf-lto 11776 B 0 B / +0.0% 4278 B 0 B / +0.0% 575.293 ms +17.93 ms / +3.2% (worse) 3.383 ms -517.2 us / -13.3% (better)
Windows MSVC fmtprintf 1475584 B 0 B / +0.0% 596982 B 0 B / +0.0% 2.738 s +71.74 ms / +2.7% (worse) 7.529 ms -760.4 us / -9.2% (better)
Windows MSVC fmtprintf-lto 1522688 B 0 B / +0.0% 597782 B 0 B / +0.0% 7.550 s +118.1 ms / +1.6% (worse) 7.871 ms +409.7 us / +5.5% (worse)
Windows MSVC println 47104 B 0 B / +0.0% 25062 B 0 B / +0.0% 533.161 ms -113.6 ms / -17.6% (better) 6.005 ms -1.545 ms / -20.5% (better)
Windows MSVC println-lto 44032 B 0 B / +0.0% 22102 B 0 B / +0.0% 742.255 ms -13.11 ms / -1.7% (better) 5.988 ms +417.2 us / +7.5% (worse)
Core language and compiler benchmarks
Platform Benchmark ns/op vs base
Linux BenchmarkLookupPCRandom 12.580 ns/op -0.02 ns/op / -0.2% (better)
Linux BenchmarkMergeCompilerFlags 135.700 ns/op +1.1 ns/op / +0.8% (worse)
Linux BenchmarkMergeLinkerFlags 89.770 ns/op +0.41 ns/op / +0.5% (worse)
Linux BenchmarkChannelBuffered 37.320 ns/op -0.3 ns/op / -0.8% (better)
Linux BenchmarkChannelHandoff 24230 ns/op -594 ns/op / -2.4% (better)
Linux BenchmarkDefer 48.760 ns/op +1.11 ns/op / +2.3% (worse)
Linux BenchmarkDirectCall 1.759 ns/op +0.001 ns/op / +0.1% (worse)
Linux BenchmarkGlobalRead 1.758 ns/op -0.003 ns/op / -0.2% (better)
Linux BenchmarkGlobalWrite 2.807 ns/op +0.002 ns/op / +0.1% (worse)
Linux BenchmarkGoroutine 36337 ns/op +4790 ns/op / +15.2% (worse)
Linux BenchmarkInterfaceCall 8.801 ns/op +0.03 ns/op / +0.3% (worse)
Linux BenchmarkRuntimeGetG 2.111 ns/op -0.02 ns/op / -0.9% (better)
macOS BenchmarkLookupPCRandom 18.130 ns/op +1.99 ns/op / +12.3% (worse)
macOS BenchmarkMergeCompilerFlags 140.600 ns/op -8.4 ns/op / -5.6% (better)
macOS BenchmarkMergeLinkerFlags 100.200 ns/op +13.08 ns/op / +15.0% (worse)
macOS BenchmarkChannelBuffered 33.610 ns/op +1.59 ns/op / +5.0% (worse)
macOS BenchmarkChannelHandoff 7807 ns/op -3568 ns/op / -31.4% (better)
macOS BenchmarkDefer 41.420 ns/op -2.43 ns/op / -5.5% (better)
macOS BenchmarkDirectCall 1.280 ns/op -0.001 ns/op / -0.1% (better)
macOS BenchmarkGlobalRead 1.270 ns/op +0.01 ns/op / +0.8% (worse)
macOS BenchmarkGlobalWrite 1.371 ns/op -0.087 ns/op / -6.0% (better)
macOS BenchmarkGoroutine 37885 ns/op +1833 ns/op / +5.1% (worse)
macOS BenchmarkInterfaceCall 5.846 ns/op -0.282 ns/op / -4.6% (better)
macOS BenchmarkRuntimeGetG 2.687 ns/op +0.049 ns/op / +1.9% (worse)
Windows MinGW BenchmarkLookupPCRandom 12.380 ns/op +0.01 ns/op / +0.1% (worse)
Windows MinGW BenchmarkMergeCompilerFlags 534 ns/op -1.8 ns/op / -0.3% (better)
Windows MinGW BenchmarkMergeLinkerFlags 467.200 ns/op +3.9 ns/op / +0.8% (worse)
Windows MinGW BenchmarkChannelBuffered 39.330 ns/op -0.14 ns/op / -0.4% (better)
Windows MinGW BenchmarkChannelHandoff 1444 ns/op -67 ns/op / -4.4% (better)
Windows MinGW BenchmarkDefer 60.530 ns/op +0.13 ns/op / +0.2% (worse)
Windows MinGW BenchmarkDirectCall 1.745 ns/op -0.001 ns/op / -0.1% (better)
Windows MinGW BenchmarkGlobalRead 1.746 ns/op -0.002 ns/op / -0.1% (better)
Windows MinGW BenchmarkGlobalWrite 2.786 ns/op 0 ns/op / +0.0%
Windows MinGW BenchmarkGoroutine 74129 ns/op -3562 ns/op / -4.6% (better)
Windows MinGW BenchmarkInterfaceCall 10.310 ns/op +0.05 ns/op / +0.5% (worse)
Windows MinGW BenchmarkRuntimeGetG 2.448 ns/op 0 ns/op / +0.0%
Windows MSVC BenchmarkLookupPCRandom 8.107 ns/op +0.031 ns/op / +0.4% (worse)
Windows MSVC BenchmarkMergeCompilerFlags 386.700 ns/op +3.6 ns/op / +0.9% (worse)
Windows MSVC BenchmarkMergeLinkerFlags 347.100 ns/op +11 ns/op / +3.3% (worse)
Windows MSVC BenchmarkChannelBuffered 38.810 ns/op -0.03 ns/op / -0.1% (better)
Windows MSVC BenchmarkChannelHandoff 3825 ns/op +756 ns/op / +24.6% (worse)
Windows MSVC BenchmarkDefer 44.260 ns/op +5.96 ns/op / +15.6% (worse)
Windows MSVC BenchmarkDirectCall 0.248 ns/op +0.0021 ns/op / +0.9% (worse)
Windows MSVC BenchmarkGlobalRead 0.361 ns/op -0.0147 ns/op / -3.9% (better)
Windows MSVC BenchmarkGlobalWrite 6.928 ns/op -0.033 ns/op / -0.5% (better)
Windows MSVC BenchmarkGoroutine 63334 ns/op +5861 ns/op / +10.2% (worse)
Windows MSVC BenchmarkInterfaceCall 4.400 ns/op -0.047 ns/op / -1.1% (better)
Windows MSVC BenchmarkRuntimeGetG 0.894 ns/op +0.0021 ns/op / +0.2% (worse)

Compared with e637682c8772 measured in the same runner job.

@codecov

codecov Bot commented Aug 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@xushiwei
xushiwei merged commit 3bbe9c5 into xgo-dev:main Aug 30, 2026
50 checks passed
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.

2 participants