diff options
Diffstat (limited to '')
-rw-r--r-- | test/chan/doubleselect.go | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/test/chan/doubleselect.go b/test/chan/doubleselect.go new file mode 100644 index 0000000..ff69dbe --- /dev/null +++ b/test/chan/doubleselect.go @@ -0,0 +1,87 @@ +// run + +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Test the situation in which two cases of a select can +// both end up running. See http://codereview.appspot.com/180068. + +package main + +import ( + "flag" + "runtime" +) + +var iterations *int = flag.Int("n", 100000, "number of iterations") + +// sender sends a counter to one of four different channels. If two +// cases both end up running in the same iteration, the same value will be sent +// to two different channels. +func sender(n int, c1, c2, c3, c4 chan<- int) { + defer close(c1) + defer close(c2) + defer close(c3) + defer close(c4) + + for i := 0; i < n; i++ { + select { + case c1 <- i: + case c2 <- i: + case c3 <- i: + case c4 <- i: + } + } +} + +// mux receives the values from sender and forwards them onto another channel. +// It would be simpler to just have sender's four cases all be the same +// channel, but this doesn't actually trigger the bug. +func mux(out chan<- int, in <-chan int, done chan<- bool) { + for v := range in { + out <- v + } + done <- true +} + +// recver gets a steam of values from the four mux's and checks for duplicates. +func recver(in <-chan int) { + seen := make(map[int]bool) + + for v := range in { + if _, ok := seen[v]; ok { + println("got duplicate value: ", v) + panic("fail") + } + seen[v] = true + } +} + +func main() { + runtime.GOMAXPROCS(2) + + flag.Parse() + c1 := make(chan int) + c2 := make(chan int) + c3 := make(chan int) + c4 := make(chan int) + done := make(chan bool) + cmux := make(chan int) + go sender(*iterations, c1, c2, c3, c4) + go mux(cmux, c1, done) + go mux(cmux, c2, done) + go mux(cmux, c3, done) + go mux(cmux, c4, done) + go func() { + <-done + <-done + <-done + <-done + close(cmux) + }() + // We keep the recver because it might catch more bugs in the future. + // However, the result of the bug linked to at the top is that we'll + // end up panicking with: "throw: bad g->status in ready". + recver(cmux) +} |