// Copyright 2012 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. package race_test import ( "runtime" "testing" ) func TestNoRaceSelect1(t *testing.T) { var x int _ = x compl := make(chan bool) c := make(chan bool) c1 := make(chan bool) go func() { x = 1 // At least two channels are needed because // otherwise the compiler optimizes select out. // See comment in runtime/select.go:^func selectgo. select { case c <- true: case c1 <- true: } compl <- true }() select { case <-c: case c1 <- true: } x = 2 <-compl } func TestNoRaceSelect2(t *testing.T) { var x int _ = x compl := make(chan bool) c := make(chan bool) c1 := make(chan bool) go func() { select { case <-c: case <-c1: } x = 1 compl <- true }() x = 2 close(c) runtime.Gosched() <-compl } func TestNoRaceSelect3(t *testing.T) { var x int _ = x compl := make(chan bool) c := make(chan bool, 10) c1 := make(chan bool) go func() { x = 1 select { case c <- true: case <-c1: } compl <- true }() <-c x = 2 <-compl } func TestNoRaceSelect4(t *testing.T) { type Task struct { f func() done chan bool } queue := make(chan Task) dummy := make(chan bool) go func() { for { select { case t := <-queue: t.f() t.done <- true } } }() doit := func(f func()) { done := make(chan bool, 1) select { case queue <- Task{f, done}: case <-dummy: } select { case <-done: case <-dummy: } } var x int doit(func() { x = 1 }) _ = x } func TestNoRaceSelect5(t *testing.T) { test := func(sel, needSched bool) { var x int _ = x ch := make(chan bool) c1 := make(chan bool) done := make(chan bool, 2) go func() { if needSched { runtime.Gosched() } // println(1) x = 1 if sel { select { case ch <- true: case <-c1: } } else { ch <- true } done <- true }() go func() { // println(2) if sel { select { case <-ch: case <-c1: } } else { <-ch } x = 1 done <- true }() <-done <-done } test(true, true) test(true, false) test(false, true) test(false, false) } func TestRaceSelect1(t *testing.T) { var x int _ = x compl := make(chan bool, 2) c := make(chan bool) c1 := make(chan bool) go func() { <-c <-c }() f := func() { select { case c <- true: case c1 <- true: } x = 1 compl <- true } go f() go f() <-compl <-compl } func TestRaceSelect2(t *testing.T) { var x int _ = x compl := make(chan bool) c := make(chan bool) c1 := make(chan bool) go func() { x = 1 select { case <-c: case <-c1: } compl <- true }() close(c) x = 2 <-compl } func TestRaceSelect3(t *testing.T) { var x int _ = x compl := make(chan bool) c := make(chan bool) c1 := make(chan bool) go func() { x = 1 select { case c <- true: case c1 <- true: } compl <- true }() x = 2 select { case <-c: } <-compl } func TestRaceSelect4(t *testing.T) { done := make(chan bool, 1) var x int go func() { select { default: x = 2 } done <- true }() _ = x <-done } // The idea behind this test: // there are two variables, access to one // of them is synchronized, access to the other // is not. // Select must (unconditionally) choose the non-synchronized variable // thus causing exactly one race. // Currently this test doesn't look like it accomplishes // this goal. func TestRaceSelect5(t *testing.T) { done := make(chan bool, 1) c1 := make(chan bool, 1) c2 := make(chan bool) var x, y int go func() { select { case c1 <- true: x = 1 case c2 <- true: y = 1 } done <- true }() _ = x _ = y <-done } // select statements may introduce // flakiness: whether this test contains // a race depends on the scheduling // (some may argue that the code contains // this race by definition) /* func TestFlakyDefault(t *testing.T) { var x int c := make(chan bool, 1) done := make(chan bool, 1) go func() { select { case <-c: x = 2 default: x = 3 } done <- true }() x = 1 c <- true _ = x <-done } */