Skip to content

Commit d3f713b

Browse files
Bryan C. Millsgopherbot
Bryan C. Mills
authored andcommitted
time: add a regression test for time.AfterFunc goroutine starvation
The test is skipped on wasm platforms for now, because it successfully detects a starvation bug on those platforms. For #65178. Change-Id: I05d28f1c7be99fcab67ec4dfaa38f412e11fd3cb Reviewed-on: https://go-review.googlesource.com/c/go/+/557038 Auto-Submit: Bryan Mills <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Damien Neil <[email protected]>
1 parent b17bf6d commit d3f713b

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

src/time/sleep_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,50 @@ func TestAfterStress(t *testing.T) {
8383
stop.Store(true)
8484
}
8585

86+
func TestAfterFuncStarvation(t *testing.T) {
87+
// Start two goroutines ping-ponging on a channel send.
88+
// At any given time, at least one of these goroutines is runnable:
89+
// if the channel buffer is full, the receiver is runnable,
90+
// and if it is not full, the sender is runnable.
91+
//
92+
// In addition, the AfterFunc callback should become runnable after
93+
// the indicated delay.
94+
//
95+
// Even if GOMAXPROCS=1, we expect the runtime to eventually schedule
96+
// the AfterFunc goroutine instead of the runnable channel goroutine.
97+
// However, in https://go.dev/issue/65178 this was observed to live-lock
98+
// on wasip1/wasm and js/wasm after <10000 runs.
99+
100+
if runtime.GOARCH == "wasm" {
101+
testenv.SkipFlaky(t, 65178)
102+
}
103+
104+
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
105+
106+
var (
107+
wg sync.WaitGroup
108+
stop atomic.Bool
109+
c = make(chan bool, 1)
110+
)
111+
112+
wg.Add(2)
113+
go func() {
114+
for !stop.Load() {
115+
c <- true
116+
}
117+
close(c)
118+
wg.Done()
119+
}()
120+
go func() {
121+
for range c {
122+
}
123+
wg.Done()
124+
}()
125+
126+
AfterFunc(1*Microsecond, func() { stop.Store(true) })
127+
wg.Wait()
128+
}
129+
86130
func benchmark(b *testing.B, bench func(n int)) {
87131

88132
// Create equal number of garbage timers on each P before starting

0 commit comments

Comments
 (0)