Skip to content

Commit a71ca3d

Browse files
rscgopherbot
authored andcommitted
runtime, sync, sync/atomic: document happens-before guarantees
A few of these are copied from the memory model doc. Many are entirely new, following discussion on #47141. See https://research.swtch.com/gomm for background. The rule we are establishing is that each type that is meant to help synchronize a Go program should document its happens-before guarantees. For #50859. Change-Id: I947c40639b263abe67499fa74f68711a97873a39 Reviewed-on: https://go-review.googlesource.com/c/go/+/381316 Auto-Submit: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-by: Alan Donovan <adonovan@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Roland Shoemaker <roland@golang.org>
1 parent 3651a61 commit a71ca3d

File tree

9 files changed

+62
-2
lines changed

9 files changed

+62
-2
lines changed

src/runtime/mfinal.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,23 @@ func runfinq() {
321321
// closing p.d, causing syscall.Write to fail because it is writing to
322322
// a closed file descriptor (or, worse, to an entirely different
323323
// file descriptor opened by a different goroutine). To avoid this problem,
324-
// call runtime.KeepAlive(p) after the call to syscall.Write.
324+
// call KeepAlive(p) after the call to syscall.Write.
325325
//
326326
// A single goroutine runs all finalizers for a program, sequentially.
327327
// If a finalizer must run for a long time, it should do so by starting
328328
// a new goroutine.
329+
//
330+
// In the terminology of the Go memory model, a call
331+
// SetFinalizer(x, f) “synchronizes before” the finalization call f(x).
332+
// However, there is no guarantee that KeepAlive(x) or any other use of x
333+
// “synchronizes before” f(x), so in general a finalizer should use a mutex
334+
// or other synchronization mechanism if it needs to access mutable state in x.
335+
// For example, consider a finalizer that inspects a mutable field in x
336+
// that is modified from time to time in the main program before x
337+
// becomes unreachable and the finalizer is invoked.
338+
// The modifications in the main program and the inspection in the finalizer
339+
// need to use appropriate synchronization, such as mutexes or atomic updates,
340+
// to avoid read-write races.
329341
func SetFinalizer(obj any, finalizer any) {
330342
if debug.sbrk != 0 {
331343
// debug.sbrk never frees memory, so no finalizers run

src/sync/atomic/doc.go

+8
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@
3636
// The load and store operations, implemented by the LoadT and StoreT
3737
// functions, are the atomic equivalents of "return *addr" and
3838
// "*addr = val".
39+
//
40+
// In the terminology of the Go memory model, if the effect of
41+
// an atomic operation A is observed by atomic operation B,
42+
// then A “synchronizes before” B.
43+
// Additionally, all the atomic operations executed in a program
44+
// behave as though executed in some sequentially consistent order.
45+
// This definition provides the same semantics as
46+
// C++'s sequentially consistent atomics and Java's volatile variables.
3947
package atomic
4048

4149
import (

src/sync/cond.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ import (
1818
// when calling the Wait method.
1919
//
2020
// A Cond must not be copied after first use.
21+
//
22+
// In the terminology of the Go memory model, Cond arranges that
23+
// a call to Broadcast or Signal “synchronizes before” any Wait call
24+
// that it unblocks.
2125
type Cond struct {
2226
noCopy noCopy
2327

@@ -85,11 +89,13 @@ func (c *copyChecker) check() {
8589
}
8690
}
8791

88-
// noCopy may be embedded into structs which must not be copied
92+
// noCopy may be added to structs which must not be copied
8993
// after the first use.
9094
//
9195
// See https://golang.org/issues/8005#issuecomment-190753527
9296
// for details.
97+
//
98+
// Note that it must not be embedded, due to the Lock and Unlock methods.
9399
type noCopy struct{}
94100

95101
// Lock is a no-op used by -copylocks checker from `go vet`.

src/sync/map.go

+7
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ import (
2424
// contention compared to a Go map paired with a separate Mutex or RWMutex.
2525
//
2626
// The zero Map is empty and ready for use. A Map must not be copied after first use.
27+
//
28+
// In the terminology of the Go memory model, Map arranges that a write operation
29+
// “synchronizes before” any read operation that observes the effect of the write, where
30+
// read and write operations are defined as follows.
31+
// Load, LoadAndDelete, LoadOrStore are read operations;
32+
// Delete, LoadAndDelete, and Store are write operations;
33+
// and LoadOrStore is a write operation when it returns loaded set to false.
2734
type Map struct {
2835
mu Mutex
2936

src/sync/mutex.go

+7
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ func fatal(string)
2424
// The zero value for a Mutex is an unlocked mutex.
2525
//
2626
// A Mutex must not be copied after first use.
27+
//
28+
// In the terminology of the Go memory model,
29+
// the n'th call to Unlock “synchronizes before” the m'th call to Lock
30+
// for any n < m.
31+
// A successful call to TryLock is equivalent to a call to Lock.
32+
// A failed call to TryLock does not establish any “synchronizes before”
33+
// relation at all.
2734
type Mutex struct {
2835
state int32
2936
sema uint32

src/sync/once.go

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import (
1111
// Once is an object that will perform exactly one action.
1212
//
1313
// A Once must not be copied after first use.
14+
//
15+
// In the terminology of the Go memory model,
16+
// the return from f “synchronizes before”
17+
// the return from any call of once.Do(f).
1418
type Once struct {
1519
// done indicates whether the action has been performed.
1620
// It is first in the struct because it is used in the hot path.

src/sync/pool.go

+5
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ import (
4141
// free list.
4242
//
4343
// A Pool must not be copied after first use.
44+
//
45+
// In the terminology of the Go memory model, a call to Put(x) “synchronizes before”
46+
// a call to Get returning that same value x.
47+
// Similarly, a call to New returning x “synchronizes before”
48+
// a call to Get returning that same value x.
4449
type Pool struct {
4550
noCopy noCopy
4651

src/sync/rwmutex.go

+8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ import (
2525
// recursive read locking. This is to ensure that the lock eventually becomes
2626
// available; a blocked Lock call excludes new readers from acquiring the
2727
// lock.
28+
//
29+
// In the terminology of the Go memory model,
30+
// the n'th call to Unlock “synchronizes before” the m'th call to Lock
31+
// for any n < m, just as for Mutex.
32+
// For any call to RLock, there exists an n such that
33+
// the n'th call to Unlock “synchronizes before” that call to RLock,
34+
// and the corresponding call to RUnlock “synchronizes before”
35+
// the n+1'th call to Lock.
2836
type RWMutex struct {
2937
w Mutex // held if there are pending writers
3038
writerSem uint32 // semaphore for writers to wait for completing readers

src/sync/waitgroup.go

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import (
1717
// Wait can be used to block until all goroutines have finished.
1818
//
1919
// A WaitGroup must not be copied after first use.
20+
//
21+
// In the terminology of the Go memory model, a call to Done
22+
// “synchronizes before” the return of any Wait call that it unblocks.
2023
type WaitGroup struct {
2124
noCopy noCopy
2225

0 commit comments

Comments
 (0)