1 package conc
2 3 import (
4 "sync"
5 6 "github.com/sourcegraph/conc/panics"
7 )
8 9 // NewWaitGroup creates a new WaitGroup.
10 func NewWaitGroup() *WaitGroup {
11 return &WaitGroup{}
12 }
13 14 // WaitGroup is the primary building block for scoped concurrency.
15 // Goroutines can be spawned in the WaitGroup with the Go method,
16 // and calling Wait() will ensure that each of those goroutines exits
17 // before continuing. Any panics in a child goroutine will be caught
18 // and propagated to the caller of Wait().
19 //
20 // The zero value of WaitGroup is usable, just like sync.WaitGroup.
21 // Also like sync.WaitGroup, it must not be copied after first use.
22 type WaitGroup struct {
23 wg sync.WaitGroup
24 pc panics.Catcher
25 }
26 27 // Go spawns a new goroutine in the WaitGroup.
28 func (h *WaitGroup) Go(f func()) {
29 h.wg.Add(1)
30 go func() {
31 defer h.wg.Done()
32 h.pc.Try(f)
33 }()
34 }
35 36 // Wait will block until all goroutines spawned with Go exit and will
37 // propagate any panics spawned in a child goroutine.
38 func (h *WaitGroup) Wait() {
39 h.wg.Wait()
40 41 // Propagate a panic if we caught one from a child goroutine.
42 h.pc.Repanic()
43 }
44 45 // WaitAndRecover will block until all goroutines spawned with Go exit and
46 // will return a *panics.Recovered if one of the child goroutines panics.
47 func (h *WaitGroup) WaitAndRecover() *panics.Recovered {
48 h.wg.Wait()
49 50 // Return a recovered panic if we caught one from a child goroutine.
51 return h.pc.Recovered()
52 }
53