diff options
author | Keith Randall <khr@golang.org> | 2014-10-18 21:02:49 -0700 |
---|---|---|
committer | Keith Randall <khr@golang.org> | 2014-10-18 21:02:49 -0700 |
commit | ad36605b757c53ef1573fea79ffd033aec48e599 (patch) | |
tree | 20406ea9697c2328aa48e31969c59d4bbb2eb801 /src/runtime/chan_test.go | |
parent | a6baa662d04a1cebf2507dea9d030836da673c84 (diff) | |
download | go-ad36605b757c53ef1573fea79ffd033aec48e599.tar.gz |
runtime: dequeue the correct SudoG
select {
case <- c:
case <- c:
}
In this case, c.recvq lists two SudoGs which have the same G.
So we can't use the G as the key to dequeue the correct SudoG,
as that key is ambiguous. Dequeueing the wrong SudoG ends up
freeing a SudoG that is still in c.recvq.
The fix is to use the actual SudoG pointer as the key.
LGTM=dvyukov
R=rsc, bradfitz, dvyukov, khr
CC=austin, golang-codereviews
https://codereview.appspot.com/159040043
Diffstat (limited to 'src/runtime/chan_test.go')
-rw-r--r-- | src/runtime/chan_test.go | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/src/runtime/chan_test.go b/src/runtime/chan_test.go index 01632892e..e689ceaed 100644 --- a/src/runtime/chan_test.go +++ b/src/runtime/chan_test.go @@ -482,6 +482,35 @@ func TestShrinkStackDuringBlockedSend(t *testing.T) { <-done } +func TestSelectDuplicateChannel(t *testing.T) { + // This test makes sure we can queue a G on + // the same channel multiple times. + c := make(chan int) + d := make(chan int) + e := make(chan int) + + // goroutine A + go func() { + select { + case <-c: + case <-c: + case <-d: + } + e <- 9 + }() + time.Sleep(time.Millisecond) // make sure goroutine A gets qeueued first on c + + // goroutine B + go func() { + <-c + }() + time.Sleep(time.Millisecond) // make sure goroutine B gets queued on c before continuing + + d <- 7 // wake up A, it dequeues itself from c. This operation used to corrupt c.recvq. + <-e // A tells us it's done + c <- 8 // wake up B. This operation used to fail because c.recvq was corrupted (it tries to wake up an already running G instead of B) +} + func BenchmarkChanNonblocking(b *testing.B) { myc := make(chan int) b.RunParallel(func(pb *testing.PB) { |