Copyright 2011 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package sync

import (
	
	
	
)
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. A WaitGroup must not be copied after first use.
type WaitGroup struct {
	noCopy noCopy
64-bit value: high 32 bits are counter, low 32 bits are waiter count. 64-bit atomic operations require 64-bit alignment, but 32-bit compilers do not ensure it. So we allocate 12 bytes and then use the aligned 8 bytes in them as state, and the other 4 as storage for the sema.
	state1 [3]uint32
}
state returns pointers to the state and sema fields stored within wg.state1.
func ( *WaitGroup) () ( *uint64,  *uint32) {
	if uintptr(unsafe.Pointer(&.state1))%8 == 0 {
		return (*uint64)(unsafe.Pointer(&.state1)), &.state1[2]
	} else {
		return (*uint64)(unsafe.Pointer(&.state1[1])), &.state1[0]
	}
}
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. Note that calls with a positive delta that occur when the counter is zero must happen before a Wait. Calls with a negative delta, or calls with a positive delta that start when the counter is greater than zero, may happen at any time. Typically this means the calls to Add should execute before the statement creating the goroutine or other event to be waited for. If a WaitGroup is reused to wait for several independent sets of events, new Add calls must happen after all previous Wait calls have returned. See the WaitGroup example.
func ( *WaitGroup) ( int) {
	,  := .state()
	if race.Enabled {
		_ = * // trigger nil deref early
Synchronize decrements with Wait.
			race.ReleaseMerge(unsafe.Pointer())
		}
		race.Disable()
		defer race.Enable()
	}
	 := atomic.AddUint64(, uint64()<<32)
	 := int32( >> 32)
	 := uint32()
The first increment must be synchronized with Wait. Need to model this as a read, because there can be several concurrent wg.counter transitions from 0.
		race.Read(unsafe.Pointer())
	}
	if  < 0 {
		panic("sync: negative WaitGroup counter")
	}
	if  != 0 &&  > 0 &&  == int32() {
		panic("sync: WaitGroup misuse: Add called concurrently with Wait")
	}
	if  > 0 ||  == 0 {
		return
This goroutine has set counter to 0 when waiters > 0. Now there can't be concurrent mutations of state: - Adds must not happen concurrently with Wait, - Wait does not increment waiters if it sees counter == 0. Still do a cheap sanity check to detect WaitGroup misuse.
	if * !=  {
		panic("sync: WaitGroup misuse: Add called concurrently with Wait")
Reset waiters count to 0.
	* = 0
	for ;  != 0; -- {
		runtime_Semrelease(, false, 0)
	}
}
Done decrements the WaitGroup counter by one.
func ( *WaitGroup) () {
	.Add(-1)
}
Wait blocks until the WaitGroup counter is zero.
func ( *WaitGroup) () {
	,  := .state()
	if race.Enabled {
		_ = * // trigger nil deref early
		race.Disable()
	}
	for {
		 := atomic.LoadUint64()
		 := int32( >> 32)
		 := uint32()
Counter is 0, no need to wait.
			if race.Enabled {
				race.Enable()
				race.Acquire(unsafe.Pointer())
			}
			return
Increment waiters count.
		if atomic.CompareAndSwapUint64(, , +1) {
Wait must be synchronized with the first Add. Need to model this is as a write to race with the read in Add. As a consequence, can do the write only for the first waiter, otherwise concurrent Waits will race with each other.
				race.Write(unsafe.Pointer())
			}
			runtime_Semacquire()
			if * != 0 {
				panic("sync: WaitGroup is reused before previous Wait has returned")
			}
			if race.Enabled {
				race.Enable()
				race.Acquire(unsafe.Pointer())
			}
			return
		}
	}