Skip to content

Commit a39c294

Browse files
committedMar 19, 2014
auto merge of #12954 : brson/rust/atomicdocs, r=alexcrichton
This adds lots of docs to the atomics module. Two of the examples are using the future atomics API (relying on `Share`) and are ignored temporarily. I discovered a bug in the way AtomicBool's fetch_nand method is implemented and fixed it by using the correct value for `true`. I also fixed the implementation of AcqRel fences (it was only doing a release barrier), and made a "relaxed" fence a failure.
2 parents 87e72c3 + 749e527 commit a39c294

File tree

1 file changed

+393
-68
lines changed

1 file changed

+393
-68
lines changed
 

‎src/libstd/sync/atomics.rs

+393-68
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,104 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
/*!
12-
* Atomic types
13-
*
14-
* Basic atomic types supporting atomic operations. Each method takes an
15-
* `Ordering` which represents the strength of the memory barrier for that
16-
* operation. These orderings are the same as C++11 atomic orderings
17-
* [http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync]
18-
*
19-
* All atomic types are a single word in size.
20-
*/
11+
//! Atomic types
12+
//!
13+
//! Atomic types provide primitive shared-memory communication between
14+
//! threads, and are the building blocks of other concurrent
15+
//! types.
16+
//!
17+
//! This module defines atomic versions of a select number of primitive
18+
//! types, including `AtomicBool`, `AtomicInt`, `AtomicUint`, and `AtomicOption`.
19+
//! Atomic types present operations that, when used correctly, synchronize
20+
//! updates between threads.
21+
//!
22+
//! Each method takes an `Ordering` which represents the strength of
23+
//! the memory barrier for that operation. These orderings are the
24+
//! same as [C++11 atomic orderings][1].
25+
//!
26+
//! [1]: http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync
27+
//!
28+
//! Atomic variables are safe to share between threads (they implement `Share`)
29+
//! but they do not themselves provide the mechanism for sharing. The most
30+
//! common way to share an atomic variable is to put it into an `Arc` (an
31+
//! atomically-reference-counted shared pointer).
32+
//!
33+
//! Most atomic types may be stored in static variables, initialized using
34+
//! the provided static initializers like `INIT_ATOMIC_BOOL`. Atomic statics
35+
//! are often used for lazy global initialization.
36+
//!
37+
//!
38+
//! # Examples
39+
//!
40+
//! A simple spinlock:
41+
//!
42+
//! ```ignore
43+
//! # // FIXME: Needs PR #12430
44+
//! extern crate sync;
45+
//!
46+
//! use sync::Arc;
47+
//! use std::sync::atomics::{AtomicUint, SeqCst};
48+
//! use std::task::deschedule;
49+
//!
50+
//! fn main() {
51+
//! let spinlock = Arc::new(AtomicUint::new(1));
52+
//!
53+
//! let spinlock_clone = spinlock.clone();
54+
//! spawn(proc() {
55+
//! spinlock_clone.store(0, SeqCst);
56+
//! });
57+
//!
58+
//! // Wait for the other task to release the lock
59+
//! while spinlock.load(SeqCst) != 0 {
60+
//! // Since tasks may not be preemptive (if they are green threads)
61+
//! // yield to the scheduler to let the other task run. Low level
62+
//! // concurrent code needs to take into account Rust's two threading
63+
//! // models.
64+
//! deschedule();
65+
//! }
66+
//! }
67+
//! ```
68+
//!
69+
//! Transferring a heap object with `AtomicOption`:
70+
//!
71+
//! ```ignore
72+
//! # // FIXME: Needs PR #12430
73+
//! extern crate sync;
74+
//!
75+
//! use sync::Arc;
76+
//! use std::sync::atomics::{AtomicOption, SeqCst};
77+
//!
78+
//! fn main() {
79+
//! struct BigObject;
80+
//!
81+
//! let shared_big_object = Arc::new(AtomicOption::empty());
82+
//!
83+
//! let shared_big_object_clone = shared_big_object.clone();
84+
//! spawn(proc() {
85+
//! let unwrapped_big_object = shared_big_object_clone.take(SeqCst);
86+
//! if unwrapped_big_object.is_some() {
87+
//! println!("got a big object from another task");
88+
//! } else {
89+
//! println!("other task hasn't sent big object yet");
90+
//! }
91+
//! });
92+
//!
93+
//! shared_big_object.swap(~BigObject, SeqCst);
94+
//! }
95+
//! ```
96+
//!
97+
//! Keep a global count of live tasks:
98+
//!
99+
//! ```
100+
//! use std::sync::atomics::{AtomicUint, SeqCst, INIT_ATOMIC_UINT};
101+
//!
102+
//! static mut GLOBAL_TASK_COUNT: AtomicUint = INIT_ATOMIC_UINT;
103+
//!
104+
//! unsafe {
105+
//! let old_task_count = GLOBAL_TASK_COUNT.fetch_add(1, SeqCst);
106+
//! println!("live tasks: {}", old_task_count + 1);
107+
//! }
108+
//! ```
21109
22110
#[allow(missing_doc)];
23111

