diff options
Diffstat (limited to 'src/pkg/runtime/race/testdata/waitgroup_test.go')
-rw-r--r-- | src/pkg/runtime/race/testdata/waitgroup_test.go | 128 |
1 files changed, 124 insertions, 4 deletions
diff --git a/src/pkg/runtime/race/testdata/waitgroup_test.go b/src/pkg/runtime/race/testdata/waitgroup_test.go index 7ea21fa7e..ff152b0ab 100644 --- a/src/pkg/runtime/race/testdata/waitgroup_test.go +++ b/src/pkg/runtime/race/testdata/waitgroup_test.go @@ -102,22 +102,22 @@ func TestRaceWaitGroupWrongWait(t *testing.T) { <-c } -// A common WaitGroup misuse that can potentially be caught be the race detector. -// For this simple case we must emulate Add() as read on &wg and Wait() as write on &wg. -// However it will have false positives if there are several concurrent Wait() calls. -func TestRaceFailingWaitGroupWrongAdd(t *testing.T) { +func TestRaceWaitGroupWrongAdd(t *testing.T) { c := make(chan bool, 2) var wg sync.WaitGroup go func() { wg.Add(1) + time.Sleep(100 * time.Millisecond) wg.Done() c <- true }() go func() { wg.Add(1) + time.Sleep(100 * time.Millisecond) wg.Done() c <- true }() + time.Sleep(50 * time.Millisecond) wg.Wait() <-c <-c @@ -158,6 +158,32 @@ func TestNoRaceWaitGroupMultipleWait2(t *testing.T) { <-c } +func TestNoRaceWaitGroupMultipleWait3(t *testing.T) { + const P = 3 + var data [P]int + done := make(chan bool, P) + var wg sync.WaitGroup + wg.Add(P) + for p := 0; p < P; p++ { + go func(p int) { + data[p] = 42 + wg.Done() + }(p) + } + for p := 0; p < P; p++ { + go func() { + wg.Wait() + for p1 := 0; p1 < P; p1++ { + _ = data[p1] + } + done <- true + }() + } + for p := 0; p < P; p++ { + <-done + } +} + // Correct usage but still a race func TestRaceWaitGroup2(t *testing.T) { var x int @@ -230,3 +256,97 @@ func TestNoRaceWaitGroupTransitive(t *testing.T) { _ = x _ = y } + +func TestNoRaceWaitGroupReuse(t *testing.T) { + const P = 3 + var data [P]int + var wg sync.WaitGroup + for try := 0; try < 3; try++ { + wg.Add(P) + for p := 0; p < P; p++ { + go func(p int) { + data[p]++ + wg.Done() + }(p) + } + wg.Wait() + for p := 0; p < P; p++ { + data[p]++ + } + } +} + +func TestNoRaceWaitGroupReuse2(t *testing.T) { + const P = 3 + var data [P]int + var wg sync.WaitGroup + for try := 0; try < 3; try++ { + wg.Add(P) + for p := 0; p < P; p++ { + go func(p int) { + data[p]++ + wg.Done() + }(p) + } + done := make(chan bool) + go func() { + wg.Wait() + for p := 0; p < P; p++ { + data[p]++ + } + done <- true + }() + wg.Wait() + <-done + for p := 0; p < P; p++ { + data[p]++ + } + } +} + +func TestRaceWaitGroupReuse(t *testing.T) { + const P = 3 + const T = 3 + done := make(chan bool, T) + var wg sync.WaitGroup + for try := 0; try < T; try++ { + var data [P]int + wg.Add(P) + for p := 0; p < P; p++ { + go func(p int) { + time.Sleep(50 * time.Millisecond) + data[p]++ + wg.Done() + }(p) + } + go func() { + wg.Wait() + for p := 0; p < P; p++ { + data[p]++ + } + done <- true + }() + time.Sleep(100 * time.Millisecond) + wg.Wait() + } + for try := 0; try < T; try++ { + <-done + } +} + +func TestNoRaceWaitGroupConcurrentAdd(t *testing.T) { + const P = 4 + waiting := make(chan bool, P) + var wg sync.WaitGroup + for p := 0; p < P; p++ { + go func() { + wg.Add(1) + waiting <- true + wg.Done() + }() + } + for p := 0; p < P; p++ { + <-waiting + } + wg.Wait() +} |