]> git.lizzy.rs Git - rust.git/blob - src/libstd/sync/atomics_stage0.rs
rand: Use fill() instead of read()
[rust.git] / src / libstd / sync / atomics_stage0.rs
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 //! 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 //! ```
109
110 #[allow(missing_doc)];
111
112 use intrinsics;
113 use cast;
114 use std::kinds::marker;
115 use option::{Option,Some,None};
116 use ops::Drop;
117 use ty::Unsafe;
118
119 /// An atomic boolean type.
120 pub struct AtomicBool {
121     priv v: Unsafe<uint>,
122     priv nopod: marker::NoPod
123 }
124
125 /// A signed atomic integer type, supporting basic atomic arithmetic operations
126 pub struct AtomicInt {
127     priv v: Unsafe<int>,
128     priv nopod: marker::NoPod
129 }
130
131 /// An unsigned atomic integer type, supporting basic atomic arithmetic operations
132 pub struct AtomicUint {
133     priv v: Unsafe<uint>,
134     priv nopod: marker::NoPod
135 }
136
137 /// An unsigned atomic integer type that is forced to be 64-bits. This does not
138 /// support all operations.
139 pub struct AtomicU64 {
140     priv v: Unsafe<u64>,
141     priv nopod: marker::NoPod
142 }
143
144 /// An unsafe atomic pointer. Only supports basic atomic operations
145 pub struct AtomicPtr<T> {
146     priv p: Unsafe<uint>,
147     priv nopod: marker::NoPod
148 }
149
150 /// An atomic, nullable unique pointer
151 ///
152 /// This can be used as the concurrency primitive for operations that transfer
153 /// owned heap objects across tasks.
154 #[unsafe_no_drop_flag]
155 pub struct AtomicOption<T> {
156     priv p: Unsafe<uint>,
157 }
158
159 /// Atomic memory orderings
160 ///
161 /// Memory orderings limit the ways that both the compiler and CPU may reorder
162 /// instructions around atomic operations. At its most restrictive,
163 /// "sequentially consistent" atomics allow neither reads nor writes
164 /// to be moved either before or after the atomic operation; on the other end
165 /// "relaxed" atomics allow all reorderings.
166 ///
167 /// Rust's memory orderings are the same as in C++[1].
168 ///
169 /// [1]: http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync
170 pub enum Ordering {
171     /// No ordering constraints, only atomic operations
172     Relaxed,
173     /// When coupled with a store, all previous writes become visible
174     /// to another thread that performs a load with `Acquire` ordering
175     /// on the same value
176     Release,
177     /// When coupled with a load, all subsequent loads will see data
178     /// written before a store with `Release` ordering on the same value
179     /// in another thread
180     Acquire,
181     /// When coupled with a load, uses `Acquire` ordering, and with a store
182     /// `Release` ordering
183     AcqRel,
184     /// Like `AcqRel` with the additional guarantee that all threads see all
185     /// sequentially consistent operations in the same order.
186     SeqCst
187 }
188
189 /// An `AtomicBool` initialized to `false`
190 pub static INIT_ATOMIC_BOOL : AtomicBool = AtomicBool { v: Unsafe{value: 0,
191                                                                   marker1: marker::InvariantType},
192                                                         nopod: marker::NoPod };
193 /// An `AtomicInt` initialized to `0`
194 pub static INIT_ATOMIC_INT  : AtomicInt  = AtomicInt  { v: Unsafe{value: 0,
195                                                                   marker1: marker::InvariantType},
196                                                         nopod: marker::NoPod };
197 /// An `AtomicUint` initialized to `0`
198 pub static INIT_ATOMIC_UINT : AtomicUint = AtomicUint { v: Unsafe{value: 0,
199                                                                   marker1: marker::InvariantType},
200                                                         nopod: marker::NoPod };
201 /// An `AtomicU64` initialized to `0`
202 pub static INIT_ATOMIC_U64 : AtomicU64 = AtomicU64 { v: Unsafe{value: 0,
203                                                                marker1: marker::InvariantType},
204                                                      nopod: marker::NoPod };
205
206
207 // NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly
208 static UINT_TRUE: uint = -1;
209
210 impl AtomicBool {
211     /// Create a new `AtomicBool`
212     pub fn new(v: bool) -> AtomicBool {
213         let val = if v { UINT_TRUE } else { 0 };
214         AtomicBool { v: Unsafe::new(val), nopod: marker::NoPod }
215     }
216
217     /// Load the value
218     #[inline]
219     pub fn load(&self, order: Ordering) -> bool {
220         unsafe { atomic_load(&*self.v.get(), order) > 0 }
221     }
222
223     /// Store the value
224     #[inline]
225     pub fn store(&mut self, val: bool, order: Ordering) {
226         let val = if val { UINT_TRUE } else { 0 };
227
228         unsafe { atomic_store(&mut *self.v.get(), val, order); }
229     }
230
231     /// Store a value, returning the old value
232     #[inline]
233     pub fn swap(&mut self, val: bool, order: Ordering) -> bool {
234         let val = if val { UINT_TRUE } else { 0 };
235
236         unsafe { atomic_swap(&mut *self.v.get(), val, order) > 0 }
237     }
238
239     /// If the current value is the same as expected, store a new value
240     ///
241     /// Compare the current value with `old`; if they are the same then
242     /// replace the current value with `new`. Return the previous value.
243     /// If the return value is equal to `old` then the value was updated.
244     ///
245     /// # Examples
246     ///
247     /// ```ignore
248     /// # // FIXME: Needs PR #12430
249     /// extern crate sync;
250     ///
251     /// use sync::Arc;
252     /// use std::sync::atomics::{AtomicBool, SeqCst};
253     ///
254     /// fn main() {
255     ///     let spinlock = Arc::new(AtomicBool::new(false));
256     ///     let spinlock_clone = spin_lock.clone();
257     ///
258     ///     spawn(proc() {
259     ///         with_lock(&spinlock, || println!("task 1 in lock"));
260     ///     });
261     ///
262     ///     spawn(proc() {
263     ///         with_lock(&spinlock_clone, || println!("task 2 in lock"));
264     ///     });
265     /// }
266     ///
267     /// fn with_lock(spinlock: &Arc<AtomicBool>, f: || -> ()) {
268     ///     // CAS loop until we are able to replace `false` with `true`
269     ///     while spinlock.compare_and_swap(false, true, SeqCst) == false {
270     ///         // Since tasks may not be preemptive (if they are green threads)
271     ///         // yield to the scheduler to let the other task run. Low level
272     ///         // concurrent code needs to take into account Rust's two threading
273     ///         // models.
274     ///         deschedule();
275     ///     }
276     ///
277     ///     // Now we have the spinlock
278     ///     f();
279     ///
280     ///     // Release the lock
281     ///     spinlock.store(false);
282     /// }
283     /// ```
284     #[inline]
285     pub fn compare_and_swap(&mut self, old: bool, new: bool, order: Ordering) -> bool {
286         let old = if old { UINT_TRUE } else { 0 };
287         let new = if new { UINT_TRUE } else { 0 };
288
289         unsafe { atomic_compare_and_swap(&mut *self.v.get(), old, new, order) > 0 }
290     }
291
292     /// A logical "and" operation
293     ///
294     /// Performs a logical "and" operation on the current value and the
295     /// argument `val`, and sets the new value to the result.
296     /// Returns the previous value.
297     ///
298     /// # Examples
299     ///
300     /// ```
301     /// use std::sync::atomics::{AtomicBool, SeqCst};
302     ///
303     /// let mut foo = AtomicBool::new(true);
304     /// assert_eq!(true, foo.fetch_and(false, SeqCst));
305     /// assert_eq!(false, foo.load(SeqCst));
306     ///
307     /// let mut foo = AtomicBool::new(true);
308     /// assert_eq!(true, foo.fetch_and(true, SeqCst));
309     /// assert_eq!(true, foo.load(SeqCst));
310     ///
311     /// let mut foo = AtomicBool::new(false);
312     /// assert_eq!(false, foo.fetch_and(false, SeqCst));
313     /// assert_eq!(false, foo.load(SeqCst));
314     /// ```
315     #[inline]
316     pub fn fetch_and(&mut self, val: bool, order: Ordering) -> bool {
317         let val = if val { UINT_TRUE } else { 0 };
318
319         unsafe { atomic_and(&mut *self.v.get(), val, order) > 0 }
320     }
321
322     /// A logical "nand" operation
323     ///
324     /// Performs a logical "nand" operation on the current value and the
325     /// argument `val`, and sets the new value to the result.
326     /// Returns the previous value.
327     ///
328     /// # Examples
329     ///
330     /// ```
331     /// use std::sync::atomics::{AtomicBool, SeqCst};
332     ///
333     /// let mut foo = AtomicBool::new(true);
334     /// assert_eq!(true, foo.fetch_nand(false, SeqCst));
335     /// assert_eq!(true, foo.load(SeqCst));
336     ///
337     /// let mut foo = AtomicBool::new(true);
338     /// assert_eq!(true, foo.fetch_nand(true, SeqCst));
339     /// assert_eq!(0, foo.load(SeqCst) as int);
340     /// assert_eq!(false, foo.load(SeqCst));
341     ///
342     /// let mut foo = AtomicBool::new(false);
343     /// assert_eq!(false, foo.fetch_nand(false, SeqCst));
344     /// assert_eq!(true, foo.load(SeqCst));
345     /// ```
346     #[inline]
347     pub fn fetch_nand(&mut self, val: bool, order: Ordering) -> bool {
348         let val = if val { UINT_TRUE } else { 0 };
349
350         unsafe { atomic_nand(&mut *self.v.get(), val, order) > 0 }
351     }
352
353     /// A logical "or" operation
354     ///
355     /// Performs a logical "or" operation on the current value and the
356     /// argument `val`, and sets the new value to the result.
357     /// Returns the previous value.
358     ///
359     /// # Examples
360     ///
361     /// ```
362     /// use std::sync::atomics::{AtomicBool, SeqCst};
363     ///
364     /// let mut foo = AtomicBool::new(true);
365     /// assert_eq!(true, foo.fetch_or(false, SeqCst));
366     /// assert_eq!(true, foo.load(SeqCst));
367     ///
368     /// let mut foo = AtomicBool::new(true);
369     /// assert_eq!(true, foo.fetch_or(true, SeqCst));
370     /// assert_eq!(true, foo.load(SeqCst));
371     ///
372     /// let mut foo = AtomicBool::new(false);
373     /// assert_eq!(false, foo.fetch_or(false, SeqCst));
374     /// assert_eq!(false, foo.load(SeqCst));
375     /// ```
376     #[inline]
377     pub fn fetch_or(&mut self, val: bool, order: Ordering) -> bool {
378         let val = if val { UINT_TRUE } else { 0 };
379
380         unsafe { atomic_or(&mut *self.v.get(), val, order) > 0 }
381     }
382
383     /// A logical "xor" operation
384     ///
385     /// Performs a logical "xor" operation on the current value and the
386     /// argument `val`, and sets the new value to the result.
387     /// Returns the previous value.
388     ///
389     /// # Examples
390     ///
391     /// ```
392     /// use std::sync::atomics::{AtomicBool, SeqCst};
393     ///
394     /// let mut foo = AtomicBool::new(true);
395     /// assert_eq!(true, foo.fetch_xor(false, SeqCst));
396     /// assert_eq!(true, foo.load(SeqCst));
397     ///
398     /// let mut foo = AtomicBool::new(true);
399     /// assert_eq!(true, foo.fetch_xor(true, SeqCst));
400     /// assert_eq!(false, foo.load(SeqCst));
401     ///
402     /// let mut foo = AtomicBool::new(false);
403     /// assert_eq!(false, foo.fetch_xor(false, SeqCst));
404     /// assert_eq!(false, foo.load(SeqCst));
405     /// ```
406     #[inline]
407     pub fn fetch_xor(&mut self, val: bool, order: Ordering) -> bool {
408         let val = if val { UINT_TRUE } else { 0 };
409
410         unsafe { atomic_xor(&mut *self.v.get(), val, order) > 0 }
411     }
412 }
413
414 impl AtomicInt {
415     /// Create a new `AtomicInt`
416     pub fn new(v: int) -> AtomicInt {
417         AtomicInt {v: Unsafe::new(v), nopod: marker::NoPod}
418     }
419
420     /// Load the value
421     #[inline]
422     pub fn load(&self, order: Ordering) -> int {
423         unsafe { atomic_load(&*self.v.get(), order) }
424     }
425
426     /// Store the value
427     #[inline]
428     pub fn store(&mut self, val: int, order: Ordering) {
429         unsafe { atomic_store(&mut *self.v.get(), val, order); }
430     }
431
432     /// Store a value, returning the old value
433     #[inline]
434     pub fn swap(&mut self, val: int, order: Ordering) -> int {
435         unsafe { atomic_swap(&mut *self.v.get(), val, order) }
436     }
437
438     /// If the current value is the same as expected, store a new value
439     ///
440     /// Compare the current value with `old`; if they are the same then
441     /// replace the current value with `new`. Return the previous value.
442     /// If the return value is equal to `old` then the value was updated.
443     #[inline]
444     pub fn compare_and_swap(&mut self, old: int, new: int, order: Ordering) -> int {
445         unsafe { atomic_compare_and_swap(&mut *self.v.get(), old, new, order) }
446     }
447
448     /// Add to the current value, returning the previous
449     ///
450     /// # Examples
451     ///
452     /// ```
453     /// use std::sync::atomics::{AtomicInt, SeqCst};
454     ///
455     /// let mut foo = AtomicInt::new(0);
456     /// assert_eq!(0, foo.fetch_add(10, SeqCst));
457     /// assert_eq!(10, foo.load(SeqCst));
458     /// ```
459     #[inline]
460     pub fn fetch_add(&mut self, val: int, order: Ordering) -> int {
461         unsafe { atomic_add(&mut *self.v.get(), val, order) }
462     }
463
464     /// Subtract from the current value, returning the previous
465     ///
466     /// # Examples
467     ///
468     /// ```
469     /// use std::sync::atomics::{AtomicInt, SeqCst};
470     ///
471     /// let mut foo = AtomicInt::new(0);
472     /// assert_eq!(0, foo.fetch_sub(10, SeqCst));
473     /// assert_eq!(-10, foo.load(SeqCst));
474     /// ```
475     #[inline]
476     pub fn fetch_sub(&mut self, val: int, order: Ordering) -> int {
477         unsafe { atomic_sub(&mut *self.v.get(), val, order) }
478     }
479 }
480
481 // temporary workaround
482 // it causes link failure on MIPS target
483 // libgcc doesn't implement 64-bit atomic operations for MIPS32
484 #[cfg(not(target_arch = "mips"))]
485 impl AtomicU64 {
486     pub fn new(v: u64) -> AtomicU64 {
487         AtomicU64 { v: Unsafe::new(v), nopod: marker::NoPod }
488     }
489
490     #[inline]
491     pub fn load(&self, order: Ordering) -> u64 {
492         unsafe { atomic_load(&*self.v.get(), order) }
493     }
494
495     #[inline]
496     pub fn store(&mut self, val: u64, order: Ordering) {
497         unsafe { atomic_store(&mut *self.v.get(), val, order); }
498     }
499
500     #[inline]
501     pub fn swap(&mut self, val: u64, order: Ordering) -> u64 {
502         unsafe { atomic_swap(&mut *self.v.get(), val, order) }
503     }
504
505     #[inline]
506     pub fn compare_and_swap(&mut self, old: u64, new: u64, order: Ordering) -> u64 {
507         unsafe { atomic_compare_and_swap(&mut *self.v.get(), old, new, order) }
508     }
509
510     #[inline]
511     pub fn fetch_add(&mut self, val: u64, order: Ordering) -> u64 {
512         unsafe { atomic_add(&mut *self.v.get(), val, order) }
513     }
514
515     #[inline]
516     pub fn fetch_sub(&mut self, val: u64, order: Ordering) -> u64 {
517         unsafe { atomic_sub(&mut *self.v.get(), val, order) }
518     }
519 }
520
521 impl AtomicUint {
522     /// Create a new `AtomicUint`
523     pub fn new(v: uint) -> AtomicUint {
524         AtomicUint { v: Unsafe::new(v), nopod: marker::NoPod }
525     }
526
527     /// Load the value
528     #[inline]
529     pub fn load(&self, order: Ordering) -> uint {
530         unsafe { atomic_load(&*self.v.get(), order) }
531     }
532
533     /// Store the value
534     #[inline]
535     pub fn store(&mut self, val: uint, order: Ordering) {
536         unsafe { atomic_store(&mut *self.v.get(), val, order); }
537     }
538
539     /// Store a value, returning the old value
540     #[inline]
541     pub fn swap(&mut self, val: uint, order: Ordering) -> uint {
542         unsafe { atomic_swap(&mut *self.v.get(), val, order) }
543     }
544
545     /// If the current value is the same as expected, store a new value
546     ///
547     /// Compare the current value with `old`; if they are the same then
548     /// replace the current value with `new`. Return the previous value.
549     /// If the return value is equal to `old` then the value was updated.
550     #[inline]
551     pub fn compare_and_swap(&mut self, old: uint, new: uint, order: Ordering) -> uint {
552         unsafe { atomic_compare_and_swap(&mut *self.v.get(), old, new, order) }
553     }
554
555     /// Add to the current value, returning the previous
556     ///
557     /// # Examples
558     ///
559     /// ```
560     /// use std::sync::atomics::{AtomicUint, SeqCst};
561     ///
562     /// let mut foo = AtomicUint::new(0);
563     /// assert_eq!(0, foo.fetch_add(10, SeqCst));
564     /// assert_eq!(10, foo.load(SeqCst));
565     /// ```
566     #[inline]
567     pub fn fetch_add(&mut self, val: uint, order: Ordering) -> uint {
568         unsafe { atomic_add(&mut *self.v.get(), val, order) }
569     }
570
571     /// Subtract from the current value, returning the previous
572     ///
573     /// # Examples
574     ///
575     /// ```
576     /// use std::sync::atomics::{AtomicUint, SeqCst};
577     ///
578     /// let mut foo = AtomicUint::new(10);
579     /// assert_eq!(10, foo.fetch_sub(10, SeqCst));
580     /// assert_eq!(0, foo.load(SeqCst));
581     /// ```
582     #[inline]
583     pub fn fetch_sub(&mut self, val: uint, order: Ordering) -> uint {
584         unsafe { atomic_sub(&mut *self.v.get(), val, order) }
585     }
586 }
587
588 impl<T> AtomicPtr<T> {
589     /// Create a new `AtomicPtr`
590     pub fn new(p: *mut T) -> AtomicPtr<T> {
591         AtomicPtr { p: Unsafe::new(p as uint), nopod: marker::NoPod }
592     }
593
594     /// Load the value
595     #[inline]
596     pub fn load(&self, order: Ordering) -> *mut T {
597         unsafe {
598             atomic_load(&*self.p.get(), order) as *mut T
599         }
600     }
601
602     /// Store the value
603     #[inline]
604     pub fn store(&mut self, ptr: *mut T, order: Ordering) {
605         unsafe { atomic_store(&mut *self.p.get(), ptr as uint, order); }
606     }
607
608     /// Store a value, returning the old value
609     #[inline]
610     pub fn swap(&mut self, ptr: *mut T, order: Ordering) -> *mut T {
611         unsafe { atomic_swap(&mut *self.p.get(), ptr as uint, order) as *mut T }
612     }
613
614     /// If the current value is the same as expected, store a new value
615     ///
616     /// Compare the current value with `old`; if they are the same then
617     /// replace the current value with `new`. Return the previous value.
618     /// If the return value is equal to `old` then the value was updated.
619     #[inline]
620     pub fn compare_and_swap(&mut self, old: *mut T, new: *mut T, order: Ordering) -> *mut T {
621         unsafe {
622             atomic_compare_and_swap(&mut *self.p.get(), old as uint,
623                                     new as uint, order) as *mut T
624         }
625     }
626 }
627
628 impl<T> AtomicOption<T> {
629     /// Create a new `AtomicOption`
630     pub fn new(p: ~T) -> AtomicOption<T> {
631         unsafe { AtomicOption { p: Unsafe::new(cast::transmute(p)) } }
632     }
633
634     /// Create a new `AtomicOption` that doesn't contain a value
635     pub fn empty() -> AtomicOption<T> { AtomicOption { p: Unsafe::new(0) } }
636
637     /// Store a value, returning the old value
638     #[inline]
639     pub fn swap(&mut self, val: ~T, order: Ordering) -> Option<~T> {
640         unsafe {
641             let val = cast::transmute(val);
642
643             let p = atomic_swap(&mut *self.p.get(), val, order);
644             if p as uint == 0 {
645                 None
646             } else {
647                 Some(cast::transmute(p))
648             }
649         }
650     }
651
652     /// Remove the value, leaving the `AtomicOption` empty.
653     #[inline]
654     pub fn take(&mut self, order: Ordering) -> Option<~T> {
655         unsafe { self.swap(cast::transmute(0), order) }
656     }
657
658     /// Replace an empty value with a non-empty value.
659     ///
660     /// Succeeds if the option is `None` and returns `None` if so. If
661     /// the option was already `Some`, returns `Some` of the rejected
662     /// value.
663     #[inline]
664     pub fn fill(&mut self, val: ~T, order: Ordering) -> Option<~T> {
665         unsafe {
666             let val = cast::transmute(val);
667             let expected = cast::transmute(0);
668             let oldval = atomic_compare_and_swap(&mut *self.p.get(), expected, val, order);
669             if oldval == expected {
670                 None
671             } else {
672                 Some(cast::transmute(val))
673             }
674         }
675     }
676
677     /// Returns `true` if the `AtomicOption` is empty.
678     ///
679     /// Be careful: The caller must have some external method of ensuring the
680     /// result does not get invalidated by another task after this returns.
681     #[inline]
682     pub fn is_empty(&mut self, order: Ordering) -> bool {
683         unsafe { atomic_load(&*self.p.get(), order) as uint == 0 }
684     }
685 }
686
687 #[unsafe_destructor]
688 impl<T> Drop for AtomicOption<T> {
689     fn drop(&mut self) {
690         let _ = self.take(SeqCst);
691     }
692 }
693
694 #[inline]
695 pub unsafe fn atomic_store<T>(dst: &mut T, val: T, order:Ordering) {
696     match order {
697         Release => intrinsics::atomic_store_rel(dst, val),
698         Relaxed => intrinsics::atomic_store_relaxed(dst, val),
699         _       => intrinsics::atomic_store(dst, val)
700     }
701 }
702
703 #[inline]
704 pub unsafe fn atomic_load<T>(dst: &T, order:Ordering) -> T {
705     match order {
706         Acquire => intrinsics::atomic_load_acq(dst),
707         Relaxed => intrinsics::atomic_load_relaxed(dst),
708         _       => intrinsics::atomic_load(dst)
709     }
710 }
711
712 #[inline]
713 pub unsafe fn atomic_swap<T>(dst: &mut T, val: T, order: Ordering) -> T {
714     match order {
715         Acquire => intrinsics::atomic_xchg_acq(dst, val),
716         Release => intrinsics::atomic_xchg_rel(dst, val),
717         AcqRel  => intrinsics::atomic_xchg_acqrel(dst, val),
718         Relaxed => intrinsics::atomic_xchg_relaxed(dst, val),
719         _       => intrinsics::atomic_xchg(dst, val)
720     }
721 }
722
723 /// Returns the old value (like __sync_fetch_and_add).
724 #[inline]
725 pub unsafe fn atomic_add<T>(dst: &mut T, val: T, order: Ordering) -> T {
726     match order {
727         Acquire => intrinsics::atomic_xadd_acq(dst, val),
728         Release => intrinsics::atomic_xadd_rel(dst, val),
729         AcqRel  => intrinsics::atomic_xadd_acqrel(dst, val),
730         Relaxed => intrinsics::atomic_xadd_relaxed(dst, val),
731         _       => intrinsics::atomic_xadd(dst, val)
732     }
733 }
734
735 /// Returns the old value (like __sync_fetch_and_sub).
736 #[inline]
737 pub unsafe fn atomic_sub<T>(dst: &mut T, val: T, order: Ordering) -> T {
738     match order {
739         Acquire => intrinsics::atomic_xsub_acq(dst, val),
740         Release => intrinsics::atomic_xsub_rel(dst, val),
741         AcqRel  => intrinsics::atomic_xsub_acqrel(dst, val),
742         Relaxed => intrinsics::atomic_xsub_relaxed(dst, val),
743         _       => intrinsics::atomic_xsub(dst, val)
744     }
745 }
746
747 #[inline]
748 pub unsafe fn atomic_compare_and_swap<T>(dst:&mut T, old:T, new:T, order: Ordering) -> T {
749     match order {
750         Acquire => intrinsics::atomic_cxchg_acq(dst, old, new),
751         Release => intrinsics::atomic_cxchg_rel(dst, old, new),
752         AcqRel  => intrinsics::atomic_cxchg_acqrel(dst, old, new),
753         Relaxed => intrinsics::atomic_cxchg_relaxed(dst, old, new),
754         _       => intrinsics::atomic_cxchg(dst, old, new),
755     }
756 }
757
758 #[inline]
759 pub unsafe fn atomic_and<T>(dst: &mut T, val: T, order: Ordering) -> T {
760     match order {
761         Acquire => intrinsics::atomic_and_acq(dst, val),
762         Release => intrinsics::atomic_and_rel(dst, val),
763         AcqRel  => intrinsics::atomic_and_acqrel(dst, val),
764         Relaxed => intrinsics::atomic_and_relaxed(dst, val),
765         _       => intrinsics::atomic_and(dst, val)
766     }
767 }
768
769 #[inline]
770 pub unsafe fn atomic_nand<T>(dst: &mut T, val: T, order: Ordering) -> T {
771     match order {
772         Acquire => intrinsics::atomic_nand_acq(dst, val),
773         Release => intrinsics::atomic_nand_rel(dst, val),
774         AcqRel  => intrinsics::atomic_nand_acqrel(dst, val),
775         Relaxed => intrinsics::atomic_nand_relaxed(dst, val),
776         _       => intrinsics::atomic_nand(dst, val)
777     }
778 }
779
780
781 #[inline]
782 pub unsafe fn atomic_or<T>(dst: &mut T, val: T, order: Ordering) -> T {
783     match order {
784         Acquire => intrinsics::atomic_or_acq(dst, val),
785         Release => intrinsics::atomic_or_rel(dst, val),
786         AcqRel  => intrinsics::atomic_or_acqrel(dst, val),
787         Relaxed => intrinsics::atomic_or_relaxed(dst, val),
788         _       => intrinsics::atomic_or(dst, val)
789     }
790 }
791
792
793 #[inline]
794 pub unsafe fn atomic_xor<T>(dst: &mut T, val: T, order: Ordering) -> T {
795     match order {
796         Acquire => intrinsics::atomic_xor_acq(dst, val),
797         Release => intrinsics::atomic_xor_rel(dst, val),
798         AcqRel  => intrinsics::atomic_xor_acqrel(dst, val),
799         Relaxed => intrinsics::atomic_xor_relaxed(dst, val),
800         _       => intrinsics::atomic_xor(dst, val)
801     }
802 }
803
804
805 /// An atomic fence.
806 ///
807 /// A fence 'A' which has `Release` ordering semantics, synchronizes with a
808 /// fence 'B' with (at least) `Acquire` semantics, if and only if there exists
809 /// atomic operations X and Y, both operating on some atomic object 'M' such
810 /// that A is sequenced before X, Y is synchronized before B and Y observers
811 /// the change to M. This provides a happens-before dependence between A and B.
812 ///
813 /// Atomic operations with `Release` or `Acquire` semantics can also synchronize
814 /// with a fence.
815 ///
816 /// A fence with has `SeqCst` ordering, in addition to having both `Acquire` and
817 /// `Release` semantics, participates in the global program order of the other
818 /// `SeqCst` operations and/or fences.
819 ///
820 /// Accepts `Acquire`, `Release`, `AcqRel` and `SeqCst` orderings.
821 ///
822 /// # Failure
823 ///
824 /// Fails if `order` is `Relaxed`
825 #[inline]
826 pub fn fence(order: Ordering) {
827     unsafe {
828         match order {
829             Acquire => intrinsics::atomic_fence_acq(),
830             Release => intrinsics::atomic_fence_rel(),
831             AcqRel  => intrinsics::atomic_fence_acqrel(),
832             SeqCst  => intrinsics::atomic_fence(),
833             Relaxed => fail!("there is no such thing as a relaxed fence")
834         }
835     }
836 }
837
838 #[cfg(test)]
839 mod test {
840     use option::*;
841     use super::*;
842
843     #[test]
844     fn bool_() {
845         let mut a = AtomicBool::new(false);
846         assert_eq!(a.compare_and_swap(false, true, SeqCst), false);
847         assert_eq!(a.compare_and_swap(false, true, SeqCst), true);
848
849         a.store(false, SeqCst);
850         assert_eq!(a.compare_and_swap(false, true, SeqCst), false);
851     }
852
853     #[test]
854     fn option_empty() {
855         let mut option: AtomicOption<()> = AtomicOption::empty();
856         assert!(option.is_empty(SeqCst));
857     }
858
859     #[test]
860     fn option_swap() {
861         let mut p = AtomicOption::new(~1);
862         let a = ~2;
863
864         let b = p.swap(a, SeqCst);
865
866         assert_eq!(b, Some(~1));
867         assert_eq!(p.take(SeqCst), Some(~2));
868     }
869
870     #[test]
871     fn option_take() {
872         let mut p = AtomicOption::new(~1);
873
874         assert_eq!(p.take(SeqCst), Some(~1));
875         assert_eq!(p.take(SeqCst), None);
876
877         let p2 = ~2;
878         p.swap(p2, SeqCst);
879
880         assert_eq!(p.take(SeqCst), Some(~2));
881     }
882
883     #[test]
884     fn option_fill() {
885         let mut p = AtomicOption::new(~1);
886         assert!(p.fill(~2, SeqCst).is_some()); // should fail; shouldn't leak!
887         assert_eq!(p.take(SeqCst), Some(~1));
888
889         assert!(p.fill(~2, SeqCst).is_none()); // shouldn't fail
890         assert_eq!(p.take(SeqCst), Some(~2));
891     }
892
893     #[test]
894     fn bool_and() {
895         let mut a = AtomicBool::new(true);
896         assert_eq!(a.fetch_and(false, SeqCst),true);
897         assert_eq!(a.load(SeqCst),false);
898     }
899
900     static mut S_BOOL : AtomicBool = INIT_ATOMIC_BOOL;
901     static mut S_INT  : AtomicInt  = INIT_ATOMIC_INT;
902     static mut S_UINT : AtomicUint = INIT_ATOMIC_UINT;
903
904     #[test]
905     fn static_init() {
906         unsafe {
907             assert!(!S_BOOL.load(SeqCst));
908             assert!(S_INT.load(SeqCst) == 0);
909             assert!(S_UINT.load(SeqCst) == 0);
910         }
911     }
912
913     #[test]
914     fn different_sizes() {
915         unsafe {
916             let mut slot = 0u16;
917             assert_eq!(super::atomic_swap(&mut slot, 1, SeqCst), 0);
918
919             let mut slot = 0u8;
920             assert_eq!(super::atomic_compare_and_swap(&mut slot, 1, 2, SeqCst), 0);
921
922             let mut slot = 0u32;
923             assert_eq!(super::atomic_load(&mut slot, SeqCst), 0);
924
925             let mut slot = 0u64;
926             super::atomic_store(&mut slot, 2, SeqCst);
927         }
928     }
929 }
930