Skip to content

Commit

Permalink
Auto merge of #33579 - Amanieu:atomic_bool2, r=alexcrichton
Browse files Browse the repository at this point in the history
Make AtomicBool the same size as bool

Reopening #32365

This allows `AtomicBool` to be transmuted to a `bool`, which makes it more consistent with the other atomic types. Note that this now guarantees that the atomic type will always contain a valid `bool` value, which wasn't the case before (due to `fetch_nand`).

r? @alexcrichton
  • Loading branch information
bors committed May 14, 2016
2 parents 5029a60 + 915fa57 commit 8492b6a
Showing 1 changed file with 36 additions and 58 deletions.
94 changes: 36 additions & 58 deletions src/libcore/sync/atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<usize>,
v: UnsafeCell<u8>,
}

#[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 {}

Expand Down Expand Up @@ -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`.
///
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -327,12 +319,10 @@ impl AtomicBool {
new: bool,
success: Ordering,
failure: Ordering) -> Result<bool, bool> {
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),
}
}

Expand Down Expand Up @@ -373,13 +363,10 @@ impl AtomicBool {
new: bool,
success: Ordering,
failure: Ordering) -> Result<bool, bool> {
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),
}
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 }
}
}

Expand Down Expand Up @@ -1263,18 +1255,6 @@ unsafe fn atomic_and<T>(dst: *mut T, val: T, order: Ordering) -> T {
}
}

#[inline]
unsafe fn atomic_nand<T>(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<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Expand All @@ -1286,7 +1266,6 @@ unsafe fn atomic_or<T>(dst: *mut T, val: T, order: Ordering) -> T {
}
}


#[inline]
unsafe fn atomic_xor<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Expand All @@ -1298,7 +1277,6 @@ unsafe fn atomic_xor<T>(dst: *mut T, val: T, order: Ordering) -> T {
}
}


/// An atomic fence.
///
/// A fence 'A' which has `Release` ordering semantics, synchronizes with a
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 8492b6a

Please sign in to comment.