about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-08-18 18:44:54 -0700
committerGitHub <noreply@github.com>2016-08-18 18:44:54 -0700
commit413ada30402f823a86a75578afc63d07179f6a23 (patch)
treeedbf1fb6b30ee913687a3db0dfc6232a76c459ae
parent499484f56d336f4628a6fa016626beb3ef21ba81 (diff)
parentee1fc38c2a41c96ab3b8d058b7fa1328e93391ef (diff)
downloadrust-413ada30402f823a86a75578afc63d07179f6a23.tar.gz
rust-413ada30402f823a86a75578afc63d07179f6a23.zip
Auto merge of #35719 - Amanieu:atomic_access, r=alexcrichton
Implement RFC 1649

cc #35603 rust-lang/rfcs#1649

r? @alexcrichton
-rw-r--r--src/libcore/sync/atomic.rs142
-rw-r--r--src/test/run-pass/atomic-access-bool.rs31
2 files changed, 173 insertions, 0 deletions
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 5701a89d8bc..bd62879c1a5 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -90,6 +90,8 @@ use default::Default;
 use fmt;
 
 /// A boolean type which can be safely shared between threads.
+///
+/// This type has the same in-memory representation as a `bool`.
 #[cfg(target_has_atomic = "8")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct AtomicBool {
