github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/sync/waitgroup.go (about)

     1  package sync
     2  
     3  import "internal/task"
     4  
     5  type WaitGroup struct {
     6  	counter uint
     7  	waiters task.Stack
     8  }
     9  
    10  func (wg *WaitGroup) Add(delta int) {
    11  	if delta > 0 {
    12  		// Check for overflow.
    13  		if uint(delta) > (^uint(0))-wg.counter {
    14  			panic("sync: WaitGroup counter overflowed")
    15  		}
    16  
    17  		// Add to the counter.
    18  		wg.counter += uint(delta)
    19  	} else {
    20  		// Check for underflow.
    21  		if uint(-delta) > wg.counter {
    22  			panic("sync: negative WaitGroup counter")
    23  		}
    24  
    25  		// Subtract from the counter.
    26  		wg.counter -= uint(-delta)
    27  
    28  		// If the counter is zero, everything is done and the waiters should be resumed.
    29  		// This code assumes that the waiters cannot wake up until after this function returns.
    30  		// In the current implementation, this is always correct.
    31  		if wg.counter == 0 {
    32  			for t := wg.waiters.Pop(); t != nil; t = wg.waiters.Pop() {
    33  				scheduleTask(t)
    34  			}
    35  		}
    36  	}
    37  }
    38  
    39  func (wg *WaitGroup) Done() {
    40  	wg.Add(-1)
    41  }
    42  
    43  func (wg *WaitGroup) Wait() {
    44  	if wg.counter == 0 {
    45  		// Everything already finished.
    46  		return
    47  	}
    48  
    49  	// Push the current goroutine onto the waiter stack.
    50  	wg.waiters.Push(task.Current())
    51  
    52  	// Pause until the waiters are awoken by Add/Done.
    53  	task.Pause()
    54  }