compiler_fence documentation: emphasize synchronization, not reordering · patricklam/verify-rust-std@e00784f (original) (raw)

`@@ -3570,10 +3570,9 @@ unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {

`

3570

3570

``

3571

3571

`/// An atomic fence.

`

3572

3572

`///

`

3573

``

`-

/// Depending on the specified order, a fence prevents the compiler and CPU from

`

3574

``

`-

/// reordering certain types of memory operations around it.

`

3575

``

`-

/// That creates synchronizes-with relationships between it and atomic operations

`

3576

``

`-

/// or fences in other threads.

`

``

3573

`+

/// Fences create synchronization between themselves and atomic operations or fences in other

`

``

3574

`+

/// threads. To achieve this, a fence prevents the compiler and CPU from reordering certain types of

`

``

3575

`+

/// memory operations around it.

`

3577

3576

`///

`

3578

3577

`` /// A fence 'A' which has (at least) [Release] ordering semantics, synchronizes

``

3579

3578

`` /// with a fence 'B' with (at least) [Acquire] semantics, if and only if there

``

`@@ -3594,6 +3593,12 @@ unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {

`

3594

3593

`/// }

`

3595

3594

```` /// ```


`3596`

`3595`

`///

`

``

`3596`

`` +

/// Note that in the example above, it is crucial that the accesses to `x` are atomic. Fences cannot

``

``

`3597`

`+

/// be used to establish synchronization among non-atomic accesses in different threads. However,

`

``

`3598`

`+

/// thanks to the happens-before relationship between A and B, any non-atomic accesses that

`

``

`3599`

`+

/// happen-before A are now also properly synchronized with any non-atomic accesses that

`

``

`3600`

`+

/// happen-after B.

`

``

`3601`

`+

///

`

`3597`

`3602`

`` /// Atomic operations with [`Release`] or [`Acquire`] semantics can also synchronize

``

`3598`

`3603`

`/// with a fence.

`

`3599`

`3604`

`///

`

`@@ -3659,33 +3664,30 @@ pub fn fence(order: Ordering) {

`

`3659`

`3664`

`}

`

`3660`

`3665`

`}

`

`3661`

`3666`

``

`3662`

``

`-

/// A compiler memory fence.

`

``

`3667`

`+

/// A "compiler-only" atomic fence.

`

`3663`

`3668`

`///

`

`3664`

``

`` -

/// `compiler_fence` does not emit any machine code, but restricts the kinds

``

`3665`

``

`-

/// of memory re-ordering the compiler is allowed to do. Specifically, depending on

`

`3666`

``

`` -

/// the given [`Ordering`] semantics, the compiler may be disallowed from moving reads

``

`3667`

``

`-

/// or writes from before or after the call to the other side of the call to

`

`3668`

``

`` -

/// `compiler_fence`. Note that it does **not** prevent the *hardware*

``

`3669`

``

`-

/// from doing such re-ordering. This is not a problem in a single-threaded,

`

`3670`

``

`-

/// execution context, but when other threads may modify memory at the same

`

`3671`

``

`` -

/// time, stronger synchronization primitives such as [`fence`] are required.

``

``

`3669`

`` +

/// Like [`fence`], this function establishes synchronization with other atomic operations and

``

``

`3670`

`` +

/// fences. However, unlike [`fence`], `compiler_fence` only establishes synchronization with

``

``

`3671`

`+

/// operations *in the same thread*. This may at first sound rather useless, since code within a

`

``

`3672`

`+

/// thread is typically already totally ordered and does not need any further synchronization.

`

``

`3673`

`+

/// However, there are cases where code can run on the same thread without being ordered:

`

``

`3674`

`+

/// - The most common case is that of a *signal handler*: a signal handler runs in the same thread

`

``

`3675`

`` +

/// as the code it interrupted, but it is not ordered with respect to that code. `compiler_fence`

``

``

`3676`

`+

/// can be used to establish synchronization between a thread and its signal handler, the same way

`

``

`3677`

`` +

/// that `fence` can be used to establish synchronization across threads.

``

``

`3678`

`+

/// - Similar situations can arise in embedded programming with interrupt handlers, or in custom

`

``

`3679`

`` +

/// implementations of preemptive green threads. In general, `compiler_fence` can establish

``

``

`3680`

`+

/// synchronization with code that is guaranteed to run on the same hardware CPU.

`

`3672`

`3681`

`///

`

`3673`

``

`-

/// The re-ordering prevented by the different ordering semantics are:

`

``

`3682`

`` +

/// See [`fence`] for how a fence can be used to achieve synchronization. Note that just like

``

``

`3683`

`` +

/// [`fence`], synchronization still requires atomic operations to be used in both threads -- it is

``

``

`3684`

`+

/// not possible to perform synchronization entirely with fences and non-atomic operations.

`

`3674`

`3685`

`///

`

`3675`

``

`` -

/// - with [`SeqCst`], no re-ordering of reads and writes across this point is allowed.

``

`3676`

``

`` -

/// - with [`Release`], preceding reads and writes cannot be moved past subsequent writes.

``

`3677`

``

`` -

/// - with [`Acquire`], subsequent reads and writes cannot be moved ahead of preceding reads.

``

`3678`

``

`` -

/// - with [`AcqRel`], both of the above rules are enforced.

``

``

`3686`

`` +

/// `compiler_fence` does not emit any machine code, but restricts the kinds of memory re-ordering

``

``

`3687`

`` +

/// the compiler is allowed to do. `compiler_fence` corresponds to [`atomic_signal_fence`] in C and

``

``

`3688`

`+

/// C++.

`

`3679`

`3689`

`///

`

`3680`

``

`` -

/// `compiler_fence` is generally only useful for preventing a thread from

``

`3681`

``

`-

/// racing *with itself*. That is, if a given thread is executing one piece

`

`3682`

``

`-

/// of code, and is then interrupted, and starts executing code elsewhere

`

`3683`

``

`-

/// (while still in the same thread, and conceptually still on the same

`

`3684`

``

`-

/// core). In traditional programs, this can only occur when a signal

`

`3685`

``

`-

/// handler is registered. In more low-level code, such situations can also

`

`3686`

``

`-

/// arise when handling interrupts, when implementing green threads with

`

`3687`

``

`-

/// pre-emption, etc. Curious readers are encouraged to read the Linux kernel's

`

`3688`

``

`-

/// discussion of [memory barriers].

`

``

`3690`

`` +

/// [`atomic_signal_fence`]: https://en.cppreference.com/w/cpp/atomic/atomic_signal_fence

``

`3689`

`3691`

`///

`

`3690`

`3692`

`/// # Panics

`

`3691`

`3693`

`///

`

`@@ -3723,8 +3725,6 @@ pub fn fence(order: Ordering) {

`

`3723`

`3725`

`/// }

`

`3724`

`3726`

`/// }

`

`3725`

`3727`

```` /// ```

3726

``

`-

///

`

3727

``

`-

/// [memory barriers]: https://www.kernel.org/doc/Documentation/memory-barriers.txt

`

3728

3728

`#[inline]

`

3729

3729

`#[stable(feature = "compiler_fences", since = "1.21.0")]

`

3730

3730

`#[rustc_diagnostic_item = "compiler_fence"]

`