about summary refs log tree commit diff
path: root/src/libcore/sync
diff options
context:
space:
mode:
authorQuietMisdreavus <grey@quietmisdreavus.net>2017-04-09 10:38:38 -0500
committerQuietMisdreavus <grey@quietmisdreavus.net>2017-04-09 10:38:38 -0500
commit8dd4c44ef6c851afcc9651c9b32df005e35d0d1d (patch)
tree5dc8ec96361b673f8d4162821a97f8f021d83436 /src/libcore/sync
parentbfd01b7f40ae2cbfe9acbc1d10e79ffe16870df8 (diff)
parent2c48ae6f7ffae392d85c86240c67f49df01f44fd (diff)
downloadrust-8dd4c44ef6c851afcc9651c9b32df005e35d0d1d.tar.gz
rust-8dd4c44ef6c851afcc9651c9b32df005e35d0d1d.zip
merge with master to pick up pulldown switch
Diffstat (limited to 'src/libcore/sync')
-rw-r--r--src/libcore/sync/atomic.rs170
1 files changed, 131 insertions, 39 deletions
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 743e3c41170..0c70524ead2 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -15,27 +15,37 @@
 //! types.
 //!
 //! This module defines atomic versions of a select number of primitive
-//! types, including `AtomicBool`, `AtomicIsize`, and `AtomicUsize`.
+//! types, including [`AtomicBool`], [`AtomicIsize`], and [`AtomicUsize`].
 //! Atomic types present operations that, when used correctly, synchronize
 //! updates between threads.
 //!
-//! Each method takes an `Ordering` which represents the strength of
+//! [`AtomicBool`]: struct.AtomicBool.html
+//! [`AtomicIsize`]: struct.AtomicIsize.html
+//! [`AtomicUsize`]: struct.AtomicUsize.html
+//!
+//! Each method takes an [`Ordering`] which represents the strength of
 //! the memory barrier for that operation. These orderings are the
 //! same as [LLVM atomic orderings][1]. For more information see the [nomicon][2].
 //!
+//! [`Ordering`]: enum.Ordering.html
+//!
 //! [1]: http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations
 //! [2]: ../../../nomicon/atomics.html
 //!
-//! Atomic variables are safe to share between threads (they implement `Sync`)
+//! Atomic variables are safe to share between threads (they implement [`Sync`])
 //! but they do not themselves provide the mechanism for sharing and follow the
 //! [threading model](../../../std/thread/index.html#the-threading-model) of rust.
-//! The most common way to share an atomic variable is to put it into an `Arc` (an
+//! The most common way to share an atomic variable is to put it into an [`Arc`][arc] (an
 //! atomically-reference-counted shared pointer).
 //!
+//! [`Sync`]: ../../marker/trait.Sync.html
+//! [arc]: ../../../std/sync/struct.Arc.html
+//!
 //! Most atomic types may be stored in static variables, initialized using
-//! the provided static initializers like `ATOMIC_BOOL_INIT`. Atomic statics
+//! the provided static initializers like [`ATOMIC_BOOL_INIT`]. Atomic statics
 //! are often used for lazy global initialization.
 //!
+//! [`ATOMIC_BOOL_INIT`]: constant.ATOMIC_BOOL_INIT.html
 //!
 //! # Examples
 //!
@@ -143,27 +153,38 @@ unsafe impl<T> Sync for AtomicPtr<T> {}
 /// Rust's memory orderings are [the same as
 /// LLVM's](http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations).
 ///
