1// run 2 3// Copyright 2009 The Go Authors. All rights reserved. 4// Use of this source code is governed by a BSD-style 5// license that can be found in the LICENSE file. 6 7// Test the situation in which two cases of a select can 8// both end up running. See http://codereview.appspot.com/180068. 9 10package main 11 12import ( 13 "flag" 14 "runtime" 15) 16 17var iterations *int = flag.Int("n", 100000, "number of iterations") 18 19// sender sends a counter to one of four different channels. If two 20// cases both end up running in the same iteration, the same value will be sent 21// to two different channels. 22func sender(n int, c1, c2, c3, c4 chan<- int) { 23 defer close(c1) 24 defer close(c2) 25 defer close(c3) 26 defer close(c4) 27 28 for i := 0; i < n; i++ { 29 select { 30 case c1 <- i: 31 case c2 <- i: 32 case c3 <- i: 33 case c4 <- i: 34 } 35 } 36} 37 38// mux receives the values from sender and forwards them onto another channel. 39// It would be simpler to just have sender's four cases all be the same 40// channel, but this doesn't actually trigger the bug. 41func mux(out chan<- int, in <-chan int, done chan<- bool) { 42 for v := range in { 43 out <- v 44 } 45 done <- true 46} 47 48// recver gets a steam of values from the four mux's and checks for duplicates. 49func recver(in <-chan int) { 50 seen := make(map[int]bool) 51 52 for v := range in { 53 if _, ok := seen[v]; ok { 54 println("got duplicate value: ", v) 55 panic("fail") 56 } 57 seen[v] = true 58 } 59} 60 61func main() { 62 runtime.GOMAXPROCS(2) 63 64 flag.Parse() 65 c1 := make(chan int) 66 c2 := make(chan int) 67 c3 := make(chan int) 68 c4 := make(chan int) 69 done := make(chan bool) 70 cmux := make(chan int) 71 go sender(*iterations, c1, c2, c3, c4) 72 go mux(cmux, c1, done) 73 go mux(cmux, c2, done) 74 go mux(cmux, c3, done) 75 go mux(cmux, c4, done) 76 go func() { 77 <-done 78 <-done 79 <-done 80 <-done 81 close(cmux) 82 }() 83 // We keep the recver because it might catch more bugs in the future. 84 // However, the result of the bug linked to at the top is that we'll 85 // end up panicking with: "throw: bad g->status in ready". 86 recver(cmux) 87} 88