@@ -27,165 +115,353 @@ use std::kinds::marker;
27115
use option::{Option,Some,None};
28116
use ops::Drop;
29117

30-
/**
31-
* An atomic boolean type.
32-
*/
118+
/// An atomic boolean type.
33119
pub struct AtomicBool {
34120
priv v: uint,
35121
priv nopod: marker::NoPod
36122
}
37123

38-
/**
39-
* A signed atomic integer type, supporting basic atomic arithmetic operations
40-
*/
124+
/// A signed atomic integer type, supporting basic atomic arithmetic operations
41125
pub struct AtomicInt {
42126
priv v: int,
43127
priv nopod: marker::NoPod
44128
}
45129

46-
/**
47-
* An unsigned atomic integer type, supporting basic atomic arithmetic operations
48-
*/
130+
/// An unsigned atomic integer type, supporting basic atomic arithmetic operations
49131
pub struct AtomicUint {
50132
priv v: uint,
51133
priv nopod: marker::NoPod
52134
}
53135

54-
/**
55-
* An unsigned atomic integer type that is forced to be 64-bits. This does not
56-
* support all operations.
57-
*/
136+
/// An unsigned atomic integer type that is forced to be 64-bits. This does not
137+
/// support all operations.
58138
pub struct AtomicU64 {
59139
priv v: u64,
60140
priv nopod: marker::NoPod
61141
}
62142

63-
/**
64-
* An unsafe atomic pointer. Only supports basic atomic operations
65-
*/
143+
/// An unsafe atomic pointer. Only supports basic atomic operations
66144
pub struct AtomicPtr<T> {
67145
priv p: uint,
68146
priv nopod: marker::NoPod
69147
}
70148

71-
/**
72-
* An owned atomic pointer. Ensures that only a single reference to the data is held at any time.
73-
*/
149+
/// An atomic, nullable unique pointer
150+
///
151+
/// This can be used as the concurrency primitive for operations that transfer
152+
/// owned heap objects across tasks.
74153
#[unsafe_no_drop_flag]
75154
pub struct AtomicOption<T> {
76155
priv p: uint,
77156
}
78157

158+
/// Atomic memory orderings
159+
///
160+
/// Memory orderings limit the ways that both the compiler and CPU may reorder
161+
/// instructions around atomic operations. At its most restrictive,
162+
/// "sequentially consistent" atomics allow neither reads nor writes
163+
/// to be moved either before or after the atomic operation; on the other end
164+
/// "relaxed" atomics allow all reorderings.
165+
///
166+
/// Rust's memory orderings are the same as in C++[1].
167+
///
168+
/// [1]: http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync
79169
pub enum Ordering {
170+
/// No ordering constraints, only atomic operations
80171
Relaxed,
172+
/// When coupled with a store, all previous writes become visible
173+
/// to another thread that performs a load with `Acquire` ordering
174+
/// on the same value
81175
Release,
176+
/// When coupled with a load, all subsequent loads will see data
177+
/// written before a store with `Release` ordering on the same value
178+
/// in another thread
82179
Acquire,
180+
/// When coupled with a load, uses `Acquire` ordering, and with a store
181+
/// `Release` ordering
83182
AcqRel,
183+
/// Like `AcqRel` with the additional guarantee that all threads see all
184+
/// sequentially consistent operations in the same order.
84185
SeqCst
85186
}
86187

