sync.WaitGroup是“同步原语”吗?

The go memory model document says

To serialize access, protect the data with channel operations or other synchronization primitives such as those in the sync and sync/atomic packages.

And the sync package says

Package sync provides basic synchronization primitives such as mutual exclusion locks

So from this we can conclude that sync.Mutex is a synchronization primitive. There's also a very strong hint that other types in that package are synchronization primitives. However, it doesn't say explicitly that e.g. sync.WaitGroup is.

Reading the source of WaitGroup, I can't convince myself completely that memory operations won't be rearranged around WaitGroup functions (the same way I could with java's synchronized keyword for example). I believe it is serializing before/after, but how can I be sure.

Is sync.WaitGroup a "synchronization primitive"? I'm not simply looking for the answer "yes" (or "no" for that matter), but pointers that can prove the case.

sync.WaitGroup is synchronized. If you read the source, you'll see it uses sync/atomic to synchronize operations on the counters.

If you go against wise advice and follow turtles all the way down...

wg.Add() leads to line 63 which leads into atomic.AddUint64() which leads to this assembly code:

LOCK
XADDQ   AX, 0(BP)

On the other hand wg.Wait() leads to line 121 which leads to atomic.CompareAndSwapUint64() which leads to:

LOCK
CMPXCHGQ    CX, 0(BP)

And that is apparently how you build a WaitGroup :). With locked atomic exchange and add and locked atomic compare and exchange. Pretty conclusive to me. You cannot fight the assembler. OK maybe you can I cannot.

On x86 locks