modernc.org/gc@v1.0.1-0.20240304020402-f0dba7c97c2b/testdata/errchk/test/chan/doubleselect.go (about) 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 10 package main 11 12 import ( 13 "flag" 14 "runtime" 15 ) 16 17 var 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. 22 func 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. 41 func 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. 49 func 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 61 func 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 }