distribution/vendor/github.com/pion/udp/pkg/sync/waitgroup.go

69 lines
1.6 KiB
Go

// Package sync extends basic synchronization primitives.
package sync
import (
"sync"
)
// A WaitGroup waits for a collection of goroutines to finish.
// The main goroutine calls Add to set the number of
// goroutines to wait for. Then each of the goroutines
// runs and calls Done when finished. At the same time,
// Wait can be used to block until all goroutines have finished.
//
// WaitGroups in the sync package do not allow adding or
// subtracting from the counter while another goroutine is
// waiting, while this one does.
//
// A WaitGroup must not be copied after first use.
//
// In the terminology of the Go memory model, a call to Done
type WaitGroup struct {
c int64
mutex sync.Mutex
cond *sync.Cond
}
// NewWaitGroup creates a new WaitGroup.
func NewWaitGroup() *WaitGroup {
wg := &WaitGroup{}
wg.cond = sync.NewCond(&wg.mutex)
return wg
}
// Add adds delta, which may be negative, to the WaitGroup counter.
// If the counter becomes zero, all goroutines blocked on Wait are released.
// If the counter goes negative, Add panics.
func (wg *WaitGroup) Add(delta int) {
wg.mutex.Lock()
defer wg.mutex.Unlock()
wg.c += int64(delta)
if wg.c < 0 {
panic("udp: negative WaitGroup counter") // nolint
}
wg.cond.Signal()
}
// Done decrements the WaitGroup counter by one.
func (wg *WaitGroup) Done() {
wg.Add(-1)
}
// Wait blocks until the WaitGroup counter is zero.
func (wg *WaitGroup) Wait() {
wg.mutex.Lock()
defer wg.mutex.Unlock()
for {
c := wg.c
switch {
case c == 0:
// wake another goroutine if there is one
wg.cond.Signal()
return
case c < 0:
panic("udp: negative WaitGroup counter") // nolint
}
wg.cond.Wait()
}
}