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  }