|
|
1072a9 |
diff --git a/src/sync/waitgroup_test.go b/src/sync/waitgroup_test.go
|
|
|
1072a9 |
index c569e0faa2eb..4ded218d2d8d 100644
|
|
|
1072a9 |
--- a/src/sync/waitgroup_test.go
|
|
|
1072a9 |
+++ b/src/sync/waitgroup_test.go
|
|
|
1072a9 |
@@ -5,8 +5,6 @@
|
|
|
1072a9 |
package sync_test
|
|
|
1072a9 |
|
|
|
1072a9 |
import (
|
|
|
1072a9 |
- "internal/race"
|
|
|
1072a9 |
- "runtime"
|
|
|
1072a9 |
. "sync"
|
|
|
1072a9 |
"sync/atomic"
|
|
|
1072a9 |
"testing"
|
|
|
1072a9 |
@@ -48,12 +46,6 @@ func TestWaitGroup(t *testing.T) {
|
|
|
1072a9 |
}
|
|
|
1072a9 |
}
|
|
|
1072a9 |
|
|
|
1072a9 |
-func knownRacy(t *testing.T) {
|
|
|
1072a9 |
- if race.Enabled {
|
|
|
1072a9 |
- t.Skip("skipping known-racy test under the race detector")
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
-}
|
|
|
1072a9 |
-
|
|
|
1072a9 |
func TestWaitGroupMisuse(t *testing.T) {
|
|
|
1072a9 |
defer func() {
|
|
|
1072a9 |
err := recover()
|
|
|
1072a9 |
@@ -68,124 +60,6 @@ func TestWaitGroupMisuse(t *testing.T) {
|
|
|
1072a9 |
t.Fatal("Should panic")
|
|
|
1072a9 |
}
|
|
|
1072a9 |
|
|
|
1072a9 |
-// pollUntilEqual blocks until v, loaded atomically, is
|
|
|
1072a9 |
-// equal to the target.
|
|
|
1072a9 |
-func pollUntilEqual(v *uint32, target uint32) {
|
|
|
1072a9 |
- for {
|
|
|
1072a9 |
- for i := 0; i < 1e3; i++ {
|
|
|
1072a9 |
- if atomic.LoadUint32(v) == target {
|
|
|
1072a9 |
- return
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
- // yield to avoid deadlock with the garbage collector
|
|
|
1072a9 |
- // see issue #20072
|
|
|
1072a9 |
- runtime.Gosched()
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
-}
|
|
|
1072a9 |
-
|
|
|
1072a9 |
-func TestWaitGroupMisuse2(t *testing.T) {
|
|
|
1072a9 |
- knownRacy(t)
|
|
|
1072a9 |
- if runtime.NumCPU() <= 4 {
|
|
|
1072a9 |
- t.Skip("NumCPU<=4, skipping: this test requires parallelism")
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
- defer func() {
|
|
|
1072a9 |
- err := recover()
|
|
|
1072a9 |
- if err != "sync: negative WaitGroup counter" &&
|
|
|
1072a9 |
- err != "sync: WaitGroup misuse: Add called concurrently with Wait" &&
|
|
|
1072a9 |
- err != "sync: WaitGroup is reused before previous Wait has returned" {
|
|
|
1072a9 |
- t.Fatalf("Unexpected panic: %#v", err)
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
- }()
|
|
|
1072a9 |
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
|
|
|
1072a9 |
- done := make(chan interface{}, 2)
|
|
|
1072a9 |
- // The detection is opportunistic, so we want it to panic
|
|
|
1072a9 |
- // at least in one run out of a million.
|
|
|
1072a9 |
- for i := 0; i < 1e6; i++ {
|
|
|
1072a9 |
- var wg WaitGroup
|
|
|
1072a9 |
- var here uint32
|
|
|
1072a9 |
- wg.Add(1)
|
|
|
1072a9 |
- go func() {
|
|
|
1072a9 |
- defer func() {
|
|
|
1072a9 |
- done <- recover()
|
|
|
1072a9 |
- }()
|
|
|
1072a9 |
- atomic.AddUint32(&here, 1)
|
|
|
1072a9 |
- pollUntilEqual(&here, 3)
|
|
|
1072a9 |
- wg.Wait()
|
|
|
1072a9 |
- }()
|
|
|
1072a9 |
- go func() {
|
|
|
1072a9 |
- defer func() {
|
|
|
1072a9 |
- done <- recover()
|
|
|
1072a9 |
- }()
|
|
|
1072a9 |
- atomic.AddUint32(&here, 1)
|
|
|
1072a9 |
- pollUntilEqual(&here, 3)
|
|
|
1072a9 |
- wg.Add(1) // This is the bad guy.
|
|
|
1072a9 |
- wg.Done()
|
|
|
1072a9 |
- }()
|
|
|
1072a9 |
- atomic.AddUint32(&here, 1)
|
|
|
1072a9 |
- pollUntilEqual(&here, 3)
|
|
|
1072a9 |
- wg.Done()
|
|
|
1072a9 |
- for j := 0; j < 2; j++ {
|
|
|
1072a9 |
- if err := <-done; err != nil {
|
|
|
1072a9 |
- panic(err)
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
- t.Fatal("Should panic")
|
|
|
1072a9 |
-}
|
|
|
1072a9 |
-
|
|
|
1072a9 |
-func TestWaitGroupMisuse3(t *testing.T) {
|
|
|
1072a9 |
- knownRacy(t)
|
|
|
1072a9 |
- if runtime.NumCPU() <= 1 {
|
|
|
1072a9 |
- t.Skip("NumCPU==1, skipping: this test requires parallelism")
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
- defer func() {
|
|
|
1072a9 |
- err := recover()
|
|
|
1072a9 |
- if err != "sync: negative WaitGroup counter" &&
|
|
|
1072a9 |
- err != "sync: WaitGroup misuse: Add called concurrently with Wait" &&
|
|
|
1072a9 |
- err != "sync: WaitGroup is reused before previous Wait has returned" {
|
|
|
1072a9 |
- t.Fatalf("Unexpected panic: %#v", err)
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
- }()
|
|
|
1072a9 |
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
|
|
|
1072a9 |
- done := make(chan interface{}, 3)
|
|
|
1072a9 |
- // The detection is opportunistically, so we want it to panic
|
|
|
1072a9 |
- // at least in one run out of a million.
|
|
|
1072a9 |
- for i := 0; i < 1e6; i++ {
|
|
|
1072a9 |
- var wg WaitGroup
|
|
|
1072a9 |
- wg.Add(1)
|
|
|
1072a9 |
- go func() {
|
|
|
1072a9 |
- defer func() {
|
|
|
1072a9 |
- done <- recover()
|
|
|
1072a9 |
- }()
|
|
|
1072a9 |
- wg.Done()
|
|
|
1072a9 |
- }()
|
|
|
1072a9 |
- go func() {
|
|
|
1072a9 |
- defer func() {
|
|
|
1072a9 |
- done <- recover()
|
|
|
1072a9 |
- }()
|
|
|
1072a9 |
- wg.Wait()
|
|
|
1072a9 |
- // Start reusing the wg before waiting for the Wait below to return.
|
|
|
1072a9 |
- wg.Add(1)
|
|
|
1072a9 |
- go func() {
|
|
|
1072a9 |
- wg.Done()
|
|
|
1072a9 |
- }()
|
|
|
1072a9 |
- wg.Wait()
|
|
|
1072a9 |
- }()
|
|
|
1072a9 |
- go func() {
|
|
|
1072a9 |
- defer func() {
|
|
|
1072a9 |
- done <- recover()
|
|
|
1072a9 |
- }()
|
|
|
1072a9 |
- wg.Wait()
|
|
|
1072a9 |
- }()
|
|
|
1072a9 |
- for j := 0; j < 3; j++ {
|
|
|
1072a9 |
- if err := <-done; err != nil {
|
|
|
1072a9 |
- panic(err)
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
- }
|
|
|
1072a9 |
- t.Fatal("Should panic")
|
|
|
1072a9 |
-}
|
|
|
1072a9 |
-
|
|
|
1072a9 |
func TestWaitGroupRace(t *testing.T) {
|
|
|
1072a9 |
// Run this test for about 1ms.
|
|
|
1072a9 |
for i := 0; i < 1000; i++ {
|