188+
/// An `AtomicBool` initialized to `false`
87189
pub static INIT_ATOMIC_BOOL : AtomicBool = AtomicBool { v: 0, nopod: marker::NoPod };
190+
/// An `AtomicInt` initialized to `0`
88191
pub static INIT_ATOMIC_INT : AtomicInt = AtomicInt { v: 0, nopod: marker::NoPod };
192+
/// An `AtomicUint` initialized to `0`
89193
pub static INIT_ATOMIC_UINT : AtomicUint = AtomicUint { v: 0, nopod: marker::NoPod };
194+
/// An `AtomicU64` initialized to `0`
90195
pub static INIT_ATOMIC_U64 : AtomicU64 = AtomicU64 { v: 0, nopod: marker::NoPod };
91196

197+
198+
// NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly
199+
static UINT_TRUE: uint = -1;
200+
92201
impl AtomicBool {
202+
/// Create a new `AtomicBool`
93203
pub fn new(v: bool) -> AtomicBool {
94-
AtomicBool { v: if v { 1 } else { 0 }, nopod: marker::NoPod }
204+
AtomicBool { v: if v { UINT_TRUE } else { 0 }, nopod: marker::NoPod }
95205
}
96206

207+
/// Load the value
97208
#[inline]
98209
pub fn load(&self, order: Ordering) -> bool {
99210
unsafe { atomic_load(&self.v, order) > 0 }
100211
}
101212

213+
/// Store the value
102214
#[inline]
103215
pub fn store(&mut self, val: bool, order: Ordering) {
104-
let val = if val { 1 } else { 0 };
216+
let val = if val { UINT_TRUE } else { 0 };
105217

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

221+
/// Store a value, returning the old value
109222
#[inline]
110223
pub fn swap(&mut self, val: bool, order: Ordering) -> bool {
111-
let val = if val { 1 } else { 0 };
224+
let val = if val { UINT_TRUE } else { 0 };
112225

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

229+
/// If the current value is the same as expected, store a new value
230+
///
231+
/// Compare the current value with `old`; if they are the same then
232+
/// replace the current value with `new`. Return the previous value.
233+
/// If the return value is equal to `old` then the value was updated.
234+
///
235+
/// # Examples
236+
///
237+
/// ```ignore
238+
/// # // FIXME: Needs PR #12430
239+
/// extern crate sync;
240+
///
241+
/// use sync::Arc;
242+
/// use std::sync::atomics::{AtomicBool, SeqCst};
243+
///
244+
/// fn main() {
245+
/// let spinlock = Arc::new(AtomicBool::new(false));
246+
/// let spinlock_clone = spin_lock.clone();
247+
///
248+
/// spawn(proc() {
249+
/// with_lock(&spinlock, || println!("task 1 in lock"));
250+
/// });
251+
///
252+
/// spawn(proc() {
253+
/// with_lock(&spinlock_clone, || println!("task 2 in lock"));
254+
/// });
255+
/// }
256+
///
257+
/// fn with_lock(spinlock: &Arc<AtomicBool>, f: || -> ()) {
258+
/// // CAS loop until we are able to replace `false` with `true`
259+
/// while spinlock.compare_and_swap(false, true, SeqCst) == false {
260+
/// // Since tasks may not be preemptive (if they are green threads)
261+
/// // yield to the scheduler to let the other task run. Low level
262+
/// // concurrent code needs to take into account Rust's two threading
263+
/// // models.
264+
/// deschedule();
265+
/// }
266+
///
267+
/// // Now we have the spinlock
268+
/// f();
269+
///
270+
/// // Release the lock
271+
/// spinlock.store(false);
272+
/// }
273+
/// ```
116274
#[inline]
117275
pub fn compare_and_swap(&mut self, old: bool, new: bool, order: Ordering) -> bool {
118-
let old = if old { 1 } else { 0 };
119-
let new = if new { 1 } else { 0 };
276+
let old = if old { UINT_TRUE } else { 0 };
277+
let new = if new { UINT_TRUE } else { 0 };
120278

121279
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) > 0 }
122280
}
123281

124-
/// Returns the old value
282+
/// A logical "and" operation
283+
///
284+
/// Performs a logical "and" operation on the current value and the
285+
/// argument `val`, and sets the new value to the result.
286+
/// Returns the previous value.
287+
///
288+
/// # Examples
289+
///
290+
/// ```
291+
/// use std::sync::atomics::{AtomicBool, SeqCst};
292+
///
293+
/// let mut foo = AtomicBool::new(true);
294+
/// assert_eq!(true, foo.fetch_and(false, SeqCst));
295+
/// assert_eq!(false, foo.load(SeqCst));
296+
///
297+
/// let mut foo = AtomicBool::new(true);
298+
/// assert_eq!(true, foo.fetch_and(true, SeqCst));
299+
/// assert_eq!(true, foo.load(SeqCst));
300+
///
301+
/// let mut foo = AtomicBool::new(false);
302+
/// assert_eq!(false, foo.fetch_and(false, SeqCst));
303+
/// assert_eq!(false, foo.load(SeqCst));
304+
/// ```
125305
#[inline]
126306
pub fn fetch_and(&mut self, val: bool, order: Ordering) -> bool {
127-
let val = if val { 1 } else { 0 };
307+
let val = if val { UINT_TRUE } else { 0 };
128308

129309
unsafe { atomic_and(&mut self.v, val, order) > 0 }
130310
}
131311

132-
/// Returns the old value
312+
/// A logical "nand" operation
313+
///
314+
/// Performs a logical "nand" operation on the current value and the
315+
/// argument `val`, and sets the new value to the result.
316+
/// Returns the previous value.
317+
///
318+
/// # Examples
319+
///
320+
/// ```
321+
/// use std::sync::atomics::{AtomicBool, SeqCst};
322+
///
323+
/// let mut foo = AtomicBool::new(true);
324+
/// assert_eq!(true, foo.fetch_nand(false, SeqCst));
325+
/// assert_eq!(true, foo.load(SeqCst));
326+
///
327+
/// let mut foo = AtomicBool::new(true);
328+
/// assert_eq!(true, foo.fetch_nand(true, SeqCst));
329+
/// assert_eq!(0, foo.load(SeqCst) as int);
330+
/// assert_eq!(false, foo.load(SeqCst));
331+
///
332+
/// let mut foo = AtomicBool::new(false);
333+
/// assert_eq!(false, foo.fetch_nand(false, SeqCst));
334+
/// assert_eq!(true, foo.load(SeqCst));
335+
/// ```
133336
#[inline]
134337
pub fn fetch_nand(&mut self, val: bool, order: Ordering) -> bool {
135-
let val = if val { 1 } else { 0 };
338+
let val = if val { UINT_TRUE } else { 0 };
136339

137340
unsafe { atomic_nand(&mut self.v, val, order) > 0 }
138341
}
139342

140-
/// Returns the old value
343+
/// A logical "or" operation
344+
///
345+
/// Performs a logical "or" operation on the current value and the
346+
/// argument `val`, and sets the new value to the result.
347+
/// Returns the previous value.
348+
///
349+
/// # Examples
350+
///
351+
/// ```
352+
/// use std::sync::atomics::{AtomicBool, SeqCst};
353+
///
354+
/// let mut foo = AtomicBool::new(true);
355+
/// assert_eq!(true, foo.fetch_or(false, SeqCst));
356+
/// assert_eq!(true, foo.load(SeqCst));
357+
///
358+
/// let mut foo = AtomicBool::new(true);
359+
/// assert_eq!(true, foo.fetch_or(true, SeqCst));
360+
/// assert_eq!(true, foo.load(SeqCst));
361+
///
362+
/// let mut foo = AtomicBool::new(false);
363+
/// assert_eq!(false, foo.fetch_or(false, SeqCst));
364+
/// assert_eq!(false, foo.load(SeqCst));
365+
/// ```
141366
#[inline]
142367
pub fn fetch_or(&mut self, val: bool, order: Ordering) -> bool {
143-
let val = if val { 1 } else { 0 };
368+
let val = if val { UINT_TRUE } else { 0 };
144369

145370
unsafe { atomic_or(&mut self.v, val, order) > 0 }
146371
}
147372

148-
/// Returns the old value
373+
/// A logical "xor" operation
374+
///
375+
/// Performs a logical "xor" operation on the current value and the
376+
/// argument `val`, and sets the new value to the result.
377+
/// Returns the previous value.
378+
///
379+
/// # Examples
380+
///
381+
/// ```
382+
/// use std::sync::atomics::{AtomicBool, SeqCst};
383+
///
384+
/// let mut foo = AtomicBool::new(true);
385+
/// assert_eq!(true, foo.fetch_xor(false, SeqCst));
386+
/// assert_eq!(true, foo.load(SeqCst));
387+
///
388+
/// let mut foo = AtomicBool::new(true);
389+
/// assert_eq!(true, foo.fetch_xor(true, SeqCst));
390+
/// assert_eq!(false, foo.load(SeqCst));
391+
///
392+
/// let mut foo = AtomicBool::new(false);
393+
/// assert_eq!(false, foo.fetch_xor(false, SeqCst));
394+
/// assert_eq!(false, foo.load(SeqCst));
395+
/// ```
149396
#[inline]
150397
pub fn fetch_xor(&mut self, val: bool, order: Ordering) -> bool {
151-
let val = if val { 1 } else { 0 };
398+
let val = if val { UINT_TRUE } else { 0 };
152399

153400
unsafe { atomic_xor(&mut self.v, val, order) > 0 }
154401
}
155402
}
156403

