Skip to content

More Atomic types #6740

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

Closed
wants to merge 3 commits into from
Closed
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
186 changes: 118 additions & 68 deletions src/libstd/unstable/atomics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,60 @@

/*!
* Atomic types
*
* 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.
*/

use unstable::intrinsics;
use cast;
use option::{Option,Some,None};
use libc::c_void;
use ops::Drop;

/**
* A simple atomic flag, that can be set and cleared. The most basic atomic type.
*/
pub struct AtomicFlag {
priv v:int
priv v: int
}

/**
* An atomic boolean type.
*/
pub struct AtomicBool {
priv v:uint
priv v: uint
}

/**
* A signed atomic integer type, supporting basic atomic aritmetic operations
*/
pub struct AtomicInt {
priv v:int
priv v: int
}

/**
* An unsigned atomic integer type, supporting basic atomic aritmetic operations
*/
pub struct AtomicUint {
priv v:uint
priv v: uint
}

/**
* An unsafe atomic pointer. Only supports basic atomic operations
*/
pub struct AtomicPtr<T> {
priv p:~T
priv p: *mut T
}

/**
* An owned atomic pointer. Ensures that only a single reference to the data is held at any time.
*/
pub struct AtomicOption<T> {
priv p: *mut c_void
}

pub enum Ordering {
Expand All @@ -53,46 +83,46 @@ impl AtomicFlag {
* Clears the atomic flag
*/
#[inline(always)]
fn clear(&mut self, order:Ordering) {
fn clear(&mut self, order: Ordering) {
unsafe {atomic_store(&mut self.v, 0, order)}
}

#[inline(always)]
/**
* Sets the flag if it was previously unset, returns the previous value of the
* flag.
*/
fn test_and_set(&mut self, order:Ordering) -> bool {
#[inline(always)]
fn test_and_set(&mut self, order: Ordering) -> bool {
unsafe {atomic_compare_and_swap(&mut self.v, 0, 1, order) > 0}
}
}

impl AtomicBool {
fn new(v:bool) -> AtomicBool {
fn new(v: bool) -> AtomicBool {
AtomicBool { v: if v { 1 } else { 0 } }
}

#[inline(always)]
fn load(&self, order:Ordering) -> bool {
fn load(&self, order: Ordering) -> bool {
unsafe { atomic_load(&self.v, order) > 0 }
}

#[inline(always)]
fn store(&mut self, val:bool, order:Ordering) {
fn store(&mut self, val: bool, order: Ordering) {
let val = if val { 1 } else { 0 };

unsafe { atomic_store(&mut self.v, val, order); }
}

#[inline(always)]
fn swap(&mut self, val:bool, order:Ordering) -> bool {
fn swap(&mut self, val: bool, order: Ordering) -> bool {
let val = if val { 1 } else { 0 };

unsafe { atomic_swap(&mut self.v, val, order) > 0}
}

#[inline(always)]
fn compare_and_swap(&mut self, old: bool, new: bool, order:Ordering) -> bool {
fn compare_and_swap(&mut self, old: bool, new: bool, order: Ordering) -> bool {
let old = if old { 1 } else { 0 };
let new = if new { 1 } else { 0 };

Expand All @@ -101,131 +131,152 @@ impl AtomicBool {
}

impl AtomicInt {
fn new(v:int) -> AtomicInt {
fn new(v: int) -> AtomicInt {
AtomicInt { v:v }
}

#[inline(always)]
fn load(&self, order:Ordering) -> int {
fn load(&self, order: Ordering) -> int {
unsafe { atomic_load(&self.v, order) }
}

#[inline(always)]
fn store(&mut self, val:int, order:Ordering) {
fn store(&mut self, val: int, order: Ordering) {
unsafe { atomic_store(&mut self.v, val, order); }
}

#[inline(always)]
fn swap(&mut self, val:int, order:Ordering) -> int {
fn swap(&mut self, val: int, order: Ordering) -> int {
unsafe { atomic_swap(&mut self.v, val, order) }
}

#[inline(always)]
fn compare_and_swap(&mut self, old: int, new: int, order:Ordering) -> int {
fn compare_and_swap(&mut self, old: int, new: int, order: Ordering) -> int {
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) }
}

#[inline(always)]
fn fetch_add(&mut self, val:int, order:Ordering) -> int {
fn fetch_add(&mut self, val: int, order: Ordering) -> int {
unsafe { atomic_add(&mut self.v, val, order) }
}

#[inline(always)]
fn fetch_sub(&mut self, val:int, order:Ordering) -> int {
fn fetch_sub(&mut self, val: int, order: Ordering) -> int {
unsafe { atomic_sub(&mut self.v, val, order) }
}
}

impl AtomicUint {
fn new(v:uint) -> AtomicUint {
fn new(v: uint) -> AtomicUint {
AtomicUint { v:v }
}

#[inline(always)]
fn load(&self, order:Ordering) -> uint {
fn load(&self, order: Ordering) -> uint {
unsafe { atomic_load(&self.v, order) }
}

#[inline(always)]
fn store(&mut self, val:uint, order:Ordering) {
fn store(&mut self, val: uint, order: Ordering) {
unsafe { atomic_store(&mut self.v, val, order); }
}

#[inline(always)]
fn swap(&mut self, val:uint, order:Ordering) -> uint {
fn swap(&mut self, val: uint, order: Ordering) -> uint {
unsafe { atomic_swap(&mut self.v, val, order) }
}

#[inline(always)]
fn compare_and_swap(&mut self, old: uint, new: uint, order:Ordering) -> uint {
fn compare_and_swap(&mut self, old: uint, new: uint, order: Ordering) -> uint {
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) }
}

#[inline(always)]
fn fetch_add(&mut self, val:uint, order:Ordering) -> uint {
fn fetch_add(&mut self, val: uint, order: Ordering) -> uint {
unsafe { atomic_add(&mut self.v, val, order) }
}

#[inline(always)]
fn fetch_sub(&mut self, val:uint, order:Ordering) -> uint {
fn fetch_sub(&mut self, val: uint, order: Ordering) -> uint {
unsafe { atomic_sub(&mut self.v, val, order) }
}
}

impl<T> AtomicPtr<T> {
fn new(p:~T) -> AtomicPtr<T> {
fn new(p: *mut T) -> AtomicPtr<T> {
AtomicPtr { p:p }
}

/**
* Atomically swaps the stored pointer with the one given.
*
* Returns None if the pointer stored has been taken
*/
#[inline(always)]
fn swap(&mut self, ptr:~T, order:Ordering) -> Option<~T> {
fn load(&self, order: Ordering) -> *mut T {
unsafe { atomic_load(&self.p, order) }
}

#[inline(always)]
fn store(&mut self, ptr: *mut T, order: Ordering) {
unsafe { atomic_store(&mut self.p, ptr, order); }
}

#[inline(always)]
fn swap(&mut self, ptr: *mut T, order: Ordering) -> *mut T {
unsafe { atomic_swap(&mut self.p, ptr, order) }
}

#[inline(always)]
fn compare_and_swap(&mut self, old: *mut T, new: *mut T, order: Ordering) -> *mut T {
unsafe { atomic_compare_and_swap(&mut self.p, old, new, order) }
}
}

impl<T> AtomicOption<T> {
fn new(p: ~T) -> AtomicOption<T> {
unsafe {
let p = atomic_swap(&mut self.p, ptr, order);
AtomicOption {
p: cast::transmute(p)
}
}
}

fn empty() -> AtomicOption<T> {
unsafe {
AtomicOption {
p: cast::transmute(0)
}
}
}

#[inline(always)]
fn swap(&mut self, val: ~T, order: Ordering) -> Option<~T> {
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(p)
Some(cast::transmute(p))
}
}
}

/**
* Atomically takes the stored pointer out.
*
* Returns None if it was already taken.
*/
#[inline(always)]
fn take(&mut self, order:Ordering) -> Option<~T> {
unsafe { self.swap(cast::transmute(0), order) }
}

/**
* Atomically stores the given pointer, this will overwrite
* and previous value stored.
*/
#[inline(always)]
fn give(&mut self, ptr:~T, order:Ordering) {
let _ = self.swap(ptr, order);
fn take(&mut self, order: Ordering) -> Option<~T> {
unsafe {
self.swap(cast::transmute(0), order)
}
}
}

/**
* Checks to see if the stored pointer has been taken.
*/
fn taken(&self, order:Ordering) -> bool {
#[unsafe_destructor]
impl<T> Drop for AtomicOption<T> {
fn finalize(&self) {
// This will ensure that the contained data is
// destroyed, unless it's null.
unsafe {
let p : ~T = atomic_load(&self.p, order);

let pv : &uint = cast::transmute(&p);

cast::forget(p);
*pv == 0
let this : &mut AtomicOption<T> = cast::transmute(self);
let _ = this.take(SeqCst);
}
}
}
Expand Down Expand Up @@ -316,8 +367,8 @@ mod test {
}

#[test]
fn pointer_swap() {
let mut p = AtomicPtr::new(~1);
fn option_swap() {
let mut p = AtomicOption::new(~1);
let a = ~2;

let b = p.swap(a, SeqCst);
Expand All @@ -327,15 +378,14 @@ mod test {
}

#[test]
fn pointer_take() {
let mut p = AtomicPtr::new(~1);
fn option_take() {
let mut p = AtomicOption::new(~1);

assert_eq!(p.take(SeqCst), Some(~1));
assert_eq!(p.take(SeqCst), None);
assert!(p.taken(SeqCst));

let p2 = ~2;
p.give(p2, SeqCst);
p.swap(p2, SeqCst);

assert_eq!(p.take(SeqCst), Some(~2));
}
Expand Down