blob: cddd9a6e782f2a2e5d0aded50f9032225baf7eef [file] [log] [blame]
// Copyright 2011 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"
"time"
)
func TestNoRaceChanSync(t *testing.T) {
v := 0
c := make(chan int)
go func() {
v = 1
c <- 0
}()
<-c
v = 2
}
func TestNoRaceChanSyncRev(t *testing.T) {
v := 0
c := make(chan int)
go func() {
c <- 0
v = 2
}()
v = 1
<-c
}
func TestNoRaceChanAsync(t *testing.T) {
v := 0
c := make(chan int, 10)
go func() {
v = 1
c <- 0
}()
<-c
v = 2
}
func TestRaceChanAsyncRev(t *testing.T) {
v := 0
c := make(chan int, 10)
go func() {
c <- 0
v = 1
}()
v = 2
<-c
}
func TestNoRaceChanAsyncCloseRecv(t *testing.T) {
v := 0
c := make(chan int, 10)
go func() {
v = 1
close(c)
}()
func() {
defer func() {
recover()
v = 2
}()
<-c
}()
}
func TestNoRaceChanAsyncCloseRecv2(t *testing.T) {
v := 0
c := make(chan int, 10)
go func() {
v = 1
close(c)
}()
_, _ = <-c
v = 2
}
func TestNoRaceChanAsyncCloseRecv3(t *testing.T) {
v := 0
c := make(chan int, 10)
go func() {
v = 1
close(c)
}()
for range c {
}
v = 2
}
func TestNoRaceChanSyncCloseRecv(t *testing.T) {
v := 0
c := make(chan int)
go func() {
v = 1
close(c)
}()
func() {
defer func() {
recover()
v = 2
}()
<-c
}()
}
func TestNoRaceChanSyncCloseRecv2(t *testing.T) {
v := 0
c := make(chan int)
go func() {
v = 1
close(c)
}()
_, _ = <-c
v = 2
}
func TestNoRaceChanSyncCloseRecv3(t *testing.T) {
v := 0
c := make(chan int)
go func() {
v = 1
close(c)
}()
for range c {
}
v = 2
}
func TestRaceChanSyncCloseSend(t *testing.T) {
v := 0
c := make(chan int)
go func() {
v = 1
close(c)
}()
func() {
defer func() {
recover()
}()
c <- 0
}()
v = 2
}
func TestRaceChanAsyncCloseSend(t *testing.T) {
v := 0
c := make(chan int, 10)
go func() {
v = 1
close(c)
}()
func() {
defer func() {
recover()
}()
for {
c <- 0
}
}()
v = 2
}
func TestRaceChanCloseClose(t *testing.T) {
compl := make(chan bool, 2)
v1 := 0
v2 := 0
c := make(chan int)
go func() {
defer func() {
if recover() != nil {
v2 = 2
}
compl <- true
}()
v1 = 1
close(c)
}()
go func() {
defer func() {
if recover() != nil {
v1 = 2
}
compl <- true
}()
v2 = 1
close(c)
}()
<-compl
<-compl
}
func TestRaceChanSendLen(t *testing.T) {
v := 0
c := make(chan int, 10)
go func() {
v = 1
c <- 1
}()
for len(c) == 0 {
runtime.Gosched()
}
v = 2
}
func TestRaceChanRecvLen(t *testing.T) {
v := 0
c := make(chan int, 10)
c <- 1
go func() {
v = 1
<-c
}()
for len(c) != 0 {
runtime.Gosched()
}
v = 2
}
func TestRaceChanSendSend(t *testing.T) {
compl := make(chan bool, 2)
v1 := 0
v2 := 0
c := make(chan int, 1)
go func() {
v1 = 1
select {
case c <- 1:
default:
v2 = 2
}
compl <- true
}()
go func() {
v2 = 1
select {
case c <- 1:
default:
v1 = 2
}
compl <- true
}()
<-compl
<-compl
}
func TestNoRaceChanPtr(t *testing.T) {
type msg struct {
x int
}
c := make(chan *msg)
go func() {
c <- &msg{1}
}()
m := <-c
m.x = 2
}
func TestRaceChanWrongSend(t *testing.T) {
v1 := 0
v2 := 0
c := make(chan int, 2)
go func() {
v1 = 1
c <- 1
}()
go func() {
v2 = 2
c <- 2
}()
time.Sleep(1e7)
if <-c == 1 {
v2 = 3
} else {
v1 = 3
}
}
func TestRaceChanWrongClose(t *testing.T) {
v1 := 0
v2 := 0
c := make(chan int, 1)
go func() {
defer func() {
recover()
}()
v1 = 1
c <- 1
}()
go func() {
time.Sleep(1e7)
v2 = 2
close(c)
}()
time.Sleep(2e7)
if _, who := <-c; who {
v2 = 2
} else {
v1 = 2
}
}
func TestRaceChanSendClose(t *testing.T) {
compl := make(chan bool, 2)
c := make(chan int, 1)
go func() {
defer func() {
recover()
compl <- true
}()
c <- 1
}()
go func() {
time.Sleep(10 * time.Millisecond)
close(c)
compl <- true
}()
<-compl
<-compl
}
func TestRaceChanSendSelectClose(t *testing.T) {
compl := make(chan bool, 2)
c := make(chan int, 1)
c1 := make(chan int)
go func() {
defer func() {
recover()
compl <- true
}()
time.Sleep(10 * time.Millisecond)
select {
case c <- 1:
case <-c1:
}
}()
go func() {
close(c)
compl <- true
}()
<-compl
<-compl
}
func TestRaceSelectReadWriteAsync(t *testing.T) {
done := make(chan bool)
x := 0
c1 := make(chan int, 10)
c2 := make(chan int, 10)
c3 := make(chan int)
c2 <- 1
go func() {
select {
case c1 <- x: // read of x races with...
case c3 <- 1:
}
done <- true
}()
select {
case x = <-c2: // ... write to x here
case c3 <- 1:
}
<-done
}
func TestRaceSelectReadWriteSync(t *testing.T) {
done := make(chan bool)
x := 0
c1 := make(chan int)
c2 := make(chan int)
c3 := make(chan int)
// make c1 and c2 ready for communication
go func() {
<-c1
}()
go func() {
c2 <- 1
}()
go func() {
select {
case c1 <- x: // read of x races with...
case c3 <- 1:
}
done <- true
}()
select {
case x = <-c2: // ... write to x here
case c3 <- 1:
}
<-done
}
func TestNoRaceSelectReadWriteAsync(t *testing.T) {
done := make(chan bool)
x := 0
c1 := make(chan int)
c2 := make(chan int)
go func() {
select {
case c1 <- x: // read of x does not race with...
case c2 <- 1:
}
done <- true
}()
select {
case x = <-c1: // ... write to x here
case c2 <- 1:
}
<-done
}
func TestRaceChanReadWriteAsync(t *testing.T) {
done := make(chan bool)
c1 := make(chan int, 10)
c2 := make(chan int, 10)
c2 <- 10
x := 0
go func() {
c1 <- x // read of x races with...
done <- true
}()
x = <-c2 // ... write to x here
<-done
}
func TestRaceChanReadWriteSync(t *testing.T) {
done := make(chan bool)
c1 := make(chan int)
c2 := make(chan int)
// make c1 and c2 ready for communication
go func() {
<-c1
}()
go func() {
c2 <- 10
}()
x := 0
go func() {
c1 <- x // read of x races with...
done <- true
}()
x = <-c2 // ... write to x here
<-done
}
func TestNoRaceChanReadWriteAsync(t *testing.T) {
done := make(chan bool)
c1 := make(chan int, 10)
x := 0
go func() {
c1 <- x // read of x does not race with...
done <- true
}()
x = <-c1 // ... write to x here
<-done
}
func TestNoRaceProducerConsumerUnbuffered(t *testing.T) {
type Task struct {
f func()
done chan bool
}
queue := make(chan Task)
go func() {
t := <-queue
t.f()
t.done <- true
}()
doit := func(f func()) {
done := make(chan bool, 1)
queue <- Task{f, done}
<-done
}
x := 0
doit(func() {
x = 1
})
_ = x
}
func TestRaceChanItselfSend(t *testing.T) {
compl := make(chan bool, 1)
c := make(chan int, 10)
go func() {
c <- 0
compl <- true
}()
c = make(chan int, 20)
<-compl
}
func TestRaceChanItselfRecv(t *testing.T) {
compl := make(chan bool, 1)
c := make(chan int, 10)
c <- 1
go func() {
<-c
compl <- true
}()
time.Sleep(1e7)
c = make(chan int, 20)
<-compl
}
func TestRaceChanItselfNil(t *testing.T) {
c := make(chan int, 10)
go func() {
c <- 0
}()
time.Sleep(1e7)
c = nil
_ = c
}
func TestRaceChanItselfClose(t *testing.T) {
compl := make(chan bool, 1)
c := make(chan int)
go func() {
close(c)
compl <- true
}()
c = make(chan int)
<-compl
}
func TestRaceChanItselfLen(t *testing.T) {
compl := make(chan bool, 1)
c := make(chan int)
go func() {
_ = len(c)
compl <- true
}()
c = make(chan int)
<-compl
}
func TestRaceChanItselfCap(t *testing.T) {
compl := make(chan bool, 1)
c := make(chan int)
go func() {
_ = cap(c)
compl <- true
}()
c = make(chan int)
<-compl
}
func TestRaceChanCloseLen(t *testing.T) {
v := 0
c := make(chan int, 10)
c <- 0
go func() {
v = 1
close(c)
}()
time.Sleep(1e7)
_ = len(c)
v = 2
}
func TestRaceChanCloseSend(t *testing.T) {
compl := make(chan bool, 1)
c := make(chan int, 10)
go func() {
close(c)
compl <- true
}()
c <- 0
<-compl
}
func TestNoRaceChanMutex(t *testing.T) {
done := make(chan struct{})
mtx := make(chan struct{}, 1)
data := 0
go func() {
mtx <- struct{}{}
data = 42
<-mtx
done <- struct{}{}
}()
mtx <- struct{}{}
data = 43
<-mtx
<-done
}
func TestNoRaceSelectMutex(t *testing.T) {
done := make(chan struct{})
mtx := make(chan struct{}, 1)
aux := make(chan bool)
data := 0
go func() {
select {
case mtx <- struct{}{}:
case <-aux:
}
data = 42
select {
case <-mtx:
case <-aux:
}
done <- struct{}{}
}()
select {
case mtx <- struct{}{}:
case <-aux:
}
data = 43
select {
case <-mtx:
case <-aux:
}
<-done
}
func TestRaceChanSem(t *testing.T) {
done := make(chan struct{})
mtx := make(chan bool, 2)
data := 0
go func() {
mtx <- true
data = 42
<-mtx
done <- struct{}{}
}()
mtx <- true
data = 43
<-mtx
<-done
}
func TestNoRaceChanWaitGroup(t *testing.T) {
const N = 10
chanWg := make(chan bool, N/2)
data := make([]int, N)
for i := 0; i < N; i++ {
chanWg <- true
go func(i int) {
data[i] = 42
<-chanWg
}(i)
}
for i := 0; i < cap(chanWg); i++ {
chanWg <- true
}
for i := 0; i < N; i++ {
_ = data[i]
}
}
// Test that sender synchronizes with receiver even if the sender was blocked.
func TestNoRaceBlockedSendSync(t *testing.T) {
c := make(chan *int, 1)
c <- nil
go func() {
i := 42
c <- &i
}()
// Give the sender time to actually block.
// This sleep is completely optional: race report must not be printed
// regardless of whether the sender actually blocks or not.
// It cannot lead to flakiness.
time.Sleep(10 * time.Millisecond)
<-c
p := <-c
if *p != 42 {
t.Fatal()
}
}
// The same as TestNoRaceBlockedSendSync above, but sender unblock happens in a select.
func TestNoRaceBlockedSelectSendSync(t *testing.T) {
c := make(chan *int, 1)
c <- nil
go func() {
i := 42
c <- &i
}()
time.Sleep(10 * time.Millisecond)
<-c
select {
case p := <-c:
if *p != 42 {
t.Fatal()
}
case <-make(chan int):
}
}