// 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 selectgoImpl.
|
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
|
}
|
*/
|