Skip to content

Add basic atomic types #6732

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 1 commit into from
Closed
Show file tree
Hide file tree
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
343 changes: 343 additions & 0 deletions src/libstd/unstable/atomics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
// 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
*/

use unstable::intrinsics;
use cast;
use option::{Option,Some,None};

pub struct AtomicFlag {
priv v:int
}

pub struct AtomicBool {
priv v:uint
}

pub struct AtomicInt {
priv v:int
}

pub struct AtomicUint {
priv v:uint
}

pub struct AtomicPtr<T> {
priv p:~T
}

pub enum Ordering {
Release,
Acquire,
SeqCst
}


impl AtomicFlag {

fn new() -> AtomicFlag {
AtomicFlag { v: 0 }
}

/**
* Clears the atomic flag
*/
#[inline(always)]
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 {
unsafe {atomic_compare_and_swap(&mut self.v, 0, 1, order) > 0}
}
}

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

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

#[inline(always)]
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 {
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 {
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 }
}
}

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

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

#[inline(always)]
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 {
unsafe { atomic_swap(&mut self.v, val, order) }
}

#[inline(always)]
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 {
unsafe { atomic_add(&mut self.v, val, order) }
}

#[inline(always)]
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 {
AtomicUint { v:v }
}

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

#[inline(always)]
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 {
unsafe { atomic_swap(&mut self.v, val, order) }
}

#[inline(always)]
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 {
unsafe { atomic_add(&mut self.v, val, order) }
}

#[inline(always)]
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> {
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> {
unsafe {
let p = atomic_swap(&mut self.p, ptr, order);
let pv : &uint = cast::transmute(&p);

if *pv == 0 {
None
} else {
Some(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);
}

/**
* Checks to see if the stored pointer has been taken.
*/
fn taken(&self, order:Ordering) -> bool {
unsafe {
let p : ~T = atomic_load(&self.p, order);

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

cast::forget(p);
*pv == 0
}
}
}

#[inline(always)]
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),
_ => intrinsics::atomic_store(dst, val)
}
}

#[inline(always)]
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),
_ => intrinsics::atomic_load(dst)
})
}

#[inline(always)]
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),
_ => intrinsics::atomic_xchg(dst, val)
})
}

#[inline(always)]
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),
_ => intrinsics::atomic_xadd(dst, val)
})
}

#[inline(always)]
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),
_ => intrinsics::atomic_xsub(dst, val)
})
}

#[inline(always)]
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),
_ => intrinsics::atomic_cxchg(dst, old, new),
})
}

#[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));
}

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

let b = p.swap(a, SeqCst);

assert_eq!(b, Some(~1));
assert_eq!(p.take(SeqCst), Some(~2));
}

#[test]
fn pointer_take() {
let mut p = AtomicPtr::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);

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

}
1 change: 1 addition & 0 deletions src/libstd/unstable/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod extfmt;
#[cfg(not(test))]
pub mod lang;
pub mod sync;
pub mod atomics;

/**

Expand Down