Skip to content

Commit 2706271

Browse files
committed
auto merge of #6732 : Aatch/rust/atomic-types, r=brson
This pull request is more of an RFC than a finished implementation. It adds some basic atomic types, with an interface modelled off of C++11's atomic types. It also adds free functions that provide a slightly nicer interface for atomic operations, though they are unsafe because there isn't a way to be generic over "word-sized" types. See also #5042
2 parents 9d37d03 + 5233604 commit 2706271

File tree

2 files changed

+344
-0
lines changed

2 files changed

+344
-0
lines changed

src/libstd/unstable/atomics.rs

+343
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
/*!
12+
* Atomic types
13+
*/
14+
15+
use unstable::intrinsics;
16+
use cast;
17+
use option::{Option,Some,None};
18+
19+
pub struct AtomicFlag {
20+
priv v:int
21+
}
22+
23+
pub struct AtomicBool {
24+
priv v:uint
25+
}
26+
27+
pub struct AtomicInt {
28+
priv v:int
29+
}
30+
31+
pub struct AtomicUint {
32+
priv v:uint
33+
}
34+
35+
pub struct AtomicPtr<T> {
36+
priv p:~T
37+
}
38+
39+
pub enum Ordering {
40+
Release,
41+
Acquire,
42+
SeqCst
43+
}
44+
45+
46+
impl AtomicFlag {
47+
48+
fn new() -> AtomicFlag {
49+
AtomicFlag { v: 0 }
50+
}
51+
52+
/**
53+
* Clears the atomic flag
54+
*/
55+
#[inline(always)]
56+
fn clear(&mut self, order:Ordering) {
57+
unsafe {atomic_store(&mut self.v, 0, order)}
58+
}
59+
60+
#[inline(always)]
61+
/**
62+
* Sets the flag if it was previously unset, returns the previous value of the
63+
* flag.
64+
*/
65+
fn test_and_set(&mut self, order:Ordering) -> bool {
66+
unsafe {atomic_compare_and_swap(&mut self.v, 0, 1, order) > 0}
67+
}
68+
}
69+
70+
impl AtomicBool {
71+
fn new(v:bool) -> AtomicBool {
72+
AtomicBool { v: if v { 1 } else { 0 } }
73+
}
74+
75+
#[inline(always)]
76+
fn load(&self, order:Ordering) -> bool {
77+
unsafe { atomic_load(&self.v, order) > 0 }
78+
}
79+
80+
#[inline(always)]
81+
fn store(&mut self, val:bool, order:Ordering) {
82+
let val = if val { 1 } else { 0 };
83+
84+
unsafe { atomic_store(&mut self.v, val, order); }
85+
}
86+
87+
#[inline(always)]
88+
fn swap(&mut self, val:bool, order:Ordering) -> bool {
89+
let val = if val { 1 } else { 0 };
90+
91+
unsafe { atomic_swap(&mut self.v, val, order) > 0}
92+
}
93+
94+
#[inline(always)]
95+
fn compare_and_swap(&mut self, old: bool, new: bool, order:Ordering) -> bool {
96+
let old = if old { 1 } else { 0 };
97+
let new = if new { 1 } else { 0 };
98+
99+
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) > 0 }
100+
}
101+
}
102+
103+
impl AtomicInt {
104+
fn new(v:int) -> AtomicInt {
105+
AtomicInt { v:v }
106+
}
107+
108+
#[inline(always)]
109+
fn load(&self, order:Ordering) -> int {
110+
unsafe { atomic_load(&self.v, order) }
111+
}
112+
113+
#[inline(always)]
114+
fn store(&mut self, val:int, order:Ordering) {
115+
unsafe { atomic_store(&mut self.v, val, order); }
116+
}
117+
118+
#[inline(always)]
119+
fn swap(&mut self, val:int, order:Ordering) -> int {
120+
unsafe { atomic_swap(&mut self.v, val, order) }
121+
}
122+
123+
#[inline(always)]
124+
fn compare_and_swap(&mut self, old: int, new: int, order:Ordering) -> int {
125+
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) }
126+
}
127+
128+
#[inline(always)]
129+
fn fetch_add(&mut self, val:int, order:Ordering) -> int {
130+
unsafe { atomic_add(&mut self.v, val, order) }
131+
}
132+
133+
#[inline(always)]
134+
fn fetch_sub(&mut self, val:int, order:Ordering) -> int {
135+
unsafe { atomic_sub(&mut self.v, val, order) }
136+
}
137+
}
138+
139+
impl AtomicUint {
140+
fn new(v:uint) -> AtomicUint {
141+
AtomicUint { v:v }
142+
}
143+
144+
#[inline(always)]
145+
fn load(&self, order:Ordering) -> uint {
146+
unsafe { atomic_load(&self.v, order) }
147+
}
148+
149+
#[inline(always)]
150+
fn store(&mut self, val:uint, order:Ordering) {
151+
unsafe { atomic_store(&mut self.v, val, order); }
152+
}
153+
154+
#[inline(always)]
155+
fn swap(&mut self, val:uint, order:Ordering) -> uint {
156+
unsafe { atomic_swap(&mut self.v, val, order) }
157+
}
158+
159+
#[inline(always)]
160+
fn compare_and_swap(&mut self, old: uint, new: uint, order:Ordering) -> uint {
161+
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) }
162+
}
163+
164+
#[inline(always)]
165+
fn fetch_add(&mut self, val:uint, order:Ordering) -> uint {
166+
unsafe { atomic_add(&mut self.v, val, order) }
167+
}
168+
169+
#[inline(always)]
170+
fn fetch_sub(&mut self, val:uint, order:Ordering) -> uint {
171+
unsafe { atomic_sub(&mut self.v, val, order) }
172+
}
173+
}
174+
175+
impl<T> AtomicPtr<T> {
176+
fn new(p:~T) -> AtomicPtr<T> {
177+
AtomicPtr { p:p }
178+
}
179+
180+
/**
181+
* Atomically swaps the stored pointer with the one given.
182+
*
183+
* Returns None if the pointer stored has been taken
184+
*/
185+
#[inline(always)]
186+
fn swap(&mut self, ptr:~T, order:Ordering) -> Option<~T> {
187+
unsafe {
188+
let p = atomic_swap(&mut self.p, ptr, order);
189+
let pv : &uint = cast::transmute(&p);
190+
191+
if *pv == 0 {
192+
None
193+
} else {
194+
Some(p)
195+
}
196+
}
197+
}
198+
199+
/**
200+
* Atomically takes the stored pointer out.
201+
*
202+
* Returns None if it was already taken.
203+
*/
204+
#[inline(always)]
205+
fn take(&mut self, order:Ordering) -> Option<~T> {
206+
unsafe { self.swap(cast::transmute(0), order) }
207+
}
208+
209+
/**
210+
* Atomically stores the given pointer, this will overwrite
211+
* and previous value stored.
212+
*/
213+
#[inline(always)]
214+
fn give(&mut self, ptr:~T, order:Ordering) {
215+
let _ = self.swap(ptr, order);
216+
}
217+
218+
/**
219+
* Checks to see if the stored pointer has been taken.
220+
*/
221+
fn taken(&self, order:Ordering) -> bool {
222+
unsafe {
223+
let p : ~T = atomic_load(&self.p, order);
224+
225+
let pv : &uint = cast::transmute(&p);
226+
227+
cast::forget(p);
228+
*pv == 0
229+
}
230+
}
231+
}
232+
233+
#[inline(always)]
234+
pub unsafe fn atomic_store<T>(dst: &mut T, val: T, order:Ordering) {
235+
let dst = cast::transmute(dst);
236+
let val = cast::transmute(val);
237+
238+
match order {
239+
Release => intrinsics::atomic_store_rel(dst, val),
240+
_ => intrinsics::atomic_store(dst, val)
241+
}
242+
}
243+
244+
#[inline(always)]
245+
pub unsafe fn atomic_load<T>(dst: &T, order:Ordering) -> T {
246+
let dst = cast::transmute(dst);
247+
248+
cast::transmute(match order {
249+
Acquire => intrinsics::atomic_load_acq(dst),
250+
_ => intrinsics::atomic_load(dst)
251+
})
252+
}
253+
254+
#[inline(always)]
255+
pub unsafe fn atomic_swap<T>(dst: &mut T, val: T, order: Ordering) -> T {
256+
let dst = cast::transmute(dst);
257+
let val = cast::transmute(val);
258+
259+
cast::transmute(match order {
260+
Acquire => intrinsics::atomic_xchg_acq(dst, val),
261+
Release => intrinsics::atomic_xchg_rel(dst, val),
262+
_ => intrinsics::atomic_xchg(dst, val)
263+
})
264+
}
265+
266+
#[inline(always)]
267+
pub unsafe fn atomic_add<T>(dst: &mut T, val: T, order: Ordering) -> T {
268+
let dst = cast::transmute(dst);
269+
let val = cast::transmute(val);
270+
271+
cast::transmute(match order {
272+
Acquire => intrinsics::atomic_xadd_acq(dst, val),
273+
Release => intrinsics::atomic_xadd_rel(dst, val),
274+
_ => intrinsics::atomic_xadd(dst, val)
275+
})
276+
}
277+
278+
#[inline(always)]
279+
pub unsafe fn atomic_sub<T>(dst: &mut T, val: T, order: Ordering) -> T {
280+
let dst = cast::transmute(dst);
281+
let val = cast::transmute(val);
282+
283+
cast::transmute(match order {
284+
Acquire => intrinsics::atomic_xsub_acq(dst, val),
285+
Release => intrinsics::atomic_xsub_rel(dst, val),
286+
_ => intrinsics::atomic_xsub(dst, val)
287+
})
288+
}
289+
290+
#[inline(always)]
291+
pub unsafe fn atomic_compare_and_swap<T>(dst:&mut T, old:T, new:T, order: Ordering) -> T {
292+
let dst = cast::transmute(dst);
293+
let old = cast::transmute(old);
294+
let new = cast::transmute(new);
295+
296+
cast::transmute(match order {
297+
Acquire => intrinsics::atomic_cxchg_acq(dst, old, new),
298+
Release => intrinsics::atomic_cxchg_rel(dst, old, new),
299+
_ => intrinsics::atomic_cxchg(dst, old, new),
300+
})
301+
}
302+
303+
#[cfg(test)]
304+
mod test {
305+
use option::*;
306+
use super::*;
307+
308+
#[test]
309+
fn flag() {
310+
let mut flg = AtomicFlag::new();
311+
assert!(!flg.test_and_set(SeqCst));
312+
assert!(flg.test_and_set(SeqCst));
313+
314+
flg.clear(SeqCst);
315+
assert!(!flg.test_and_set(SeqCst));
316+
}
317+
318+
#[test]
319+
fn pointer_swap() {
320+
let mut p = AtomicPtr::new(~1);
321+
let a = ~2;
322+
323+
let b = p.swap(a, SeqCst);
324+
325+
assert_eq!(b, Some(~1));
326+
assert_eq!(p.take(SeqCst), Some(~2));
327+
}
328+
329+
#[test]
330+
fn pointer_take() {
331+
let mut p = AtomicPtr::new(~1);
332+
333+
assert_eq!(p.take(SeqCst), Some(~1));
334+
assert_eq!(p.take(SeqCst), None);
335+
assert!(p.taken(SeqCst));
336+
337+
let p2 = ~2;
338+
p.give(p2, SeqCst);
339+
340+
assert_eq!(p.take(SeqCst), Some(~2));
341+
}
342+
343+
}

src/libstd/unstable/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub mod extfmt;
2525
#[cfg(not(test))]
2626
pub mod lang;
2727
pub mod sync;
28+
pub mod atomics;
2829

2930
/**
3031

0 commit comments

Comments
 (0)