blob: 9969f47e8e7223895350bf25eaf4f4d0fbe6cf87 [file] [log] [blame]
// 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
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
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
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
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
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
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
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
}
*/