Skip to content

Commit

Permalink
runtime: avoid deadlock in synctest changegstatus when copying stacks
Browse files Browse the repository at this point in the history
For #67434
Fixes #70452

Change-Id: Ie655a9e55837aa68b6bfb0bb69b6c8caaf3bbea5
Reviewed-on: https://go-review.googlesource.com/c/go/+/629856
Reviewed-by: Russ Cox <[email protected]>
LUCI-TryBot-Result: Go LUCI <[email protected]>
Auto-Submit: Damien Neil <[email protected]>
Reviewed-by: Michael Pratt <[email protected]>
  • Loading branch information
neild authored and gopherbot committed Nov 20, 2024
1 parent b483f38 commit 1d28fa8
Showing 1 changed file with 19 additions and 3 deletions.
22 changes: 19 additions & 3 deletions src/runtime/synctest.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,20 @@ type synctestGroup struct {
// changegstatus is called when the non-lock status of a g changes.
// It is never called with a Gscanstatus.
func (sg *synctestGroup) changegstatus(gp *g, oldval, newval uint32) {
lock(&sg.mu)
// Determine whether this change in status affects the idleness of the group.
// If this isn't a goroutine starting, stopping, durably blocking,
// or waking up after durably blocking, then return immediately without
// locking sg.mu.
//
// For example, stack growth (newstack) will changegstatus
// from _Grunning to _Gcopystack. This is uninteresting to synctest,
// but if stack growth occurs while sg.mu is held, we must not recursively lock.
totalDelta := 0
wasRunning := true
switch oldval {
case _Gdead:
wasRunning = false
sg.total++
totalDelta++
case _Gwaiting:
if gp.waitreason.isIdleInSynctest() {
wasRunning = false
Expand All @@ -51,12 +59,20 @@ func (sg *synctestGroup) changegstatus(gp *g, oldval, newval uint32) {
switch newval {
case _Gdead:
isRunning = false
sg.total--
totalDelta--
case _Gwaiting:
if gp.waitreason.isIdleInSynctest() {
isRunning = false
}
}
// It's possible for wasRunning == isRunning while totalDelta != 0;
// for example, if a new goroutine is created in a non-running state.
if wasRunning == isRunning && totalDelta == 0 {
return
}

lock(&sg.mu)
sg.total += totalDelta
if wasRunning != isRunning {
if isRunning {
sg.running++
Expand Down

0 comments on commit 1d28fa8

Please sign in to comment.