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