Module Name: src Committed By: martin Date: Sun Sep 13 12:20:22 UTC 2020
Modified Files: src/lib/libc/atomic [netbsd-9]: membar_ops.3 src/share/man/man9 [netbsd-9]: atomic_loadstore.9 ipi.9 Log Message: Pull up following revision(s) (requested by riastradh in ticket #1082): share/man/man9/atomic_loadstore.9: revision 1.6 share/man/man9/ipi.9: revision 1.5 lib/libc/atomic/membar_ops.3: revision 1.6 Spell out acronyms in title for clarity. Update membar_ops(3) man page with examples and relation to C11. Add exhortation to always always always document how membars come in pairs for synchronization between two CPUs when you use them. atomic_load/store_* appeared in NetBSD 9, not 10. Pullup preceded release of 9.0. To generate a diff of this commit: cvs rdiff -u -r1.5 -r1.5.6.1 src/lib/libc/atomic/membar_ops.3 cvs rdiff -u -r1.5.2.2 -r1.5.2.3 src/share/man/man9/atomic_loadstore.9 cvs rdiff -u -r1.4 -r1.4.2.1 src/share/man/man9/ipi.9 Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libc/atomic/membar_ops.3 diff -u src/lib/libc/atomic/membar_ops.3:1.5 src/lib/libc/atomic/membar_ops.3:1.5.6.1 --- src/lib/libc/atomic/membar_ops.3:1.5 Tue Oct 24 18:19:17 2017 +++ src/lib/libc/atomic/membar_ops.3 Sun Sep 13 12:20:22 2020 @@ -1,4 +1,4 @@ -.\" $NetBSD: membar_ops.3,v 1.5 2017/10/24 18:19:17 abhinav Exp $ +.\" $NetBSD: membar_ops.3,v 1.5.6.1 2020/09/13 12:20:22 martin Exp $ .\" .\" Copyright (c) 2007, 2008 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd November 20, 2014 +.Dd September 2, 2020 .Dt MEMBAR_OPS 3 .Os .Sh NAME @@ -38,7 +38,7 @@ .Nm membar_consumer , .Nm membar_datadep_consumer , .Nm membar_sync -.Nd memory access barrier operations +.Nd memory ordering barriers .\" .Sh LIBRARY .\" .Lb libc .Sh SYNOPSIS @@ -58,33 +58,213 @@ .Fn membar_sync "void" .Sh DESCRIPTION The -.Nm membar_ops -family of functions provide memory access barrier operations necessary +.Nm +family of functions prevent reordering of memory operations, as needed for synchronization in multiprocessor execution environments that have relaxed load and store order. -.Bl -tag -width "mem" +.Pp +In general, memory barriers must come in pairs \(em a barrier on one +CPU, such as +.Fn membar_exit , +must pair with a barrier on another CPU, such as +.Fn membar_enter , +in order to synchronize anything between the two CPUs. +Code using +.Nm +should generally be annotated with comments identifying how they are +paired. +.Pp +.Nm +affect only operations on regular memory, not on device +memory; see +.Xr bus_space 9 +and +.Xr bus_dma 9 +for machine-independent interfaces to handling device memory and DMA +operations for device drivers. +.Pp +Unlike C11, +.Em all +memory operations \(em that is, all loads and stores on regular +memory \(em are affected by +.Nm , +not just C11 atomic operations on +.Vt _Atomic Ns -qualified +objects. +.Bl -tag -width abcd .It Fn membar_enter Any store preceding .Fn membar_enter -will reach global visibility before all loads and stores following it. +will happen before all memory operations following it. +.Pp +An atomic read/modify/write operation +.Pq Xr atomic_ops 3 +followed by a +.Fn membar_enter +implies a +.Em load-acquire +operation in the language of C11. +.Pp +.Sy WARNING : +A load followed by +.Fn membar_enter +.Em does not +imply a +.Em load-acquire +operation, even though +.Fn membar_exit +followed by a store implies a +.Em store-release +operation; the symmetry of these names and asymmetry of the semantics +is a historical mistake. +In the +.Nx +kernel, you can use +.Xr atomic_load_acquire 9 +for a +.Em load-acquire +operation without any atomic read/modify/write. .Pp .Fn membar_enter is typically used in code that implements locking primitives to ensure -that a lock protects its data. +that a lock protects its data, and is typically paired with +.Fn membar_exit ; +see below for an example. .It Fn membar_exit -All loads and stores preceding +All memory operations preceding .Fn membar_exit -will reach global visibility before any store that follows it. +will happen before any store that follows it. +.Pp +A +.Fn membar_exit +followed by a store implies a +.Em store-release +operation in the language of C11. +For a regular store, rather than an atomic read/modify/write store, you +should use +.Xr atomic_store_release 9 +instead of +.Fn membar_exit +followed by the store. .Pp .Fn membar_exit is typically used in code that implements locking primitives to ensure -that a lock protects its data. +that a lock protects its data, and is typically paired with +.Fn membar_enter . +For example: +.Bd -literal -offset abcdefgh +/* thread A */ +obj->state.mumblefrotz = 42; +KASSERT(valid(&obj->state)); +membar_exit(); +obj->lock = 0; + +/* thread B */ +if (atomic_cas_uint(&obj->lock, 0, 1) != 0) + return; +membar_enter(); +KASSERT(valid(&obj->state)); +obj->state.mumblefrotz--; +.Ed +.Pp +In this example, +.Em if +the +.Fn atomic_cas_uint +operation in thread B witnesses the store +.Li "obj->lock = 0" +from thread A, +.Em then +everything in thread A before the +.Fn membar_exit +is guaranteed to happen before everything in thread B after the +.Fn membar_enter , +as if the machine had sequentially executed: +.Bd -literal -offset abcdefgh +obj->state.mumblefrotz = 42; /* from thread A */ +KASSERT(valid(&obj->state)); +\&... +KASSERT(valid(&obj->state)); /* from thread B */ +obj->state.mumblefrotz--; +.Ed +.Pp +.Fn membar_exit +followed by a store, serving as a +.Em store-release +operation, may also be paired with a subsequent load followed by +.Fn membar_sync , +serving as the corresponding +.Em load-acquire +operation. +However, you should use +.Xr atomic_store_release 9 +and +.Xr atomic_load_acquire 9 +instead in that situation, unless the store is an atomic +read/modify/write which requires a separate +.Fn membar_exit . .It Fn membar_producer -All stores preceding the memory barrier will reach global visibility -before any stores after the memory barrier reach global visibility. +All stores preceding +.Fn membar_producer +will happen before any stores following it. +.Pp +.Fn membar_producer +has no analogue in C11. +.Pp +.Fn membar_producer +is typically used in code that produces data for read-only consumers +which use +.Fn membar_consumer , +such as +.Sq seqlocked +snapshots of statistics; see below for an example. .It Fn membar_consumer -All loads preceding the memory barrier will complete before any loads -after the memory barrier complete. +All loads preceding +.Fn membar_consumer +will complete before any loads after it. +.Pp +.Fn membar_consumer +has no analogue in C11. +.Pp +.Fn membar_consumer +is typically used in code that reads data from producers which use +.Fn membar_producer , +such as +.Sq seqlocked +snapshots of statistics. +For example: +.Bd -literal +struct { + /* version number and in-progress bit */ + unsigned seq; + + /* read-only statistics, too large for atomic load */ + unsigned foo; + int bar; + uint64_t baz; +} stats; + + /* producer (must be serialized, e.g. with mutex(9)) */ + stats->seq |= 1; /* mark update in progress */ + membar_producer(); + stats->foo = count_foo(); + stats->bar = measure_bar(); + stats->baz = enumerate_baz(); + membar_producer(); + stats->seq++; /* bump version number */ + + /* consumer (in parallel w/ producer, other consumers) */ +restart: + while ((seq = stats->seq) & 1) /* wait for update */ + SPINLOCK_BACKOFF_HOOK; + membar_consumer(); + foo = stats->foo; /* read out a candidate snapshot */ + bar = stats->bar; + baz = stats->baz; + membar_consumer(); + if (seq != stats->seq) /* try again if version changed */ + goto restart; +.Ed .It Fn membar_datadep_consumer Same as .Fn membar_consumer , @@ -100,9 +280,21 @@ v = *p; consume(v); .Ed .Pp -Does not guarantee ordering of loads in branches, or +.Fn membar_datadep_consumer +is typically paired with +.Fn membar_exit +by code that initializes an object before publishing it. +However, you should use +.Xr atomic_store_release 9 +and +.Xr atomic_load_consume 9 +instead, to avoid obscure edge cases in case the consumer is not +read-only. +.Pp +.Fn membar_datadep_consumer +does not guarantee ordering of loads in branches, or .Sq control-dependent -loads -- you must use +loads \(em you must use .Fn membar_consumer instead: .Bd -literal -offset indent @@ -120,12 +312,41 @@ guarantee that cached values are not sta .Fn membar_datadep_consumer is a no-op on those CPUs. .It Fn membar_sync -All loads and stores preceding the memory barrier will complete and -reach global visibility before any loads and stores after the memory -barrier complete and reach global visibility. +All memory operations preceding +.Fn membar_sync +will happen before any memory operations following it. +.Pp +.Fn membar_sync +is a sequential consistency acquire/release barrier, analogous to +.Li "atomic_thread_fence(memory_order_seq_cst)" +in C11. +.Pp +.Fn membar_sync +is typically paired with +.Fn membar_sync . +.Pp +A load followed by +.Fn membar_sync , +serving as a +.Em load-acquire +operation, may also be paired with a prior +.Fn membar_exit +followed by a store, serving as the corresponding +.Em store-release +operation. +However, you should use +.Xr atomic_load_acquire 9 +instead of +.No load-then- Ns Fn membar_sync +if it is a regular load, or +.Fn membar_enter +instead of +.Fn membar_sync +if the load is in an atomic read/modify/write operation. .El .Sh SEE ALSO -.Xr atomic_ops 3 +.Xr atomic_ops 3 , +.Xr atomic_loadstore 9 .Sh HISTORY The .Nm membar_ops Index: src/share/man/man9/atomic_loadstore.9 diff -u src/share/man/man9/atomic_loadstore.9:1.5.2.2 src/share/man/man9/atomic_loadstore.9:1.5.2.3 --- src/share/man/man9/atomic_loadstore.9:1.5.2.2 Sun Dec 8 14:26:38 2019 +++ src/share/man/man9/atomic_loadstore.9 Sun Sep 13 12:20:22 2020 @@ -1,4 +1,4 @@ -.\" $NetBSD: atomic_loadstore.9,v 1.5.2.2 2019/12/08 14:26:38 martin Exp $ +.\" $NetBSD: atomic_loadstore.9,v 1.5.2.3 2020/09/13 12:20:22 martin Exp $ .\" .\" Copyright (c) 2019 The NetBSD Foundation .\" All rights reserved. @@ -760,7 +760,7 @@ or similar to enable resource reclamatio .Xr pserialize 9 .Sh HISTORY These atomic operations first appeared in -.Nx 10.0 . +.Nx 9.0 . .Sh CAVEATS C11 formally specifies that all subexpressions, except the left operands of the Index: src/share/man/man9/ipi.9 diff -u src/share/man/man9/ipi.9:1.4 src/share/man/man9/ipi.9:1.4.2.1 --- src/share/man/man9/ipi.9:1.4 Sat Apr 6 07:57:04 2019 +++ src/share/man/man9/ipi.9 Sun Sep 13 12:20:22 2020 @@ -1,4 +1,4 @@ -.\" $NetBSD: ipi.9,v 1.4 2019/04/06 07:57:04 wiz Exp $ +.\" $NetBSD: ipi.9,v 1.4.2.1 2020/09/13 12:20:22 martin Exp $ .\" .\" Copyright (c) 2014, 2019 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -32,7 +32,7 @@ .Os .Sh NAME .Nm ipi -.Nd MI IPI interface +.Nd machine-independent interprocessor interrupts .Sh SYNOPSIS .In sys/ipi.h .Vt typedef void (*ipi_func_t)(void *);