From 84bb9e62f06dbb62279241fa0bd7a6c8846271ac Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 7 Jul 2016 17:43:08 -0700 Subject: runtime: handle selects with duplicate channels in shrinkstack The shrinkstack code locks all the channels a goroutine is waiting for, but didn't handle the case of the same channel appearing in the list multiple times. This led to a deadlock. The channels are sorted so it's easy to avoid locking the same channel twice. Fixes #16286. Change-Id: Ie514805d0532f61c942e85af5b7b8ac405e2ff65 Reviewed-on: https://go-review.googlesource.com/24815 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Austin Clements --- src/runtime/stack.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src/runtime/stack.go') diff --git a/src/runtime/stack.go b/src/runtime/stack.go index b14b4005d8..8398a101fd 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -784,8 +784,12 @@ func syncadjustsudogs(gp *g, used uintptr, adjinfo *adjustinfo) uintptr { // copystack; otherwise, gp may be in the middle of // putting itself on wait queues and this would // self-deadlock. + var lastc *hchan for sg := gp.waiting; sg != nil; sg = sg.waitlink { - lock(&sg.c.lock) + if sg.c != lastc { + lock(&sg.c.lock) + } + lastc = sg.c } // Adjust sudogs. @@ -803,8 +807,12 @@ func syncadjustsudogs(gp *g, used uintptr, adjinfo *adjustinfo) uintptr { } // Unlock channels. + lastc = nil for sg := gp.waiting; sg != nil; sg = sg.waitlink { - unlock(&sg.c.lock) + if sg.c != lastc { + unlock(&sg.c.lock) + } + lastc = sg.c } return sgsize -- cgit v1.3-5-g9baa