File tree 1 file changed +44
-0
lines changed
1 file changed +44
-0
lines changed Original file line number Diff line number Diff line change @@ -83,6 +83,50 @@ func TestAfterStress(t *testing.T) {
83
83
stop .Store (true )
84
84
}
85
85
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
+
86
130
func benchmark (b * testing.B , bench func (n int )) {
87
131
88
132
// Create equal number of garbage timers on each P before starting
You can’t perform that action at this time.
0 commit comments