-/// For more information see the [nomicon][1].
-/// [1]: ../../../nomicon/atomics.html
+/// For more information see the [nomicon].
+///
+/// [nomicon]: ../../../nomicon/atomics.html
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Copy, Clone, Debug)]
 pub enum Ordering {
-    /// No ordering constraints, only atomic operations. Corresponds to LLVM's
-    /// `Monotonic` ordering.
+    /// No ordering constraints, only atomic operations.
+    ///
+    /// Corresponds to LLVM's [`Monotonic`] ordering.
+    ///
+    /// [`Monotonic`]: http://llvm.org/docs/Atomics.html#monotonic
     #[stable(feature = "rust1", since = "1.0.0")]
     Relaxed,
     /// When coupled with a store, all previous writes become visible
-    /// to the other threads that perform a load with `Acquire` ordering
+    /// to the other threads that perform a load with [`Acquire`] ordering
     /// on the same value.
+    ///
+    /// [`Acquire`]: http://llvm.org/docs/Atomics.html#acquire
     #[stable(feature = "rust1", since = "1.0.0")]
     Release,
     /// When coupled with a load, all subsequent loads will see data
-    /// written before a store with `Release` ordering on the same value
+    /// written before a store with [`Release`] ordering on the same value
     /// in other threads.
+    ///
+    /// [`Release`]: http://llvm.org/docs/Atomics.html#release
     #[stable(feature = "rust1", since = "1.0.0")]
     Acquire,
-    /// When coupled with a load, uses `Acquire` ordering, and with a store
-    /// `Release` ordering.
+    /// When coupled with a load, uses [`Acquire`] ordering, and with a store
+    /// [`Release`] ordering.
+    ///
+    /// [`Acquire`]: http://llvm.org/docs/Atomics.html#acquire
+    /// [`Release`]: http://llvm.org/docs/Atomics.html#release
     #[stable(feature = "rust1", since = "1.0.0")]
     AcqRel,
     /// Like `AcqRel` with the additional guarantee that all threads see all
@@ -176,7 +197,9 @@ pub enum Ordering {
     __Nonexhaustive,
 }
 
-/// An `AtomicBool` initialized to `false`.
+/// An [`AtomicBool`] initialized to `false`.
+///
+/// [`AtomicBool`]: struct.AtomicBool.html
 #[cfg(target_has_atomic = "8")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false);
@@ -250,7 +273,7 @@ impl AtomicBool {
     ///
     /// [`Ordering`]: enum.Ordering.html
     /// [`Release`]: enum.Ordering.html#variant.Release
-    /// [`AcqRel`]: enum.Ordering.html#variant.Release
+    /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel
     ///
     /// # Examples
     ///
@@ -287,7 +310,10 @@ impl AtomicBool {
     ///
     /// # Panics
     ///
-    /// Panics if `order` is `Acquire` or `AcqRel`.
+    /// Panics if `order` is [`Acquire`] or [`AcqRel`].
+    ///
+    /// [`Acquire`]: enum.Ordering.html#variant.Acquire
+    /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn store(&self, val: bool, order: Ordering) {
@@ -296,7 +322,7 @@ impl AtomicBool {
         }
     }
 
-    /// Stores a value into the bool, returning the old value.
+    /// Stores a value into the bool, returning the previous value.
     ///
     /// `swap` takes an [`Ordering`] argument which describes the memory ordering
     /// of this operation.
@@ -404,7 +430,7 @@ impl AtomicBool {
 
     /// Stores a value into the `bool` if the current value is the same as the `current` value.
     ///
-    /// Unlike `compare_exchange`, this function is allowed to spuriously fail even when the
+    /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even when the
     /// comparison succeeds, which can result in more efficient code on some platforms. The
     /// return value is a result indicating whether the new value was written and containing the
     /// previous value.
@@ -415,6 +441,7 @@ impl AtomicBool {
     /// failure ordering can't be [`Release`] or [`AcqRel`] and must be equivalent or
     /// weaker than the success ordering.
     ///
+    /// [`compare_exchange`]: #method.compare_exchange
     /// [`Ordering`]: enum.Ordering.html
     /// [`Release`]: enum.Ordering.html#variant.Release
     /// [`AcqRel`]: enum.Ordering.html#variant.Release
@@ -512,17 +539,16 @@ impl AtomicBool {
         // We can't use atomic_nand here because it can result in a bool with
         // an invalid value. This happens because the atomic operation is done
         // with an 8-bit integer internally, which would set the upper 7 bits.
-        // So we just use a compare-exchange loop instead, which is what the
-        // intrinsic actually expands to anyways on many platforms.
-        let mut old = self.load(Relaxed);
-        loop {
-            let new = !(old && val);
-            match self.compare_exchange_weak(old, new, order, Relaxed) {
-                Ok(_) => break,
-                Err(x) => old = x,
-            }
+        // So we just use fetch_xor or swap instead.
+        if val {
+            // !(x & true) == !x
+            // We must invert the bool.
+            self.fetch_xor(true, order)
+        } else {
+            // !(x & false) == true
+            // We must set the bool to true.
+            self.swap(true, order)
         }
-        old
     }
 
     /// Logical "or" with a boolean value.
@@ -694,7 +720,10 @@ impl<T> AtomicPtr<T> {
     ///
     /// # Panics
     ///
-    /// Panics if `order` is `Acquire` or `AcqRel`.
+    /// Panics if `order` is [`Acquire`] or [`AcqRel`].
+    ///
+    /// [`Acquire`]: enum.Ordering.html#variant.Acquire
+    /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn store(&self, ptr: *mut T, order: Ordering) {
@@ -703,7 +732,7 @@ impl<T> AtomicPtr<T> {
         }
     }
 
-    /// Stores a value into the pointer, returning the old value.
+    /// Stores a value into the pointer, returning the previous value.
     ///
     /// `swap` takes an [`Ordering`] argument which describes the memory ordering
     /// of this operation.
@@ -1008,14 +1037,17 @@ macro_rules! atomic_int {
             ///
             /// # Panics
             ///
-            /// Panics if `order` is `Acquire` or `AcqRel`.
+            /// Panics if `order` is [`Acquire`] or [`AcqRel`].
+            ///
+            /// [`Acquire`]: enum.Ordering.html#variant.Acquire
+            /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel
             #[inline]
             #[$stable]
             pub fn store(&self, val: $int_type, order: Ordering) {
                 unsafe { atomic_store(self.v.get(), val, order); }
             }
 
-            /// Stores a value into the atomic integer, returning the old value.
+            /// Stores a value into the atomic integer, returning the previous value.
             ///
             /// `swap` takes an [`Ordering`] argument which describes the memory ordering of this
             /// operation.
@@ -1169,7 +1201,9 @@ macro_rules! atomic_int {
                 }
             }
 
-            /// Add to the current value, returning the previous value.
+            /// Adds to the current value, returning the previous value.
+            ///
+            /// This operation wraps around on overflow.
             ///
             /// # Examples
             ///
@@ -1186,7 +1220,9 @@ macro_rules! atomic_int {
                 unsafe { atomic_add(self.v.get(), val, order) }
             }
 
-            /// Subtract from the current value, returning the previous value.
+            /// Subtracts from the current value, returning the previous value.
+            ///
+            /// This operation wraps around on overflow.
             ///
             /// # Examples
             ///
@@ -1203,7 +1239,12 @@ macro_rules! atomic_int {
                 unsafe { atomic_sub(self.v.get(), val, order) }
             }
 
-            /// Bitwise and with the current value, returning the previous value.
+            /// Bitwise "and" with the current value.
+            ///
+            /// Performs a bitwise "and" operation on the current value and the argument `val`, and
+            /// sets the new value to the result.
+            ///
+            /// Returns the previous value.
             ///
             /// # Examples
             ///
@@ -1219,7 +1260,12 @@ macro_rules! atomic_int {
                 unsafe { atomic_and(self.v.get(), val, order) }
             }
 
-            /// Bitwise or with the current value, returning the previous value.
+            /// Bitwise "or" with the current value.
+            ///
+            /// Performs a bitwise "or" operation on the current value and the argument `val`, and
+            /// sets the new value to the result.
+            ///
+            /// Returns the previous value.
             ///
             /// # Examples
             ///
@@ -1235,7 +1281,12 @@ macro_rules! atomic_int {
                 unsafe { atomic_or(self.v.get(), val, order) }
             }
 
-            /// Bitwise xor with the current value, returning the previous value.
+            /// Bitwise "xor" with the current value.
+            ///
+            /// Performs a bitwise "xor" operation on the current value and the argument `val`, and
+            /// sets the new value to the result.
+            ///
+            /// Returns the previous value.
             ///
             /// # Examples
             ///
@@ -1383,7 +1434,7 @@ unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
     }
 }
 
-/// Returns the old value (like __sync_fetch_and_add).
+/// Returns the previous value (like __sync_fetch_and_add).
 #[inline]
 unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
@@ -1396,7 +1447,7 @@ unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
     }
 }
 
-/// Returns the old value (like __sync_fetch_and_sub).
+/// Returns the previous value (like __sync_fetch_and_sub).
 #[inline]
 unsafe fn atomic_sub<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
@@ -1540,6 +1591,47 @@ pub fn fence(order: Ordering) {
 }
 
 
+/// A compiler memory barrier.
+///
+/// `compiler_barrier` does not emit any machine code, but prevents the compiler from re-ordering
+/// memory operations across this point. Which reorderings are disallowed is dictated by the given
+/// [`Ordering`]. Note that `compiler_barrier` does *not* introduce inter-thread memory
+/// synchronization; for that, a [`fence`] is needed.
+///
+/// The re-ordering prevented by the different ordering semantics are:
+///
+///  - with [`SeqCst`], no re-ordering of reads and writes across this point is allowed.
+///  - with [`Release`], preceding reads and writes cannot be moved past subsequent writes.
+///  - with [`Acquire`], subsequent reads and writes cannot be moved ahead of preceding reads.
+///  - with [`AcqRel`], both of the above rules are enforced.
+///
+/// # Panics
+///
+/// Panics if `order` is [`Relaxed`].
+///
+/// [`fence`]: fn.fence.html
+/// [`Ordering`]: enum.Ordering.html
+/// [`Acquire`]: enum.Ordering.html#variant.Acquire
+/// [`SeqCst`]: enum.Ordering.html#variant.SeqCst
+/// [`Release`]: enum.Ordering.html#variant.Release
+/// [`AcqRel`]: enum.Ordering.html#variant.AcqRel
+/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed
+#[inline]
+#[unstable(feature = "compiler_barriers", issue = "41091")]
+pub fn compiler_barrier(order: Ordering) {
+    unsafe {
+        match order {
+            Acquire => intrinsics::atomic_singlethreadfence_acq(),
+            Release => intrinsics::atomic_singlethreadfence_rel(),
+            AcqRel => intrinsics::atomic_singlethreadfence_acqrel(),
+            SeqCst => intrinsics::atomic_singlethreadfence(),
+            Relaxed => panic!("there is no such thing as a relaxed barrier"),
+            __Nonexhaustive => panic!("invalid memory ordering"),
+        }
+    }
+}
+
+
 #[cfg(target_has_atomic = "8")]
 #[stable(feature = "atomic_debug", since = "1.3.0")]
 impl fmt::Debug for AtomicBool {