Source file
src/sync/waitgroup_test.go
1
2
3
4
5 package sync_test
6
7 import (
8 "bytes"
9 "internal/testenv"
10 "os"
11 "os/exec"
12 "strings"
13 . "sync"
14 "sync/atomic"
15 "testing"
16 )
17
18 func testWaitGroup(t *testing.T, wg1 *WaitGroup, wg2 *WaitGroup) {
19 n := 16
20 wg1.Add(n)
21 wg2.Add(n)
22 exited := make(chan bool, n)
23 for i := 0; i != n; i++ {
24 go func() {
25 wg1.Done()
26 wg2.Wait()
27 exited <- true
28 }()
29 }
30 wg1.Wait()
31 for i := 0; i != n; i++ {
32 select {
33 case <-exited:
34 t.Fatal("WaitGroup released group too soon")
35 default:
36 }
37 wg2.Done()
38 }
39 for i := 0; i != n; i++ {
40 <-exited
41 }
42 }
43
44 func TestWaitGroup(t *testing.T) {
45 wg1 := &WaitGroup{}
46 wg2 := &WaitGroup{}
47
48
49 for i := 0; i != 8; i++ {
50 testWaitGroup(t, wg1, wg2)
51 }
52 }
53
54 func TestWaitGroupMisuse(t *testing.T) {
55 defer func() {
56 err := recover()
57 if err != "sync: negative WaitGroup counter" {
58 t.Fatalf("Unexpected panic: %#v", err)
59 }
60 }()
61 wg := &WaitGroup{}
62 wg.Add(1)
63 wg.Done()
64 wg.Done()
65 t.Fatal("Should panic")
66 }
67
68 func TestWaitGroupRace(t *testing.T) {
69
70 for i := 0; i < 1000; i++ {
71 wg := &WaitGroup{}
72 n := new(int32)
73
74 wg.Add(1)
75 go func() {
76 atomic.AddInt32(n, 1)
77 wg.Done()
78 }()
79
80 wg.Add(1)
81 go func() {
82 atomic.AddInt32(n, 1)
83 wg.Done()
84 }()
85
86 wg.Wait()
87 if atomic.LoadInt32(n) != 2 {
88 t.Fatal("Spurious wakeup from Wait")
89 }
90 }
91 }
92
93 func TestWaitGroupAlign(t *testing.T) {
94 type X struct {
95 x byte
96 wg WaitGroup
97 }
98 var x X
99 x.wg.Add(1)
100 go func(x *X) {
101 x.wg.Done()
102 }(&x)
103 x.wg.Wait()
104 }
105
106 func TestWaitGroupGo(t *testing.T) {
107 wg := &WaitGroup{}
108 var i int
109 wg.Go(func() {
110 i++
111 })
112 wg.Wait()
113 if i != 1 {
114 t.Fatalf("got %d, want 1", i)
115 }
116 }
117
118
119
120 func TestIssue76126(t *testing.T) {
121 testenv.MustHaveExec(t)
122 if os.Getenv("SYNC_TEST_CHILD") != "1" {
123
124
125 cmd := exec.Command(os.Args[0], "-test.run=^TestIssue76126$")
126 cmd.Env = append(os.Environ(), "SYNC_TEST_CHILD=1")
127 buf := new(bytes.Buffer)
128 cmd.Stderr = buf
129 cmd.Run()
130 got := buf.String()
131 if !strings.Contains(got, "panic: test") {
132 t.Errorf("missing panic: test\n%s", got)
133 }
134 return
135 }
136 var wg WaitGroup
137 wg.Go(func() {
138 panic("test")
139 })
140 wg.Wait()
141 panic("Wait returned")
142 }
143
144 func BenchmarkWaitGroupUncontended(b *testing.B) {
145 type PaddedWaitGroup struct {
146 WaitGroup
147 pad [128]uint8
148 }
149 b.RunParallel(func(pb *testing.PB) {
150 var wg PaddedWaitGroup
151 for pb.Next() {
152 wg.Add(1)
153 wg.Done()
154 wg.Wait()
155 }
156 })
157 }
158
159 func benchmarkWaitGroupAddDone(b *testing.B, localWork int) {
160 var wg WaitGroup
161 b.RunParallel(func(pb *testing.PB) {
162 foo := 0
163 for pb.Next() {
164 wg.Add(1)
165 for i := 0; i < localWork; i++ {
166 foo *= 2
167 foo /= 2
168 }
169 wg.Done()
170 }
171 _ = foo
172 })
173 }
174
175 func BenchmarkWaitGroupAddDone(b *testing.B) {
176 benchmarkWaitGroupAddDone(b, 0)
177 }
178
179 func BenchmarkWaitGroupAddDoneWork(b *testing.B) {
180 benchmarkWaitGroupAddDone(b, 100)
181 }
182
183 func benchmarkWaitGroupWait(b *testing.B, localWork int) {
184 var wg WaitGroup
185 b.RunParallel(func(pb *testing.PB) {
186 foo := 0
187 for pb.Next() {
188 wg.Wait()
189 for i := 0; i < localWork; i++ {
190 foo *= 2
191 foo /= 2
192 }
193 }
194 _ = foo
195 })
196 }
197
198 func BenchmarkWaitGroupWait(b *testing.B) {
199 benchmarkWaitGroupWait(b, 0)
200 }
201
202 func BenchmarkWaitGroupWaitWork(b *testing.B) {
203 benchmarkWaitGroupWait(b, 100)
204 }
205
206 func BenchmarkWaitGroupActuallyWait(b *testing.B) {
207 b.ReportAllocs()
208 b.RunParallel(func(pb *testing.PB) {
209 for pb.Next() {
210 var wg WaitGroup
211 wg.Add(1)
212 go func() {
213 wg.Done()
214 }()
215 wg.Wait()
216 }
217 })
218 }
219
View as plain text