| | |
| | |
| | |
| |
|
| | package sync_test |
| |
|
| | import ( |
| | "bytes" |
| | "internal/testenv" |
| | "os" |
| | "os/exec" |
| | "strings" |
| | . "sync" |
| | "sync/atomic" |
| | "testing" |
| | ) |
| |
|
| | func testWaitGroup(t *testing.T, wg1 *WaitGroup, wg2 *WaitGroup) { |
| | n := 16 |
| | wg1.Add(n) |
| | wg2.Add(n) |
| | exited := make(chan bool, n) |
| | for i := 0; i != n; i++ { |
| | go func() { |
| | wg1.Done() |
| | wg2.Wait() |
| | exited <- true |
| | }() |
| | } |
| | wg1.Wait() |
| | for i := 0; i != n; i++ { |
| | select { |
| | case <-exited: |
| | t.Fatal("WaitGroup released group too soon") |
| | default: |
| | } |
| | wg2.Done() |
| | } |
| | for i := 0; i != n; i++ { |
| | <-exited |
| | } |
| | } |
| |
|
| | func TestWaitGroup(t *testing.T) { |
| | wg1 := &WaitGroup{} |
| | wg2 := &WaitGroup{} |
| |
|
| | |
| | for i := 0; i != 8; i++ { |
| | testWaitGroup(t, wg1, wg2) |
| | } |
| | } |
| |
|
| | func TestWaitGroupMisuse(t *testing.T) { |
| | defer func() { |
| | err := recover() |
| | if err != "sync: negative WaitGroup counter" { |
| | t.Fatalf("Unexpected panic: %#v", err) |
| | } |
| | }() |
| | wg := &WaitGroup{} |
| | wg.Add(1) |
| | wg.Done() |
| | wg.Done() |
| | t.Fatal("Should panic") |
| | } |
| |
|
| | func TestWaitGroupRace(t *testing.T) { |
| | |
| | for i := 0; i < 1000; i++ { |
| | wg := &WaitGroup{} |
| | n := new(int32) |
| | |
| | wg.Add(1) |
| | go func() { |
| | atomic.AddInt32(n, 1) |
| | wg.Done() |
| | }() |
| | |
| | wg.Add(1) |
| | go func() { |
| | atomic.AddInt32(n, 1) |
| | wg.Done() |
| | }() |
| | |
| | wg.Wait() |
| | if atomic.LoadInt32(n) != 2 { |
| | t.Fatal("Spurious wakeup from Wait") |
| | } |
| | } |
| | } |
| |
|
| | func TestWaitGroupAlign(t *testing.T) { |
| | type X struct { |
| | x byte |
| | wg WaitGroup |
| | } |
| | var x X |
| | x.wg.Add(1) |
| | go func(x *X) { |
| | x.wg.Done() |
| | }(&x) |
| | x.wg.Wait() |
| | } |
| |
|
| | func TestWaitGroupGo(t *testing.T) { |
| | wg := &WaitGroup{} |
| | var i int |
| | wg.Go(func() { |
| | i++ |
| | }) |
| | wg.Wait() |
| | if i != 1 { |
| | t.Fatalf("got %d, want 1", i) |
| | } |
| | } |
| |
|
| | |
| | |
| | func TestIssue76126(t *testing.T) { |
| | testenv.MustHaveExec(t) |
| | if os.Getenv("SYNC_TEST_CHILD") != "1" { |
| | |
| | |
| | cmd := exec.Command(os.Args[0], "-test.run=^TestIssue76126$") |
| | cmd.Env = append(os.Environ(), "SYNC_TEST_CHILD=1") |
| | buf := new(bytes.Buffer) |
| | cmd.Stderr = buf |
| | cmd.Run() |
| | got := buf.String() |
| | if !strings.Contains(got, "panic: test") { |
| | t.Errorf("missing panic: test\n%s", got) |
| | } |
| | return |
| | } |
| | var wg WaitGroup |
| | wg.Go(func() { |
| | panic("test") |
| | }) |
| | wg.Wait() |
| | panic("Wait returned") |
| | } |
| |
|
| | func BenchmarkWaitGroupUncontended(b *testing.B) { |
| | type PaddedWaitGroup struct { |
| | WaitGroup |
| | pad [128]uint8 |
| | } |
| | b.RunParallel(func(pb *testing.PB) { |
| | var wg PaddedWaitGroup |
| | for pb.Next() { |
| | wg.Add(1) |
| | wg.Done() |
| | wg.Wait() |
| | } |
| | }) |
| | } |
| |
|
| | func benchmarkWaitGroupAddDone(b *testing.B, localWork int) { |
| | var wg WaitGroup |
| | b.RunParallel(func(pb *testing.PB) { |
| | foo := 0 |
| | for pb.Next() { |
| | wg.Add(1) |
| | for i := 0; i < localWork; i++ { |
| | foo *= 2 |
| | foo /= 2 |
| | } |
| | wg.Done() |
| | } |
| | _ = foo |
| | }) |
| | } |
| |
|
| | func BenchmarkWaitGroupAddDone(b *testing.B) { |
| | benchmarkWaitGroupAddDone(b, 0) |
| | } |
| |
|
| | func BenchmarkWaitGroupAddDoneWork(b *testing.B) { |
| | benchmarkWaitGroupAddDone(b, 100) |
| | } |
| |
|
| | func benchmarkWaitGroupWait(b *testing.B, localWork int) { |
| | var wg WaitGroup |
| | b.RunParallel(func(pb *testing.PB) { |
| | foo := 0 |
| | for pb.Next() { |
| | wg.Wait() |
| | for i := 0; i < localWork; i++ { |
| | foo *= 2 |
| | foo /= 2 |
| | } |
| | } |
| | _ = foo |
| | }) |
| | } |
| |
|
| | func BenchmarkWaitGroupWait(b *testing.B) { |
| | benchmarkWaitGroupWait(b, 0) |
| | } |
| |
|
| | func BenchmarkWaitGroupWaitWork(b *testing.B) { |
| | benchmarkWaitGroupWait(b, 100) |
| | } |
| |
|
| | func BenchmarkWaitGroupActuallyWait(b *testing.B) { |
| | b.ReportAllocs() |
| | b.RunParallel(func(pb *testing.PB) { |
| | for pb.Next() { |
| | var wg WaitGroup |
| | wg.Add(1) |
| | go func() { |
| | wg.Done() |
| | }() |
| | wg.Wait() |
| | } |
| | }) |
| | } |
| |
|