157404
impl AtomicInt {
405+
/// Create a new `AtomicInt`
158406
pub fn new(v: int) -> AtomicInt {
159407
AtomicInt { v:v, nopod: marker::NoPod}
160408
}
161409

410+
/// Load the value
162411
#[inline]
163412
pub fn load(&self, order: Ordering) -> int {
164413
unsafe { atomic_load(&self.v, order) }
165414
}
166415

416+
/// Store the value
167417
#[inline]
168418
pub fn store(&mut self, val: int, order: Ordering) {
169419
unsafe { atomic_store(&mut self.v, val, order); }
170420
}
171421

422+
/// Store a value, returning the old value
172423
#[inline]
173424
pub fn swap(&mut self, val: int, order: Ordering) -> int {
174425
unsafe { atomic_swap(&mut self.v, val, order) }
175426
}
176427

428+
/// If the current value is the same as expected, store a new value
429+
///
430+
/// Compare the current value with `old`; if they are the same then
431+
/// replace the current value with `new`. Return the previous value.
432+
/// If the return value is equal to `old` then the value was updated.
177433
#[inline]
178434
pub fn compare_and_swap(&mut self, old: int, new: int, order: Ordering) -> int {
179435
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) }
180436
}
181437

182-
/// Returns the old value (like __sync_fetch_and_add).
438+
/// Add to the current value, returning the previous
439+
///
440+
/// # Examples
441+
///
442+
/// ```
443+
/// use std::sync::atomics::{AtomicInt, SeqCst};
444+
///
445+
/// let mut foo = AtomicInt::new(0);
446+
/// assert_eq!(0, foo.fetch_add(10, SeqCst));
447+
/// assert_eq!(10, foo.load(SeqCst));
448+
/// ```
183449
#[inline]
184450
pub fn fetch_add(&mut self, val: int, order: Ordering) -> int {
185451
unsafe { atomic_add(&mut self.v, val, order) }
186452
}
187453

