Home | History | Annotate | Download | only in chan
      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 }
     88