@@ -110,6 +112,8 @@ impl Default for AtomicBool {
 unsafe impl Sync for AtomicBool {}
 
 /// A raw pointer type which can be safely shared between threads.
+///
+/// This type has the same in-memory representation as a `*mut T`.
 #[cfg(target_has_atomic = "ptr")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct AtomicPtr<T> {
@@ -191,6 +195,48 @@ impl AtomicBool {
         AtomicBool { v: UnsafeCell::new(v as u8) }
     }
 
+    /// Returns a mutable reference to the underlying `bool`.
+    ///
+    /// This is safe because the mutable reference guarantees that no other threads are
+    /// concurrently accessing the atomic data.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(atomic_access)]
+    /// use std::sync::atomic::{AtomicBool, Ordering};
+    ///
+    /// let mut some_bool = AtomicBool::new(true);
+    /// assert_eq!(*some_bool.get_mut(), true);
+    /// *some_bool.get_mut() = false;
+    /// assert_eq!(some_bool.load(Ordering::SeqCst), false);
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_access", issue = "35603")]
+    pub fn get_mut(&mut self) -> &mut bool {
+        unsafe { &mut *(self.v.get() as *mut bool) }
+    }
+
+    /// Consumes the atomic and returns the contained value.
+    ///
+    /// This is safe because passing `self` by value guarantees that no other threads are
+    /// concurrently accessing the atomic data.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(atomic_access)]
+    /// use std::sync::atomic::AtomicBool;
+    ///
+    /// let some_bool = AtomicBool::new(true);
+    /// assert_eq!(some_bool.into_inner(), true);
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_access", issue = "35603")]
+    pub fn into_inner(self) -> bool {
+        unsafe { self.v.into_inner() != 0 }
+    }
+
     /// Loads a value from the bool.
     ///
     /// `load` takes an `Ordering` argument which describes the memory ordering of this operation.
@@ -528,6 +574,47 @@ impl<T> AtomicPtr<T> {
         AtomicPtr { p: UnsafeCell::new(p) }
     }
 
+    /// Returns a mutable reference to the underlying pointer.
+    ///
+    /// This is safe because the mutable reference guarantees that no other threads are
+    /// concurrently accessing the atomic data.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(atomic_access)]
+    /// use std::sync::atomic::{AtomicPtr, Ordering};
+    ///
+    /// let mut atomic_ptr = AtomicPtr::new(&mut 10);
+    /// *atomic_ptr.get_mut() = &mut 5;
+    /// assert_eq!(unsafe { *atomic_ptr.load(Ordering::SeqCst) }, 5);
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_access", issue = "35603")]
+    pub fn get_mut(&mut self) -> &mut *mut T {
+        unsafe { &mut *self.p.get() }
+    }
+
+    /// Consumes the atomic and returns the contained value.
+    ///
+    /// This is safe because passing `self` by value guarantees that no other threads are
+    /// concurrently accessing the atomic data.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(atomic_access)]
+    /// use std::sync::atomic::AtomicPtr;
+    ///
+    /// let atomic_ptr = AtomicPtr::new(&mut 5);
+    /// assert_eq!(unsafe { *atomic_ptr.into_inner() }, 5);
+    /// ```
+    #[inline]
+    #[unstable(feature = "atomic_access", issue = "35603")]
+    pub fn into_inner(self) -> *mut T {
+        unsafe { self.p.into_inner() }
+    }
+
     /// Loads a value from the pointer.
     ///
     /// `load` takes an `Ordering` argument which describes the memory ordering of this operation.
@@ -730,8 +817,11 @@ macro_rules! atomic_int {
     ($stable:meta,
      $stable_cxchg:meta,
      $stable_debug:meta,
+     $stable_access:meta,
      $int_type:ident $atomic_type:ident $atomic_init:ident) => {
         /// An integer type which can be safely shared between threads.
+        ///
+        /// This type has the same in-memory representation as the underlying integer type.
         #[$stable]
         pub struct $atomic_type {
             v: UnsafeCell<$int_type>,
@@ -777,6 +867,48 @@ macro_rules! atomic_int {
                 $atomic_type {v: UnsafeCell::new(v)}
             }
 
+            /// Returns a mutable reference to the underlying integer.
+            ///
+            /// This is safe because the mutable reference guarantees that no other threads are
+            /// concurrently accessing the atomic data.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// #![feature(atomic_access)]
+            /// use std::sync::atomic::{AtomicIsize, Ordering};
+            ///
+            /// let mut some_isize = AtomicIsize::new(10);
+            /// assert_eq!(*some_isize.get_mut(), 10);
+            /// *some_isize.get_mut() = 5;
+            /// assert_eq!(some_isize.load(Ordering::SeqCst), 5);
+            /// ```
+            #[inline]
+            #[$stable_access]
+            pub fn get_mut(&mut self) -> &mut $int_type {
+                unsafe { &mut *self.v.get() }
+            }
+
+            /// Consumes the atomic and returns the contained value.
+            ///
+            /// This is safe because passing `self` by value guarantees that no other threads are
+            /// concurrently accessing the atomic data.
+            ///
+            /// # Examples
+            ///
+            /// ```
+            /// #![feature(atomic_access)]
+            /// use std::sync::atomic::AtomicIsize;
+            ///
+            /// let some_isize = AtomicIsize::new(5);
+            /// assert_eq!(some_isize.into_inner(), 5);
+            /// ```
+            #[inline]
+            #[$stable_access]
+            pub fn into_inner(self) -> $int_type {
+                unsafe { self.v.into_inner() }
+            }
+
             /// Loads a value from the atomic integer.
             ///
             /// `load` takes an `Ordering` argument which describes the memory ordering of this
@@ -1057,6 +1189,7 @@ atomic_int! {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     i8 AtomicI8 ATOMIC_I8_INIT
 }
 #[cfg(target_has_atomic = "8")]
@@ -1064,6 +1197,7 @@ atomic_int! {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     u8 AtomicU8 ATOMIC_U8_INIT
 }
 #[cfg(target_has_atomic = "16")]
@@ -1071,6 +1205,7 @@ atomic_int! {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     i16 AtomicI16 ATOMIC_I16_INIT
 }
 #[cfg(target_has_atomic = "16")]
@@ -1078,6 +1213,7 @@ atomic_int! {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     u16 AtomicU16 ATOMIC_U16_INIT
 }
 #[cfg(target_has_atomic = "32")]
@@ -1085,6 +1221,7 @@ atomic_int! {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     i32 AtomicI32 ATOMIC_I32_INIT
 }
 #[cfg(target_has_atomic = "32")]
@@ -1092,6 +1229,7 @@ atomic_int! {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     u32 AtomicU32 ATOMIC_U32_INIT
 }
 #[cfg(target_has_atomic = "64")]
@@ -1099,6 +1237,7 @@ atomic_int! {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     i64 AtomicI64 ATOMIC_I64_INIT
 }
 #[cfg(target_has_atomic = "64")]
@@ -1106,6 +1245,7 @@ atomic_int! {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "32976"),
     u64 AtomicU64 ATOMIC_U64_INIT
 }
 #[cfg(target_has_atomic = "ptr")]
@@ -1113,6 +1253,7 @@ atomic_int!{
     stable(feature = "rust1", since = "1.0.0"),
     stable(feature = "extended_compare_and_swap", since = "1.10.0"),
     stable(feature = "atomic_debug", since = "1.3.0"),
+    unstable(feature = "atomic_access", issue = "35603"),
     isize AtomicIsize ATOMIC_ISIZE_INIT
 }
 #[cfg(target_has_atomic = "ptr")]
@@ -1120,6 +1261,7 @@ atomic_int!{
     stable(feature = "rust1", since = "1.0.0"),
     stable(feature = "extended_compare_and_swap", since = "1.10.0"),
     stable(feature = "atomic_debug", since = "1.3.0"),
+    unstable(feature = "atomic_access", issue = "35603"),
     usize AtomicUsize ATOMIC_USIZE_INIT
 }
 
diff --git a/src/test/run-pass/atomic-access-bool.rs b/src/test/run-pass/atomic-access-bool.rs
new file mode 100644
index 00000000000..286c92ce50e
--- /dev/null
+++ b/src/test/run-pass/atomic-access-bool.rs
@@ -0,0 +1,31 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(atomic_access)]
+use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
+use std::sync::atomic::Ordering::*;
+
+static mut ATOMIC: AtomicBool = ATOMIC_BOOL_INIT;
+
+fn main() {
+    unsafe {
+        assert_eq!(*ATOMIC.get_mut(), false);
+        ATOMIC.store(true, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), true);
+        ATOMIC.fetch_or(false, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), true);
+        ATOMIC.fetch_and(false, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), false);
+        ATOMIC.fetch_nand(true, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), true);
+        ATOMIC.fetch_xor(true, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), false);
+    }
+}