From 915fa57a931d044005cdf749eb4cba43d7d3e67d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 12 May 2016 16:12:05 +0100 Subject: [PATCH] Make AtomicBool the same size as bool --- src/libcore/sync/atomic.rs | 94 +++++++++++++++----------------------- 1 file changed, 36 insertions(+), 58 deletions(-) diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index cf3e45cf3de79..49b923286d888 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -83,22 +83,22 @@ use default::Default; use fmt; /// A boolean type which can be safely shared between threads. -#[cfg(any(stage0, target_has_atomic = "ptr"))] +#[cfg(any(stage0, target_has_atomic = "8"))] #[stable(feature = "rust1", since = "1.0.0")] pub struct AtomicBool { - v: UnsafeCell, + v: UnsafeCell, } -#[cfg(any(stage0, target_has_atomic = "ptr"))] +#[cfg(any(stage0, target_has_atomic = "8"))] #[stable(feature = "rust1", since = "1.0.0")] impl Default for AtomicBool { fn default() -> Self { - Self::new(Default::default()) + Self::new(false) } } // Send is implicitly implemented for AtomicBool. -#[cfg(any(stage0, target_has_atomic = "ptr"))] +#[cfg(any(stage0, target_has_atomic = "8"))] #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Sync for AtomicBool {} @@ -162,15 +162,11 @@ pub enum Ordering { } /// An `AtomicBool` initialized to `false`. -#[cfg(any(stage0, target_has_atomic = "ptr"))] +#[cfg(any(stage0, target_has_atomic = "8"))] #[stable(feature = "rust1", since = "1.0.0")] pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false); -// NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly -#[cfg(any(stage0, target_has_atomic = "ptr"))] -const UINT_TRUE: usize = !0; - -#[cfg(any(stage0, target_has_atomic = "ptr"))] +#[cfg(any(stage0, target_has_atomic = "8"))] impl AtomicBool { /// Creates a new `AtomicBool`. /// @@ -185,7 +181,7 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub const fn new(v: bool) -> AtomicBool { - AtomicBool { v: UnsafeCell::new(-(v as isize) as usize) } + AtomicBool { v: UnsafeCell::new(v as u8) } } /// Loads a value from the bool. @@ -208,7 +204,7 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn load(&self, order: Ordering) -> bool { - unsafe { atomic_load(self.v.get(), order) > 0 } + unsafe { atomic_load(self.v.get(), order) != 0 } } /// Stores a value into the bool. @@ -232,9 +228,7 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn store(&self, val: bool, order: Ordering) { - let val = if val { UINT_TRUE } else { 0 }; - - unsafe { atomic_store(self.v.get(), val, order); } + unsafe { atomic_store(self.v.get(), val as u8, order); } } /// Stores a value into the bool, returning the old value. @@ -254,9 +248,7 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn swap(&self, val: bool, order: Ordering) -> bool { - let val = if val { UINT_TRUE } else { 0 }; - - unsafe { atomic_swap(self.v.get(), val, order) > 0 } + unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 } } /// Stores a value into the `bool` if the current value is the same as the `current` value. @@ -327,12 +319,10 @@ impl AtomicBool { new: bool, success: Ordering, failure: Ordering) -> Result { - let current = if current { UINT_TRUE } else { 0 }; - let new = if new { UINT_TRUE } else { 0 }; - - match unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) } { - Ok(x) => Ok(x > 0), - Err(x) => Err(x > 0), + match unsafe { atomic_compare_exchange(self.v.get(), current as u8, new as u8, + success, failure) } { + Ok(x) => Ok(x != 0), + Err(x) => Err(x != 0), } } @@ -373,13 +363,10 @@ impl AtomicBool { new: bool, success: Ordering, failure: Ordering) -> Result { - let current = if current { UINT_TRUE } else { 0 }; - let new = if new { UINT_TRUE } else { 0 }; - - match unsafe { atomic_compare_exchange_weak(self.v.get(), current, new, + match unsafe { atomic_compare_exchange_weak(self.v.get(), current as u8, new as u8, success, failure) } { - Ok(x) => Ok(x > 0), - Err(x) => Err(x > 0), + Ok(x) => Ok(x != 0), + Err(x) => Err(x != 0), } } @@ -410,9 +397,7 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn fetch_and(&self, val: bool, order: Ordering) -> bool { - let val = if val { UINT_TRUE } else { 0 }; - - unsafe { atomic_and(self.v.get(), val, order) > 0 } + unsafe { atomic_and(self.v.get(), val as u8, order) != 0 } } /// Logical "nand" with a boolean value. @@ -443,9 +428,20 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool { - let val = if val { UINT_TRUE } else { 0 }; - - unsafe { atomic_nand(self.v.get(), val, order) > 0 } + // 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, + } + } + old } /// Logical "or" with a boolean value. @@ -475,9 +471,7 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn fetch_or(&self, val: bool, order: Ordering) -> bool { - let val = if val { UINT_TRUE } else { 0 }; - - unsafe { atomic_or(self.v.get(), val, order) > 0 } + unsafe { atomic_or(self.v.get(), val as u8, order) != 0 } } /// Logical "xor" with a boolean value. @@ -507,9 +501,7 @@ impl AtomicBool { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool { - let val = if val { UINT_TRUE } else { 0 }; - - unsafe { atomic_xor(self.v.get(), val, order) > 0 } + unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 } } } @@ -1263,18 +1255,6 @@ unsafe fn atomic_and(dst: *mut T, val: T, order: Ordering) -> T { } } -#[inline] -unsafe fn atomic_nand(dst: *mut T, val: T, order: Ordering) -> T { - match order { - Acquire => intrinsics::atomic_nand_acq(dst, val), - Release => intrinsics::atomic_nand_rel(dst, val), - AcqRel => intrinsics::atomic_nand_acqrel(dst, val), - Relaxed => intrinsics::atomic_nand_relaxed(dst, val), - SeqCst => intrinsics::atomic_nand(dst, val) - } -} - - #[inline] unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { match order { @@ -1286,7 +1266,6 @@ unsafe fn atomic_or(dst: *mut T, val: T, order: Ordering) -> T { } } - #[inline] unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { match order { @@ -1298,7 +1277,6 @@ unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { } } - /// An atomic fence. /// /// A fence 'A' which has `Release` ordering semantics, synchronizes with a @@ -1334,7 +1312,7 @@ pub fn fence(order: Ordering) { } -#[cfg(any(stage0, target_has_atomic = "ptr"))] +#[cfg(any(stage0, target_has_atomic = "8"))] #[stable(feature = "atomic_debug", since = "1.3.0")] impl fmt::Debug for AtomicBool { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {