2013-05-25 00:51:26 -05:00
|
|
|
// Copyright 2012-2013 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.
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Atomic types
|
2013-05-25 19:54:30 -05:00
|
|
|
*
|
|
|
|
* Basic atomic types supporting atomic operations. Each method takes an `Ordering` which
|
|
|
|
* represents the strength of the memory barrier for that operation. These orderings are the same
|
|
|
|
* as C++11 atomic orderings [http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync]
|
|
|
|
*
|
|
|
|
* All atomic types are a single word in size.
|
2013-05-25 00:51:26 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
use unstable::intrinsics;
|
|
|
|
use cast;
|
|
|
|
use option::{Option,Some,None};
|
2013-05-25 19:39:53 -05:00
|
|
|
use libc::c_void;
|
|
|
|
use ops::Drop;
|
2013-05-25 00:51:26 -05:00
|
|
|
|
2013-05-25 19:54:30 -05:00
|
|
|
/**
|
|
|
|
* A simple atomic flag, that can be set and cleared. The most basic atomic type.
|
|
|
|
*/
|
2013-05-25 00:51:26 -05:00
|
|
|
pub struct AtomicFlag {
|
2013-05-25 18:44:31 -05:00
|
|
|
priv v: int
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
|
2013-05-25 19:54:30 -05:00
|
|
|
/**
|
|
|
|
* An atomic boolean type.
|
|
|
|
*/
|
2013-05-25 00:51:26 -05:00
|
|
|
pub struct AtomicBool {
|
2013-05-25 18:44:31 -05:00
|
|
|
priv v: uint
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
|
2013-05-25 19:54:30 -05:00
|
|
|
/**
|
|
|
|
* A signed atomic integer type, supporting basic atomic aritmetic operations
|
|
|
|
*/
|
2013-05-25 00:51:26 -05:00
|
|
|
pub struct AtomicInt {
|
2013-05-25 18:44:31 -05:00
|
|
|
priv v: int
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
|
2013-05-25 19:54:30 -05:00
|
|
|
/**
|
|
|
|
* An unsigned atomic integer type, supporting basic atomic aritmetic operations
|
|
|
|
*/
|
2013-05-25 00:51:26 -05:00
|
|
|
pub struct AtomicUint {
|
2013-05-25 18:44:31 -05:00
|
|
|
priv v: uint
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
|
2013-05-25 19:54:30 -05:00
|
|
|
/**
|
|
|
|
* An unsafe atomic pointer. Only supports basic atomic operations
|
|
|
|
*/
|
2013-05-25 00:51:26 -05:00
|
|
|
pub struct AtomicPtr<T> {
|
2013-05-25 18:44:31 -05:00
|
|
|
priv p: *mut T
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
|
2013-05-25 19:54:30 -05:00
|
|
|
/**
|
|
|
|
* An owned atomic pointer. Ensures that only a single reference to the data is held at any time.
|
|
|
|
*/
|
2013-06-27 12:47:45 -05:00
|
|
|
#[unsafe_no_drop_flag]
|
2013-05-25 19:39:53 -05:00
|
|
|
pub struct AtomicOption<T> {
|
|
|
|
priv p: *mut c_void
|
|
|
|
}
|
|
|
|
|
2013-05-25 00:51:26 -05:00
|
|
|
pub enum Ordering {
|
2013-07-23 05:34:40 -05:00
|
|
|
Relaxed,
|
2013-05-25 00:51:26 -05:00
|
|
|
Release,
|
|
|
|
Acquire,
|
2013-07-23 05:34:40 -05:00
|
|
|
AcqRel,
|
2013-05-25 00:51:26 -05:00
|
|
|
SeqCst
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl AtomicFlag {
|
|
|
|
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn new() -> AtomicFlag {
|
2013-05-25 00:51:26 -05:00
|
|
|
AtomicFlag { v: 0 }
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clears the atomic flag
|
|
|
|
*/
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn clear(&mut self, order: Ordering) {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe {atomic_store(&mut self.v, 0, order)}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the flag if it was previously unset, returns the previous value of the
|
|
|
|
* flag.
|
|
|
|
*/
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn test_and_set(&mut self, order: Ordering) -> bool {
|
2013-07-25 03:46:31 -05:00
|
|
|
unsafe { atomic_compare_and_swap(&mut self.v, 0, 1, order) > 0 }
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AtomicBool {
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn new(v: bool) -> AtomicBool {
|
2013-05-25 00:51:26 -05:00
|
|
|
AtomicBool { v: if v { 1 } else { 0 } }
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn load(&self, order: Ordering) -> bool {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe { atomic_load(&self.v, order) > 0 }
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn store(&mut self, val: bool, order: Ordering) {
|
2013-05-25 00:51:26 -05:00
|
|
|
let val = if val { 1 } else { 0 };
|
|
|
|
|
|
|
|
unsafe { atomic_store(&mut self.v, val, order); }
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn swap(&mut self, val: bool, order: Ordering) -> bool {
|
2013-05-25 00:51:26 -05:00
|
|
|
let val = if val { 1 } else { 0 };
|
|
|
|
|
2013-07-25 03:46:31 -05:00
|
|
|
unsafe { atomic_swap(&mut self.v, val, order) > 0 }
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn compare_and_swap(&mut self, old: bool, new: bool, order: Ordering) -> bool {
|
2013-05-25 00:51:26 -05:00
|
|
|
let old = if old { 1 } else { 0 };
|
|
|
|
let new = if new { 1 } else { 0 };
|
|
|
|
|
|
|
|
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) > 0 }
|
|
|
|
}
|
2013-07-25 03:46:31 -05:00
|
|
|
|
|
|
|
/// Returns the old value
|
|
|
|
#[inline]
|
|
|
|
pub fn fetch_and(&mut self, val: bool, order: Ordering) -> bool {
|
|
|
|
let val = if val { 1 } else { 0 };
|
|
|
|
|
|
|
|
unsafe { atomic_and(&mut self.v, val, order) > 0 }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the old value
|
|
|
|
#[inline]
|
|
|
|
pub fn fetch_nand(&mut self, val: bool, order: Ordering) -> bool {
|
|
|
|
let val = if val { 1 } else { 0 };
|
|
|
|
|
|
|
|
unsafe { atomic_nand(&mut self.v, val, order) > 0 }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the old value
|
|
|
|
#[inline]
|
|
|
|
pub fn fetch_or(&mut self, val: bool, order: Ordering) -> bool {
|
|
|
|
let val = if val { 1 } else { 0 };
|
|
|
|
|
|
|
|
unsafe { atomic_or(&mut self.v, val, order) > 0 }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the old value
|
|
|
|
#[inline]
|
|
|
|
pub fn fetch_xor(&mut self, val: bool, order: Ordering) -> bool {
|
|
|
|
let val = if val { 1 } else { 0 };
|
|
|
|
|
|
|
|
unsafe { atomic_xor(&mut self.v, val, order) > 0 }
|
|
|
|
}
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AtomicInt {
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn new(v: int) -> AtomicInt {
|
2013-05-25 00:51:26 -05:00
|
|
|
AtomicInt { v:v }
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn load(&self, order: Ordering) -> int {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe { atomic_load(&self.v, order) }
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn store(&mut self, val: int, order: Ordering) {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe { atomic_store(&mut self.v, val, order); }
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn swap(&mut self, val: int, order: Ordering) -> int {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe { atomic_swap(&mut self.v, val, order) }
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn compare_and_swap(&mut self, old: int, new: int, order: Ordering) -> int {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) }
|
|
|
|
}
|
|
|
|
|
2013-06-10 21:13:17 -05:00
|
|
|
/// Returns the old value (like __sync_fetch_and_add).
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn fetch_add(&mut self, val: int, order: Ordering) -> int {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe { atomic_add(&mut self.v, val, order) }
|
|
|
|
}
|
|
|
|
|
2013-06-10 21:13:17 -05:00
|
|
|
/// Returns the old value (like __sync_fetch_and_sub).
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn fetch_sub(&mut self, val: int, order: Ordering) -> int {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe { atomic_sub(&mut self.v, val, order) }
|
|
|
|
}
|
2013-07-25 03:46:31 -05:00
|
|
|
|
|
|
|
/// Returns the old value
|
|
|
|
#[inline]
|
|
|
|
pub fn fetch_min(&mut self, val: int, order: Ordering) -> int {
|
|
|
|
unsafe { atomic_min(&mut self.v, val, order) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the old value
|
|
|
|
#[inline]
|
|
|
|
pub fn fetch_max(&mut self, val: int, order: Ordering) -> int {
|
|
|
|
unsafe { atomic_max(&mut self.v, val, order) }
|
|
|
|
}
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AtomicUint {
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn new(v: uint) -> AtomicUint {
|
2013-05-25 00:51:26 -05:00
|
|
|
AtomicUint { v:v }
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn load(&self, order: Ordering) -> uint {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe { atomic_load(&self.v, order) }
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn store(&mut self, val: uint, order: Ordering) {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe { atomic_store(&mut self.v, val, order); }
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn swap(&mut self, val: uint, order: Ordering) -> uint {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe { atomic_swap(&mut self.v, val, order) }
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn compare_and_swap(&mut self, old: uint, new: uint, order: Ordering) -> uint {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) }
|
|
|
|
}
|
|
|
|
|
2013-06-10 21:13:17 -05:00
|
|
|
/// Returns the old value (like __sync_fetch_and_add).
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn fetch_add(&mut self, val: uint, order: Ordering) -> uint {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe { atomic_add(&mut self.v, val, order) }
|
|
|
|
}
|
|
|
|
|
2013-06-10 21:13:17 -05:00
|
|
|
/// Returns the old value (like __sync_fetch_and_sub)..
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn fetch_sub(&mut self, val: uint, order: Ordering) -> uint {
|
2013-05-25 00:51:26 -05:00
|
|
|
unsafe { atomic_sub(&mut self.v, val, order) }
|
|
|
|
}
|
2013-07-25 03:46:31 -05:00
|
|
|
|
|
|
|
/// Returns the old value
|
|
|
|
#[inline]
|
|
|
|
pub fn fetch_min(&mut self, val: uint, order: Ordering) -> uint {
|
|
|
|
unsafe { atomic_umin(&mut self.v, val, order) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the old value
|
|
|
|
#[inline]
|
|
|
|
pub fn fetch_max(&mut self, val: uint, order: Ordering) -> uint {
|
|
|
|
unsafe { atomic_umax(&mut self.v, val, order) }
|
|
|
|
}
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> AtomicPtr<T> {
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn new(p: *mut T) -> AtomicPtr<T> {
|
2013-05-25 00:51:26 -05:00
|
|
|
AtomicPtr { p:p }
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn load(&self, order: Ordering) -> *mut T {
|
2013-05-25 18:44:31 -05:00
|
|
|
unsafe { atomic_load(&self.p, order) }
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn store(&mut self, ptr: *mut T, order: Ordering) {
|
2013-05-25 18:44:31 -05:00
|
|
|
unsafe { atomic_store(&mut self.p, ptr, order); }
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn swap(&mut self, ptr: *mut T, order: Ordering) -> *mut T {
|
2013-05-25 18:44:31 -05:00
|
|
|
unsafe { atomic_swap(&mut self.p, ptr, order) }
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn compare_and_swap(&mut self, old: *mut T, new: *mut T, order: Ordering) -> *mut T {
|
2013-05-25 19:39:53 -05:00
|
|
|
unsafe { atomic_compare_and_swap(&mut self.p, old, new, order) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> AtomicOption<T> {
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn new(p: ~T) -> AtomicOption<T> {
|
2013-05-25 19:39:53 -05:00
|
|
|
unsafe {
|
|
|
|
AtomicOption {
|
|
|
|
p: cast::transmute(p)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn empty() -> AtomicOption<T> {
|
2013-05-25 19:39:53 -05:00
|
|
|
unsafe {
|
|
|
|
AtomicOption {
|
|
|
|
p: cast::transmute(0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn swap(&mut self, val: ~T, order: Ordering) -> Option<~T> {
|
2013-05-25 19:39:53 -05:00
|
|
|
unsafe {
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
|
|
|
|
let p = atomic_swap(&mut self.p, val, order);
|
|
|
|
let pv : &uint = cast::transmute(&p);
|
|
|
|
|
|
|
|
if *pv == 0 {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(cast::transmute(p))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-06-04 17:37:52 -05:00
|
|
|
pub fn take(&mut self, order: Ordering) -> Option<~T> {
|
2013-05-25 19:39:53 -05:00
|
|
|
unsafe {
|
|
|
|
self.swap(cast::transmute(0), order)
|
|
|
|
}
|
|
|
|
}
|
2013-07-02 12:13:07 -05:00
|
|
|
|
|
|
|
/// A compare-and-swap. Succeeds if the option is 'None' and returns 'None'
|
|
|
|
/// if so. If the option was already 'Some', returns 'Some' of the rejected
|
|
|
|
/// value.
|
|
|
|
#[inline]
|
|
|
|
pub fn fill(&mut self, val: ~T, order: Ordering) -> Option<~T> {
|
|
|
|
unsafe {
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
let expected = cast::transmute(0);
|
|
|
|
let oldval = atomic_compare_and_swap(&mut self.p, expected, val, order);
|
|
|
|
if oldval == expected {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(cast::transmute(val))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Be careful: The caller must have some external method of ensuring the
|
|
|
|
/// result does not get invalidated by another task after this returns.
|
|
|
|
#[inline]
|
|
|
|
pub fn is_empty(&mut self, order: Ordering) -> bool {
|
|
|
|
unsafe { atomic_load(&self.p, order) == cast::transmute(0) }
|
|
|
|
}
|
2013-05-25 19:39:53 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[unsafe_destructor]
|
|
|
|
impl<T> Drop for AtomicOption<T> {
|
2013-06-20 20:06:13 -05:00
|
|
|
fn drop(&self) {
|
2013-05-25 19:39:53 -05:00
|
|
|
// This will ensure that the contained data is
|
|
|
|
// destroyed, unless it's null.
|
|
|
|
unsafe {
|
2013-06-10 17:18:04 -05:00
|
|
|
// FIXME(#4330) Need self by value to get mutability.
|
2013-05-25 19:39:53 -05:00
|
|
|
let this : &mut AtomicOption<T> = cast::transmute(self);
|
|
|
|
let _ = this.take(SeqCst);
|
|
|
|
}
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-05-25 00:51:26 -05:00
|
|
|
pub unsafe fn atomic_store<T>(dst: &mut T, val: T, order:Ordering) {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
|
|
|
|
match order {
|
|
|
|
Release => intrinsics::atomic_store_rel(dst, val),
|
2013-07-23 05:34:40 -05:00
|
|
|
Relaxed => intrinsics::atomic_store_relaxed(dst, val),
|
2013-05-25 00:51:26 -05:00
|
|
|
_ => intrinsics::atomic_store(dst, val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-05-25 00:51:26 -05:00
|
|
|
pub unsafe fn atomic_load<T>(dst: &T, order:Ordering) -> T {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
|
|
|
|
cast::transmute(match order {
|
|
|
|
Acquire => intrinsics::atomic_load_acq(dst),
|
2013-07-23 05:34:40 -05:00
|
|
|
Relaxed => intrinsics::atomic_load_relaxed(dst),
|
2013-05-25 00:51:26 -05:00
|
|
|
_ => intrinsics::atomic_load(dst)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-05-25 00:51:26 -05:00
|
|
|
pub unsafe fn atomic_swap<T>(dst: &mut T, val: T, order: Ordering) -> T {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
|
|
|
|
cast::transmute(match order {
|
|
|
|
Acquire => intrinsics::atomic_xchg_acq(dst, val),
|
|
|
|
Release => intrinsics::atomic_xchg_rel(dst, val),
|
2013-07-23 05:34:40 -05:00
|
|
|
AcqRel => intrinsics::atomic_xchg_acqrel(dst, val),
|
|
|
|
Relaxed => intrinsics::atomic_xchg_relaxed(dst, val),
|
2013-05-25 00:51:26 -05:00
|
|
|
_ => intrinsics::atomic_xchg(dst, val)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2013-06-10 21:13:17 -05:00
|
|
|
/// Returns the old value (like __sync_fetch_and_add).
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-05-25 00:51:26 -05:00
|
|
|
pub unsafe fn atomic_add<T>(dst: &mut T, val: T, order: Ordering) -> T {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
|
|
|
|
cast::transmute(match order {
|
|
|
|
Acquire => intrinsics::atomic_xadd_acq(dst, val),
|
|
|
|
Release => intrinsics::atomic_xadd_rel(dst, val),
|
2013-07-23 05:34:40 -05:00
|
|
|
AcqRel => intrinsics::atomic_xadd_acqrel(dst, val),
|
|
|
|
Relaxed => intrinsics::atomic_xadd_relaxed(dst, val),
|
2013-05-25 00:51:26 -05:00
|
|
|
_ => intrinsics::atomic_xadd(dst, val)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2013-06-10 21:13:17 -05:00
|
|
|
/// Returns the old value (like __sync_fetch_and_sub).
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-05-25 00:51:26 -05:00
|
|
|
pub unsafe fn atomic_sub<T>(dst: &mut T, val: T, order: Ordering) -> T {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
|
|
|
|
cast::transmute(match order {
|
|
|
|
Acquire => intrinsics::atomic_xsub_acq(dst, val),
|
|
|
|
Release => intrinsics::atomic_xsub_rel(dst, val),
|
2013-07-23 05:34:40 -05:00
|
|
|
AcqRel => intrinsics::atomic_xsub_acqrel(dst, val),
|
|
|
|
Relaxed => intrinsics::atomic_xsub_relaxed(dst, val),
|
2013-05-25 00:51:26 -05:00
|
|
|
_ => intrinsics::atomic_xsub(dst, val)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2013-06-18 16:45:18 -05:00
|
|
|
#[inline]
|
2013-05-25 00:51:26 -05:00
|
|
|
pub unsafe fn atomic_compare_and_swap<T>(dst:&mut T, old:T, new:T, order: Ordering) -> T {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
let old = cast::transmute(old);
|
|
|
|
let new = cast::transmute(new);
|
|
|
|
|
|
|
|
cast::transmute(match order {
|
|
|
|
Acquire => intrinsics::atomic_cxchg_acq(dst, old, new),
|
|
|
|
Release => intrinsics::atomic_cxchg_rel(dst, old, new),
|
2013-07-23 05:34:40 -05:00
|
|
|
AcqRel => intrinsics::atomic_cxchg_acqrel(dst, old, new),
|
|
|
|
Relaxed => intrinsics::atomic_cxchg_relaxed(dst, old, new),
|
2013-05-25 00:51:26 -05:00
|
|
|
_ => intrinsics::atomic_cxchg(dst, old, new),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2013-07-25 03:46:31 -05:00
|
|
|
#[inline]
|
|
|
|
pub unsafe fn atomic_and<T>(dst: &mut T, val: T, order: Ordering) -> T {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
|
|
|
|
cast::transmute(match order {
|
|
|
|
Acquire => intrinsics::atomic_and_acq(dst, val),
|
|
|
|
Release => intrinsics::atomic_and_rel(dst, val),
|
|
|
|
AcqRel => intrinsics::atomic_and_acqrel(dst, val),
|
|
|
|
Relaxed => intrinsics::atomic_and_relaxed(dst, val),
|
|
|
|
_ => intrinsics::atomic_and(dst, val)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub unsafe fn atomic_nand<T>(dst: &mut T, val: T, order: Ordering) -> T {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
|
|
|
|
cast::transmute(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),
|
|
|
|
_ => intrinsics::atomic_nand(dst, val)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub unsafe fn atomic_or<T>(dst: &mut T, val: T, order: Ordering) -> T {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
|
|
|
|
cast::transmute(match order {
|
|
|
|
Acquire => intrinsics::atomic_or_acq(dst, val),
|
|
|
|
Release => intrinsics::atomic_or_rel(dst, val),
|
|
|
|
AcqRel => intrinsics::atomic_or_acqrel(dst, val),
|
|
|
|
Relaxed => intrinsics::atomic_or_relaxed(dst, val),
|
|
|
|
_ => intrinsics::atomic_or(dst, val)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub unsafe fn atomic_xor<T>(dst: &mut T, val: T, order: Ordering) -> T {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
|
|
|
|
cast::transmute(match order {
|
|
|
|
Acquire => intrinsics::atomic_xor_acq(dst, val),
|
|
|
|
Release => intrinsics::atomic_xor_rel(dst, val),
|
|
|
|
AcqRel => intrinsics::atomic_xor_acqrel(dst, val),
|
|
|
|
Relaxed => intrinsics::atomic_xor_relaxed(dst, val),
|
|
|
|
_ => intrinsics::atomic_xor(dst, val)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub unsafe fn atomic_max<T>(dst: &mut T, val: T, order: Ordering) -> T {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
|
|
|
|
cast::transmute(match order {
|
|
|
|
Acquire => intrinsics::atomic_max_acq(dst, val),
|
|
|
|
Release => intrinsics::atomic_max_rel(dst, val),
|
|
|
|
AcqRel => intrinsics::atomic_max_acqrel(dst, val),
|
|
|
|
Relaxed => intrinsics::atomic_max_relaxed(dst, val),
|
|
|
|
_ => intrinsics::atomic_max(dst, val)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub unsafe fn atomic_min<T>(dst: &mut T, val: T, order: Ordering) -> T {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
|
|
|
|
cast::transmute(match order {
|
|
|
|
Acquire => intrinsics::atomic_min_acq(dst, val),
|
|
|
|
Release => intrinsics::atomic_min_rel(dst, val),
|
|
|
|
AcqRel => intrinsics::atomic_min_acqrel(dst, val),
|
|
|
|
Relaxed => intrinsics::atomic_min_relaxed(dst, val),
|
|
|
|
_ => intrinsics::atomic_min(dst, val)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub unsafe fn atomic_umax<T>(dst: &mut T, val: T, order: Ordering) -> T {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
|
|
|
|
cast::transmute(match order {
|
|
|
|
Acquire => intrinsics::atomic_umax_acq(dst, val),
|
|
|
|
Release => intrinsics::atomic_umax_rel(dst, val),
|
|
|
|
AcqRel => intrinsics::atomic_umax_acqrel(dst, val),
|
|
|
|
Relaxed => intrinsics::atomic_umax_relaxed(dst, val),
|
|
|
|
_ => intrinsics::atomic_umax(dst, val)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub unsafe fn atomic_umin<T>(dst: &mut T, val: T, order: Ordering) -> T {
|
|
|
|
let dst = cast::transmute(dst);
|
|
|
|
let val = cast::transmute(val);
|
|
|
|
|
|
|
|
cast::transmute(match order {
|
|
|
|
Acquire => intrinsics::atomic_umin_acq(dst, val),
|
|
|
|
Release => intrinsics::atomic_umin_rel(dst, val),
|
|
|
|
AcqRel => intrinsics::atomic_umin_acqrel(dst, val),
|
|
|
|
Relaxed => intrinsics::atomic_umin_relaxed(dst, val),
|
|
|
|
_ => intrinsics::atomic_umin(dst, val)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-25 00:51:26 -05:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
use option::*;
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn flag() {
|
|
|
|
let mut flg = AtomicFlag::new();
|
|
|
|
assert!(!flg.test_and_set(SeqCst));
|
|
|
|
assert!(flg.test_and_set(SeqCst));
|
|
|
|
|
|
|
|
flg.clear(SeqCst);
|
|
|
|
assert!(!flg.test_and_set(SeqCst));
|
|
|
|
}
|
|
|
|
|
2013-07-02 12:13:07 -05:00
|
|
|
#[test]
|
|
|
|
fn option_empty() {
|
|
|
|
assert!(AtomicOption::empty::<()>().is_empty(SeqCst));
|
|
|
|
}
|
|
|
|
|
2013-05-25 00:51:26 -05:00
|
|
|
#[test]
|
2013-05-25 19:39:53 -05:00
|
|
|
fn option_swap() {
|
|
|
|
let mut p = AtomicOption::new(~1);
|
2013-05-25 00:51:26 -05:00
|
|
|
let a = ~2;
|
|
|
|
|
|
|
|
let b = p.swap(a, SeqCst);
|
|
|
|
|
|
|
|
assert_eq!(b, Some(~1));
|
|
|
|
assert_eq!(p.take(SeqCst), Some(~2));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2013-05-25 19:39:53 -05:00
|
|
|
fn option_take() {
|
|
|
|
let mut p = AtomicOption::new(~1);
|
2013-05-25 00:51:26 -05:00
|
|
|
|
|
|
|
assert_eq!(p.take(SeqCst), Some(~1));
|
|
|
|
assert_eq!(p.take(SeqCst), None);
|
|
|
|
|
|
|
|
let p2 = ~2;
|
2013-05-25 19:39:53 -05:00
|
|
|
p.swap(p2, SeqCst);
|
2013-05-25 00:51:26 -05:00
|
|
|
|
|
|
|
assert_eq!(p.take(SeqCst), Some(~2));
|
|
|
|
}
|
|
|
|
|
2013-07-02 12:13:07 -05:00
|
|
|
#[test]
|
|
|
|
fn option_fill() {
|
|
|
|
let mut p = AtomicOption::new(~1);
|
|
|
|
assert!(p.fill(~2, SeqCst).is_some()); // should fail; shouldn't leak!
|
|
|
|
assert_eq!(p.take(SeqCst), Some(~1));
|
|
|
|
|
|
|
|
assert!(p.fill(~2, SeqCst).is_none()); // shouldn't fail
|
|
|
|
assert_eq!(p.take(SeqCst), Some(~2));
|
|
|
|
}
|
2013-07-25 03:46:31 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn bool_and() {
|
|
|
|
let mut a = AtomicBool::new(true);
|
|
|
|
assert_eq!(a.fetch_and(false, SeqCst),true);
|
|
|
|
assert_eq!(a.load(SeqCst),false);
|
|
|
|
}
|
2013-05-25 00:51:26 -05:00
|
|
|
}
|