github.com/evanw/esbuild@v0.21.4/internal/helpers/waitgroup.go (about) 1 package helpers 2 3 import "sync/atomic" 4 5 // Go's "sync.WaitGroup" is not thread-safe. Specifically it's not safe to call 6 // "Add" concurrently with "Wait", which is problematic because we have a case 7 // where we would like to do that. 8 // 9 // This is a simple alternative implementation of "sync.WaitGroup" that is 10 // thread-safe and that works for our purposes. We don't need to worry about 11 // multiple waiters so the implementation can be very simple. 12 type ThreadSafeWaitGroup struct { 13 counter int32 14 channel chan struct{} 15 } 16 17 func MakeThreadSafeWaitGroup() *ThreadSafeWaitGroup { 18 return &ThreadSafeWaitGroup{ 19 channel: make(chan struct{}, 1), 20 } 21 } 22 23 func (wg *ThreadSafeWaitGroup) Add(delta int32) { 24 if counter := atomic.AddInt32(&wg.counter, delta); counter == 0 { 25 wg.channel <- struct{}{} 26 } else if counter < 0 { 27 panic("sync: negative WaitGroup counter") 28 } 29 } 30 31 func (wg *ThreadSafeWaitGroup) Done() { 32 wg.Add(-1) 33 } 34 35 func (wg *ThreadSafeWaitGroup) Wait() { 36 <-wg.channel 37 }