Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make AtomicBool the same size as bool #33579

Merged
merged 1 commit into from
May 14, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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