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