Skip to content

Commit 2a20f90

Browse files
a-nogikhdvyukov
authored andcommitted
pkg/manager: prevent deadlock on ReproLoop cancellation
When the context is cancelled, no one may be polling the pingQueue, yet we write to it synchronously. Wrap it in a select{} statement and add a test to ensure that the loop reacts properly to the context cancellation.
1 parent 2a6eded commit 2a20f90

File tree

2 files changed

+27
-1
lines changed

2 files changed

+27
-1
lines changed

pkg/manager/repro.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,11 @@ func (r *ReproLoop) Loop(ctx context.Context) {
230230
r.mu.Unlock()
231231

232232
r.parallel <- struct{}{}
233-
r.pingQueue <- struct{}{}
233+
// If the context is cancelled, no one is listening on pingQueue.
234+
select {
235+
case r.pingQueue <- struct{}{}:
236+
default:
237+
}
234238
}()
235239
}
236240
}

pkg/manager/repro_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,28 @@ func TestReproRWRace(t *testing.T) {
123123
mock.onVMShutdown(t, obj)
124124
}
125125

126+
func TestCancelRunningRepro(t *testing.T) {
127+
mock := &reproMgrMock{
128+
run: make(chan runCallback),
129+
}
130+
obj := NewReproLoop(mock, 1, false)
131+
ctx, done := context.WithCancel(context.Background())
132+
complete := make(chan struct{})
133+
go func() {
134+
obj.Loop(ctx)
135+
close(complete)
136+
}()
137+
138+
defer func() {
139+
<-complete
140+
}()
141+
142+
obj.Enqueue(&Crash{Report: &report.Report{Title: "A"}})
143+
obj.Enqueue(&Crash{Report: &report.Report{Title: "B"}})
144+
<-mock.run
145+
done()
146+
}
147+
126148
type reproMgrMock struct {
127149
reserved atomic.Int64
128150
run chan runCallback

0 commit comments

Comments
 (0)