summaryrefslogtreecommitdiff
path: root/src/runtime/chan_test.go
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2014-10-18 21:02:49 -0700
committerKeith Randall <khr@golang.org>2014-10-18 21:02:49 -0700
commitad36605b757c53ef1573fea79ffd033aec48e599 (patch)
tree20406ea9697c2328aa48e31969c59d4bbb2eb801 /src/runtime/chan_test.go
parenta6baa662d04a1cebf2507dea9d030836da673c84 (diff)
downloadgo-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.go29
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) {