188-
/// Returns the old value (like __sync_fetch_and_sub).
454+
/// Subtract from the current value, returning the previous
455+
///
456+
/// # Examples
457+
///
458+
/// ```
459+
/// use std::sync::atomics::{AtomicInt, SeqCst};
460+
///
461+
/// let mut foo = AtomicInt::new(0);
462+
/// assert_eq!(0, foo.fetch_sub(10, SeqCst));
463+
/// assert_eq!(-10, foo.load(SeqCst));
464+
/// ```
189465
#[inline]
190466
pub fn fetch_sub(&mut self, val: int, order: Ordering) -> int {
191467
unsafe { atomic_sub(&mut self.v, val, order) }
@@ -233,65 +509,103 @@ impl AtomicU64 {
233509
}
234510

235511
impl AtomicUint {
512+
/// Create a new `AtomicUint`
236513
pub fn new(v: uint) -> AtomicUint {
237514
AtomicUint { v:v, nopod: marker::NoPod }
238515
}
239516

517+
/// Load the value
240518
#[inline]
241519
pub fn load(&self, order: Ordering) -> uint {
242520
unsafe { atomic_load(&self.v, order) }
243521
}
244522

523+
/// Store the value
245524
#[inline]
246525
pub fn store(&mut self, val: uint, order: Ordering) {
247526
unsafe { atomic_store(&mut self.v, val, order); }
248527
}
249528

529+
/// Store a value, returning the old value
250530
#[inline]
251531
pub fn swap(&mut self, val: uint, order: Ordering) -> uint {
252532
unsafe { atomic_swap(&mut self.v, val, order) }
253533
}
254534

535+
/// If the current value is the same as expected, store a new value
536+
///
537+
/// Compare the current value with `old`; if they are the same then
538+
/// replace the current value with `new`. Return the previous value.
539+
/// If the return value is equal to `old` then the value was updated.
255540
#[inline]
256541
pub fn compare_and_swap(&mut self, old: uint, new: uint, order: Ordering) -> uint {
257542
unsafe { atomic_compare_and_swap(&mut self.v, old, new, order) }
258543
}
259544

260-
/// Returns the old value (like __sync_fetch_and_add).
545+
/// Add to the current value, returning the previous
546+
///
547+
/// # Examples
548+
///
549+
/// ```
550+
/// use std::sync::atomics::{AtomicUint, SeqCst};
551+
///
552+
/// let mut foo = AtomicUint::new(0);
553+
/// assert_eq!(0, foo.fetch_add(10, SeqCst));
554+
/// assert_eq!(10, foo.load(SeqCst));
555+
/// ```
261556
#[inline]
262557
pub fn fetch_add(&mut self, val: uint, order: Ordering) -> uint {
263558
unsafe { atomic_add(&mut self.v, val, order) }
264559
}
265560

266-
/// Returns the old value (like __sync_fetch_and_sub)..
561+
/// Subtract from the current value, returning the previous
562+
///
563+
/// # Examples
564+
///
565+
/// ```
566+
/// use std::sync::atomics::{AtomicUint, SeqCst};
567+
///
568+
/// let mut foo = AtomicUint::new(10);
569+
/// assert_eq!(10, foo.fetch_sub(10, SeqCst));
570+
/// assert_eq!(0, foo.load(SeqCst));
571+
/// ```
267572
#[inline]
268573
pub fn fetch_sub(&mut self, val: uint, order: Ordering) -> uint {
269574
unsafe { atomic_sub(&mut self.v, val, order) }
270575
}
271576
}
272577

273578
impl<T> AtomicPtr<T> {
579+
/// Create a new `AtomicPtr`
274580
pub fn new(p: *mut T) -> AtomicPtr<T> {
275581
AtomicPtr { p: p as uint, nopod: marker::NoPod }
276582
}
277583

584+
/// Load the value
278585
#[inline]
279586
pub fn load(&self, order: Ordering) -> *mut T {
280587
unsafe {
281588
atomic_load(&self.p, order) as *mut T
282589
}
283590
}
284591

592+
/// Store the value
285593
#[inline]
286594
pub fn store(&mut self, ptr: *mut T, order: Ordering) {
287595
unsafe { atomic_store(&mut self.p, ptr as uint, order); }
288596
}
289597

598+
/// Store a value, returning the old value
290599
#[inline]
291600
pub fn swap(&mut self, ptr: *mut T, order: Ordering) -> *mut T {
292601
unsafe { atomic_swap(&mut self.p, ptr as uint, order) as *mut T }
293602
}
294603

604+
/// If the current value is the same as expected, store a new value
605+
///
606+
/// Compare the current value with `old`; if they are the same then
607+
/// replace the current value with `new`. Return the previous value.
608+
/// If the return value is equal to `old` then the value was updated.
295609
#[inline]
296610
pub fn compare_and_swap(&mut self, old: *mut T, new: *mut T, order: Ordering) -> *mut T {
297611
unsafe {
@@ -302,12 +616,15 @@ impl<T> AtomicPtr<T> {
302616
}
303617

304618
impl<T> AtomicOption<T> {
619+
/// Create a new `AtomicOption`
305620
pub fn new(p: ~T) -> AtomicOption<T> {
306621
unsafe { AtomicOption { p: cast::transmute(p) } }
307622
}
308623

624+
/// Create a new `AtomicOption` that doesn't contain a value
309625
pub fn empty() -> AtomicOption<T> { AtomicOption { p: 0 } }
310626

627+
/// Store a value, returning the old value
311628
#[inline]
312629
pub fn swap(&mut self, val: ~T, order: Ordering) -> Option<~T> {
313630
unsafe {
@@ -322,13 +639,16 @@ impl<T> AtomicOption<T> {
322639
}
323640
}
324641

642+
/// Remove the value, leaving the `AtomicOption` empty.
325643
#[inline]
326644
pub fn take(&mut self, order: Ordering) -> Option<~T> {
327645
unsafe { self.swap(cast::transmute(0), order) }
328646
}
329647

330-
/// A compare-and-swap. Succeeds if the option is 'None' and returns 'None'
331-
/// if so. If the option was already 'Some', returns 'Some' of the rejected
648+
/// Replace an empty value with a non-empty value.
649+
///
650+
/// Succeeds if the option is `None` and returns `None` if so. If
651+
/// the option was already `Some`, returns `Some` of the rejected
332652
/// value.
333653
#[inline]
334654
pub fn fill(&mut self, val: ~T, order: Ordering) -> Option<~T> {
@@ -344,6 +664,8 @@ impl<T> AtomicOption<T> {
344664
}
345665
}
346666

667+
/// Returns `true` if the `AtomicOption` is empty.
668+
///
347669
/// Be careful: The caller must have some external method of ensuring the
348670
/// result does not get invalidated by another task after this returns.
349671
#[inline]
@@ -470,32 +792,35 @@ pub unsafe fn atomic_xor<T>(dst: &mut T, val: T, order: Ordering) -> T {
470792
}
471793

472794

473-
/**
474-
* An atomic fence.
475-
*
476-
* A fence 'A' which has `Release` ordering semantics, synchronizes with a
477-
* fence 'B' with (at least) `Acquire` semantics, if and only if there exists
478-
* atomic operations X and Y, both operating on some atomic object 'M' such
479-
* that A is sequenced before X, Y is synchronized before B and Y observers
480-
* the change to M. This provides a happens-before dependence between A and B.
481-
*
482-
* Atomic operations with `Release` or `Acquire` semantics can also synchronize
483-
* with a fence.
484-
*
485-
* A fence with has `SeqCst` ordering, in addition to having both `Acquire` and
486-
* `Release` semantics, participates in the global program order of the other
487-
* `SeqCst` operations and/or fences.
488-
*
489-
* Accepts `Acquire`, `Release`, `AcqRel` and `SeqCst` orderings.
490-
*/
795+
/// An atomic fence.
796+
///
797+
/// A fence 'A' which has `Release` ordering semantics, synchronizes with a
798+
/// fence 'B' with (at least) `Acquire` semantics, if and only if there exists
799+
/// atomic operations X and Y, both operating on some atomic object 'M' such
800+
/// that A is sequenced before X, Y is synchronized before B and Y observers
801+
/// the change to M. This provides a happens-before dependence between A and B.
802+
///
803+
/// Atomic operations with `Release` or `Acquire` semantics can also synchronize
804+
/// with a fence.
805+
///
806+
/// A fence with has `SeqCst` ordering, in addition to having both `Acquire` and
807+
/// `Release` semantics, participates in the global program order of the other
808+
/// `SeqCst` operations and/or fences.
809+
///
810+
/// Accepts `Acquire`, `Release`, `AcqRel` and `SeqCst` orderings.
811+
///
812+
/// # Failure
813+
///
814+
/// Fails if `order` is `Relaxed`
491815
#[inline]
492816
pub fn fence(order: Ordering) {
493817
unsafe {
494818
match order {
495819
Acquire => intrinsics::atomic_fence_acq(),
496820
Release => intrinsics::atomic_fence_rel(),
497-
AcqRel => intrinsics::atomic_fence_rel(),
498-
_ => intrinsics::atomic_fence(),
821+
AcqRel => intrinsics::atomic_fence_acqrel(),
822+
SeqCst => intrinsics::atomic_fence(),
823+
Relaxed => fail!("there is no such thing as a relaxed fence")
499824
}
500825
}
501826
}

0 commit comments

Comments
 (0)
Please sign in to comment.