1// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package sync_test
6
7import (
8	"internal/race"
9	"runtime"
10	. "sync"
11	"sync/atomic"
12	"testing"
13)
14
15func testWaitGroup(t *testing.T, wg1 *WaitGroup, wg2 *WaitGroup) {
16	n := 16
17	wg1.Add(n)
18	wg2.Add(n)
19	exited := make(chan bool, n)
20	for i := 0; i != n; i++ {
21		go func(i int) {
22			wg1.Done()
23			wg2.Wait()
24			exited <- true
25		}(i)
26	}
27	wg1.Wait()
28	for i := 0; i != n; i++ {
29		select {
30		case <-exited:
31			t.Fatal("WaitGroup released group too soon")
32		default:
33		}
34		wg2.Done()
35	}
36	for i := 0; i != n; i++ {
37		<-exited // Will block if barrier fails to unlock someone.
38	}
39}
40
41func TestWaitGroup(t *testing.T) {
42	wg1 := &WaitGroup{}
43	wg2 := &WaitGroup{}
44
45	// Run the same test a few times to ensure barrier is in a proper state.
46	for i := 0; i != 8; i++ {
47		testWaitGroup(t, wg1, wg2)
48	}
49}
50
51func knownRacy(t *testing.T) {
52	if race.Enabled {
53		t.Skip("skipping known-racy test under the race detector")
54	}
55}
56
57func TestWaitGroupMisuse(t *testing.T) {
58	defer func() {
59		err := recover()
60		if err != "sync: negative WaitGroup counter" {
61			t.Fatalf("Unexpected panic: %#v", err)
62		}
63	}()
64	wg := &WaitGroup{}
65	wg.Add(1)
66	wg.Done()
67	wg.Done()
68	t.Fatal("Should panic")
69}
70
71func TestWaitGroupMisuse2(t *testing.T) {
72	knownRacy(t)
73	if testing.Short() {
74		t.Skip("skipping flaky test in short mode; see issue 11443")
75	}
76	if runtime.NumCPU() <= 2 {
77		t.Skip("NumCPU<=2, skipping: this test requires parallelism")
78	}
79	defer func() {
80		err := recover()
81		if err != "sync: negative WaitGroup counter" &&
82			err != "sync: WaitGroup misuse: Add called concurrently with Wait" &&
83			err != "sync: WaitGroup is reused before previous Wait has returned" {
84			t.Fatalf("Unexpected panic: %#v", err)
85		}
86	}()
87	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
88	done := make(chan interface{}, 2)
89	// The detection is opportunistically, so we want it to panic
90	// at least in one run out of a million.
91	for i := 0; i < 1e6; i++ {
92		var wg WaitGroup
93		wg.Add(1)
94		go func() {
95			defer func() {
96				done <- recover()
97			}()
98			wg.Wait()
99		}()
100		go func() {
101			defer func() {
102				done <- recover()
103			}()
104			wg.Add(1) // This is the bad guy.
105			wg.Done()
106		}()
107		wg.Done()
108		for j := 0; j < 2; j++ {
109			if err := <-done; err != nil {
110				panic(err)
111			}
112		}
113	}
114	t.Fatal("Should panic")
115}
116
117func TestWaitGroupMisuse3(t *testing.T) {
118	knownRacy(t)
119	if runtime.NumCPU() <= 1 {
120		t.Skip("NumCPU==1, skipping: this test requires parallelism")
121	}
122	defer func() {
123		err := recover()
124		if err != "sync: negative WaitGroup counter" &&
125			err != "sync: WaitGroup misuse: Add called concurrently with Wait" &&
126			err != "sync: WaitGroup is reused before previous Wait has returned" {
127			t.Fatalf("Unexpected panic: %#v", err)
128		}
129	}()
130	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
131	done := make(chan interface{}, 2)
132	// The detection is opportunistically, so we want it to panic
133	// at least in one run out of a million.
134	for i := 0; i < 1e6; i++ {
135		var wg WaitGroup
136		wg.Add(1)
137		go func() {
138			defer func() {
139				done <- recover()
140			}()
141			wg.Done()
142		}()
143		go func() {
144			defer func() {
145				done <- recover()
146			}()
147			wg.Wait()
148			// Start reusing the wg before waiting for the Wait below to return.
149			wg.Add(1)
150			go func() {
151				wg.Done()
152			}()
153			wg.Wait()
154		}()
155		wg.Wait()
156		for j := 0; j < 2; j++ {
157			if err := <-done; err != nil {
158				panic(err)
159			}
160		}
161	}
162	t.Fatal("Should panic")
163}
164
165func TestWaitGroupRace(t *testing.T) {
166	// Run this test for about 1ms.
167	for i := 0; i < 1000; i++ {
168		wg := &WaitGroup{}
169		n := new(int32)
170		// spawn goroutine 1
171		wg.Add(1)
172		go func() {
173			atomic.AddInt32(n, 1)
174			wg.Done()
175		}()
176		// spawn goroutine 2
177		wg.Add(1)
178		go func() {
179			atomic.AddInt32(n, 1)
180			wg.Done()
181		}()
182		// Wait for goroutine 1 and 2
183		wg.Wait()
184		if atomic.LoadInt32(n) != 2 {
185			t.Fatal("Spurious wakeup from Wait")
186		}
187	}
188}
189
190func TestWaitGroupAlign(t *testing.T) {
191	type X struct {
192		x  byte
193		wg WaitGroup
194	}
195	var x X
196	x.wg.Add(1)
197	go func(x *X) {
198		x.wg.Done()
199	}(&x)
200	x.wg.Wait()
201}
202
203func BenchmarkWaitGroupUncontended(b *testing.B) {
204	type PaddedWaitGroup struct {
205		WaitGroup
206		pad [128]uint8
207	}
208	b.RunParallel(func(pb *testing.PB) {
209		var wg PaddedWaitGroup
210		for pb.Next() {
211			wg.Add(1)
212			wg.Done()
213			wg.Wait()
214		}
215	})
216}
217
218func benchmarkWaitGroupAddDone(b *testing.B, localWork int) {
219	var wg WaitGroup
220	b.RunParallel(func(pb *testing.PB) {
221		foo := 0
222		for pb.Next() {
223			wg.Add(1)
224			for i := 0; i < localWork; i++ {
225				foo *= 2
226				foo /= 2
227			}
228			wg.Done()
229		}
230		_ = foo
231	})
232}
233
234func BenchmarkWaitGroupAddDone(b *testing.B) {
235	benchmarkWaitGroupAddDone(b, 0)
236}
237
238func BenchmarkWaitGroupAddDoneWork(b *testing.B) {
239	benchmarkWaitGroupAddDone(b, 100)
240}
241
242func benchmarkWaitGroupWait(b *testing.B, localWork int) {
243	var wg WaitGroup
244	b.RunParallel(func(pb *testing.PB) {
245		foo := 0
246		for pb.Next() {
247			wg.Wait()
248			for i := 0; i < localWork; i++ {
249				foo *= 2
250				foo /= 2
251			}
252		}
253		_ = foo
254	})
255}
256
257func BenchmarkWaitGroupWait(b *testing.B) {
258	benchmarkWaitGroupWait(b, 0)
259}
260
261func BenchmarkWaitGroupWaitWork(b *testing.B) {
262	benchmarkWaitGroupWait(b, 100)
263}
264
265func BenchmarkWaitGroupActuallyWait(b *testing.B) {
266	b.ReportAllocs()
267	b.RunParallel(func(pb *testing.PB) {
268		for pb.Next() {
269			var wg WaitGroup
270			wg.Add(1)
271			go func() {
272				wg.Done()
273			}()
274			wg.Wait()
275		}
276	})
277}
278