]> git.lizzy.rs Git - rust.git/blob - src/libcore/atomic.rs
Kill RacyCell in favor of marking SyncSender explicitly Send.
[rust.git] / src / libcore / atomic.rs
1 // Copyright 2012-2014 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`, `AtomicIsize`, `AtomicUsize`, 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 `Sync`)
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 //! use std::sync::Arc;
44 //! use std::sync::atomic::{AtomicUsize, Ordering};
45 //! use std::thread::Thread;
46 //!
47 //! fn main() {
48 //!     let spinlock = Arc::new(AtomicUsize::new(1));
49 //!
50 //!     let spinlock_clone = spinlock.clone();
51 //!     Thread::spawn(move|| {
52 //!         spinlock_clone.store(0, Ordering::SeqCst);
53 //!     });
54 //!
55 //!     // Wait for the other task to release the lock
56 //!     while spinlock.load(Ordering::SeqCst) != 0 {}
57 //! }
58 //! ```
59 //!
60 //! Keep a global count of live tasks:
61 //!
62 //! ```
63 //! use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
64 //!
65 //! static GLOBAL_TASK_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
66 //!
67 //! let old_task_count = GLOBAL_TASK_COUNT.fetch_add(1, Ordering::SeqCst);
68 //! println!("live tasks: {}", old_task_count + 1);
69 //! ```
70
71 #![stable]
72
73 use self::Ordering::*;
74
75 use marker::Sync;
76
77 use intrinsics;
78 use cell::UnsafeCell;
79
80 /// A boolean type which can be safely shared between threads.
81 #[stable]
82 pub struct AtomicBool {
83     v: UnsafeCell<usize>,
84 }
85
86 unsafe impl Sync for AtomicBool {}
87
88 /// A signed integer type which can be safely shared between threads.
89 #[stable]
90 pub struct AtomicIsize {
91     v: UnsafeCell<isize>,
92 }
93
94 unsafe impl Sync for AtomicIsize {}
95
96 /// An unsigned integer type which can be safely shared between threads.
97 #[stable]
98 pub struct AtomicUsize {
99     v: UnsafeCell<usize>,
100 }
101
102 unsafe impl Sync for AtomicUsize {}
103
104 /// A raw pointer type which can be safely shared between threads.
105 #[stable]
106 pub struct AtomicPtr<T> {
107     p: UnsafeCell<usize>,
108 }
109
110 unsafe impl<T> Sync for AtomicPtr<T> {}
111
112 /// Atomic memory orderings
113 ///
114 /// Memory orderings limit the ways that both the compiler and CPU may reorder
115 /// instructions around atomic operations. At its most restrictive,
116 /// "sequentially consistent" atomics allow neither reads nor writes
117 /// to be moved either before or after the atomic operation; on the other end
118 /// "relaxed" atomics allow all reorderings.
119 ///
120 /// Rust's memory orderings are [the same as
121 /// C++'s](http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync).
122 #[stable]
123 #[derive(Copy)]
124 pub enum Ordering {
125     /// No ordering constraints, only atomic operations.
126     #[stable]
127     Relaxed,
128     /// When coupled with a store, all previous writes become visible
129     /// to another thread that performs a load with `Acquire` ordering
130     /// on the same value.
131     #[stable]
132     Release,
133     /// When coupled with a load, all subsequent loads will see data
134     /// written before a store with `Release` ordering on the same value
135     /// in another thread.
136     #[stable]
137     Acquire,
138     /// When coupled with a load, uses `Acquire` ordering, and with a store
139     /// `Release` ordering.
140     #[stable]
141     AcqRel,
142     /// Like `AcqRel` with the additional guarantee that all threads see all
143     /// sequentially consistent operations in the same order.
144     #[stable]
145     SeqCst,
146 }
147
148 /// An `AtomicBool` initialized to `false`.
149 #[stable]
150 pub const ATOMIC_BOOL_INIT: AtomicBool =
151         AtomicBool { v: UnsafeCell { value: 0 } };
152 /// An `AtomicIsize` initialized to `0`.
153 #[stable]
154 pub const ATOMIC_ISIZE_INIT: AtomicIsize =
155         AtomicIsize { v: UnsafeCell { value: 0 } };
156 /// An `AtomicUsize` initialized to `0`.
157 #[stable]
158 pub const ATOMIC_USIZE_INIT: AtomicUsize =
159         AtomicUsize { v: UnsafeCell { value: 0, } };
160
161 // NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly
162 const UINT_TRUE: usize = -1;
163
164 impl AtomicBool {
165     /// Creates a new `AtomicBool`.
166     ///
167     /// # Examples
168     ///
169     /// ```
170     /// use std::sync::atomic::AtomicBool;
171     ///
172     /// let atomic_true  = AtomicBool::new(true);
173     /// let atomic_false = AtomicBool::new(false);
174     /// ```
175     #[inline]
176     #[stable]
177     pub fn new(v: bool) -> AtomicBool {
178         let val = if v { UINT_TRUE } else { 0 };
179         AtomicBool { v: UnsafeCell::new(val) }
180     }
181
182     /// Loads a value from the bool.
183     ///
184     /// `load` takes an `Ordering` argument which describes the memory ordering of this operation.
185     ///
186     /// # Panics
187     ///
188     /// Panics if `order` is `Release` or `AcqRel`.
189     ///
190     /// # Examples
191     ///
192     /// ```
193     /// use std::sync::atomic::{AtomicBool, Ordering};
194     ///
195     /// let some_bool = AtomicBool::new(true);
196     ///
197     /// let value = some_bool.load(Ordering::Relaxed);
198     /// ```
199     #[inline]
200     #[stable]
201     pub fn load(&self, order: Ordering) -> bool {
202         unsafe { atomic_load(self.v.get() as *const usize, order) > 0 }
203     }
204
205     /// Stores a value into the bool.
206     ///
207     /// `store` takes an `Ordering` argument which describes the memory ordering of this operation.
208     ///
209     /// # Examples
210     ///
211     /// ```
212     /// use std::sync::atomic::{AtomicBool, Ordering};
213     ///
214     /// let some_bool = AtomicBool::new(true);
215     ///
216     /// some_bool.store(false, Ordering::Relaxed);
217     /// ```
218     ///
219     /// # Panics
220     ///
221     /// Panics if `order` is `Acquire` or `AcqRel`.
222     #[inline]
223     #[stable]
224     pub fn store(&self, val: bool, order: Ordering) {
225         let val = if val { UINT_TRUE } else { 0 };
226
227         unsafe { atomic_store(self.v.get(), val, order); }
228     }
229
230     /// Stores a value into the bool, returning the old value.
231     ///
232     /// `swap` takes an `Ordering` argument which describes the memory ordering of this operation.
233     ///
234     /// # Examples
235     ///
236     /// ```
237     /// use std::sync::atomic::{AtomicBool, Ordering};
238     ///
239     /// let some_bool = AtomicBool::new(true);
240     ///
241     /// let value = some_bool.swap(false, Ordering::Relaxed);
242     /// ```
243     #[inline]
244     #[stable]
245     pub fn swap(&self, val: bool, order: Ordering) -> bool {
246         let val = if val { UINT_TRUE } else { 0 };
247
248         unsafe { atomic_swap(self.v.get(), val, order) > 0 }
249     }
250
251     /// Stores a value into the bool if the current value is the same as the expected value.
252     ///
253     /// If the return value is equal to `old` then the value was updated.
254     ///
255     /// `swap` also takes an `Ordering` argument which describes the memory ordering of this
256     /// operation.
257     ///
258     /// # Examples
259     ///
260     /// ```
261     /// use std::sync::atomic::{AtomicBool, Ordering};
262     ///
263     /// let some_bool = AtomicBool::new(true);
264     ///
265     /// let value = some_bool.store(false, Ordering::Relaxed);
266     /// ```
267     #[inline]
268     #[stable]
269     pub fn compare_and_swap(&self, old: bool, new: bool, order: Ordering) -> bool {
270         let old = if old { UINT_TRUE } else { 0 };
271         let new = if new { UINT_TRUE } else { 0 };
272
273         unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) > 0 }
274     }
275
276     /// Logical "and" with a boolean value.
277     ///
278     /// Performs a logical "and" operation on the current value and the argument `val`, and sets
279     /// the new value to the result.
280     ///
281     /// Returns the previous value.
282     ///
283     /// # Examples
284     ///
285     /// ```
286     /// use std::sync::atomic::{AtomicBool, Ordering};
287     ///
288     /// let foo = AtomicBool::new(true);
289     /// assert_eq!(true, foo.fetch_and(false, Ordering::SeqCst));
290     /// assert_eq!(false, foo.load(Ordering::SeqCst));
291     ///
292     /// let foo = AtomicBool::new(true);
293     /// assert_eq!(true, foo.fetch_and(true, Ordering::SeqCst));
294     /// assert_eq!(true, foo.load(Ordering::SeqCst));
295     ///
296     /// let foo = AtomicBool::new(false);
297     /// assert_eq!(false, foo.fetch_and(false, Ordering::SeqCst));
298     /// assert_eq!(false, foo.load(Ordering::SeqCst));
299     /// ```
300     #[inline]
301     #[stable]
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     /// Logical "nand" with a boolean value.
309     ///
310     /// Performs a logical "nand" operation on the current value and the argument `val`, and sets
311     /// the new value to the result.
312     ///
313     /// Returns the previous value.
314     ///
315     /// # Examples
316     ///
317     /// ```
318     /// use std::sync::atomic::{AtomicBool, Ordering};
319     ///
320     /// let foo = AtomicBool::new(true);
321     /// assert_eq!(true, foo.fetch_nand(false, Ordering::SeqCst));
322     /// assert_eq!(true, foo.load(Ordering::SeqCst));
323     ///
324     /// let foo = AtomicBool::new(true);
325     /// assert_eq!(true, foo.fetch_nand(true, Ordering::SeqCst));
326     /// assert_eq!(0, foo.load(Ordering::SeqCst) as usize);
327     /// assert_eq!(false, foo.load(Ordering::SeqCst));
328     ///
329     /// let foo = AtomicBool::new(false);
330     /// assert_eq!(false, foo.fetch_nand(false, Ordering::SeqCst));
331     /// assert_eq!(true, foo.load(Ordering::SeqCst));
332     /// ```
333     #[inline]
334     #[stable]
335     pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
336         let val = if val { UINT_TRUE } else { 0 };
337
338         unsafe { atomic_nand(self.v.get(), val, order) > 0 }
339     }
340
341     /// Logical "or" with a boolean value.
342     ///
343     /// Performs a logical "or" operation on the current value and the argument `val`, and sets the
344     /// new value to the result.
345     ///
346     /// Returns the previous value.
347     ///
348     /// # Examples
349     ///
350     /// ```
351     /// use std::sync::atomic::{AtomicBool, Ordering};
352     ///
353     /// let foo = AtomicBool::new(true);
354     /// assert_eq!(true, foo.fetch_or(false, Ordering::SeqCst));
355     /// assert_eq!(true, foo.load(Ordering::SeqCst));
356     ///
357     /// let foo = AtomicBool::new(true);
358     /// assert_eq!(true, foo.fetch_or(true, Ordering::SeqCst));
359     /// assert_eq!(true, foo.load(Ordering::SeqCst));
360     ///
361     /// let foo = AtomicBool::new(false);
362     /// assert_eq!(false, foo.fetch_or(false, Ordering::SeqCst));
363     /// assert_eq!(false, foo.load(Ordering::SeqCst));
364     /// ```
365     #[inline]
366     #[stable]
367     pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
368         let val = if val { UINT_TRUE } else { 0 };
369
370         unsafe { atomic_or(self.v.get(), val, order) > 0 }
371     }
372
373     /// Logical "xor" with a boolean value.
374     ///
375     /// Performs a logical "xor" operation on the current value and the argument `val`, and sets
376     /// the new value to the result.
377     ///
378     /// Returns the previous value.
379     ///
380     /// # Examples
381     ///
382     /// ```
383     /// use std::sync::atomic::{AtomicBool, Ordering};
384     ///
385     /// let foo = AtomicBool::new(true);
386     /// assert_eq!(true, foo.fetch_xor(false, Ordering::SeqCst));
387     /// assert_eq!(true, foo.load(Ordering::SeqCst));
388     ///
389     /// let foo = AtomicBool::new(true);
390     /// assert_eq!(true, foo.fetch_xor(true, Ordering::SeqCst));
391     /// assert_eq!(false, foo.load(Ordering::SeqCst));
392     ///
393     /// let foo = AtomicBool::new(false);
394     /// assert_eq!(false, foo.fetch_xor(false, Ordering::SeqCst));
395     /// assert_eq!(false, foo.load(Ordering::SeqCst));
396     /// ```
397     #[inline]
398     #[stable]
399     pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
400         let val = if val { UINT_TRUE } else { 0 };
401
402         unsafe { atomic_xor(self.v.get(), val, order) > 0 }
403     }
404 }
405
406 #[stable]
407 impl AtomicIsize {
408     /// Creates a new `AtomicIsize`.
409     ///
410     /// # Examples
411     ///
412     /// ```
413     /// use std::sync::atomic::AtomicIsize;
414     ///
415     /// let atomic_forty_two  = AtomicIsize::new(42);
416     /// ```
417     #[inline]
418     pub fn new(v: isize) -> AtomicIsize {
419         AtomicIsize {v: UnsafeCell::new(v)}
420     }
421
422     /// Loads a value from the isize.
423     ///
424     /// `load` takes an `Ordering` argument which describes the memory ordering of this operation.
425     ///
426     /// # Panics
427     ///
428     /// Panics if `order` is `Release` or `AcqRel`.
429     ///
430     /// # Examples
431     ///
432     /// ```
433     /// use std::sync::atomic::{AtomicIsize, Ordering};
434     ///
435     /// let some_isize = AtomicIsize::new(5);
436     ///
437     /// let value = some_isize.load(Ordering::Relaxed);
438     /// ```
439     #[inline]
440     pub fn load(&self, order: Ordering) -> isize {
441         unsafe { atomic_load(self.v.get() as *const isize, order) }
442     }
443
444     /// Stores a value into the isize.
445     ///
446     /// `store` takes an `Ordering` argument which describes the memory ordering of this operation.
447     ///
448     /// # Examples
449     ///
450     /// ```
451     /// use std::sync::atomic::{AtomicIsize, Ordering};
452     ///
453     /// let some_isize = AtomicIsize::new(5);
454     ///
455     /// some_isize.store(10, Ordering::Relaxed);
456     /// ```
457     ///
458     /// # Panics
459     ///
460     /// Panics if `order` is `Acquire` or `AcqRel`.
461     #[inline]
462     pub fn store(&self, val: isize, order: Ordering) {
463         unsafe { atomic_store(self.v.get(), val, order); }
464     }
465
466     /// Stores a value into the isize, returning the old value.
467     ///
468     /// `swap` takes an `Ordering` argument which describes the memory ordering of this operation.
469     ///
470     /// # Examples
471     ///
472     /// ```
473     /// use std::sync::atomic::{AtomicIsize, Ordering};
474     ///
475     /// let some_isize = AtomicIsize::new(5);
476     ///
477     /// let value = some_isize.swap(10, Ordering::Relaxed);
478     /// ```
479     #[inline]
480     pub fn swap(&self, val: isize, order: Ordering) -> isize {
481         unsafe { atomic_swap(self.v.get(), val, order) }
482     }
483
484     /// Stores a value into the isize if the current value is the same as the expected value.
485     ///
486     /// If the return value is equal to `old` then the value was updated.
487     ///
488     /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
489     /// this operation.
490     ///
491     /// # Examples
492     ///
493     /// ```
494     /// use std::sync::atomic::{AtomicIsize, Ordering};
495     ///
496     /// let some_isize = AtomicIsize::new(5);
497     ///
498     /// let value = some_isize.compare_and_swap(5, 10, Ordering::Relaxed);
499     /// ```
500     #[inline]
501     pub fn compare_and_swap(&self, old: isize, new: isize, order: Ordering) -> isize {
502         unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
503     }
504
505     /// Add an isize to the current value, returning the previous value.
506     ///
507     /// # Examples
508     ///
509     /// ```
510     /// use std::sync::atomic::{AtomicIsize, Ordering};
511     ///
512     /// let foo = AtomicIsize::new(0);
513     /// assert_eq!(0, foo.fetch_add(10, Ordering::SeqCst));
514     /// assert_eq!(10, foo.load(Ordering::SeqCst));
515     /// ```
516     #[inline]
517     pub fn fetch_add(&self, val: isize, order: Ordering) -> isize {
518         unsafe { atomic_add(self.v.get(), val, order) }
519     }
520
521     /// Subtract an isize from the current value, returning the previous value.
522     ///
523     /// # Examples
524     ///
525     /// ```
526     /// use std::sync::atomic::{AtomicIsize, Ordering};
527     ///
528     /// let foo = AtomicIsize::new(0);
529     /// assert_eq!(0, foo.fetch_sub(10, Ordering::SeqCst));
530     /// assert_eq!(-10, foo.load(Ordering::SeqCst));
531     /// ```
532     #[inline]
533     pub fn fetch_sub(&self, val: isize, order: Ordering) -> isize {
534         unsafe { atomic_sub(self.v.get(), val, order) }
535     }
536
537     /// Bitwise and with the current isize, returning the previous value.
538     ///
539     /// # Examples
540     ///
541     /// ```
542     /// use std::sync::atomic::{AtomicIsize, Ordering};
543     ///
544     /// let foo = AtomicIsize::new(0b101101);
545     /// assert_eq!(0b101101, foo.fetch_and(0b110011, Ordering::SeqCst));
546     /// assert_eq!(0b100001, foo.load(Ordering::SeqCst));
547     #[inline]
548     pub fn fetch_and(&self, val: isize, order: Ordering) -> isize {
549         unsafe { atomic_and(self.v.get(), val, order) }
550     }
551
552     /// Bitwise or with the current isize, returning the previous value.
553     ///
554     /// # Examples
555     ///
556     /// ```
557     /// use std::sync::atomic::{AtomicIsize, Ordering};
558     ///
559     /// let foo = AtomicIsize::new(0b101101);
560     /// assert_eq!(0b101101, foo.fetch_or(0b110011, Ordering::SeqCst));
561     /// assert_eq!(0b111111, foo.load(Ordering::SeqCst));
562     #[inline]
563     pub fn fetch_or(&self, val: isize, order: Ordering) -> isize {
564         unsafe { atomic_or(self.v.get(), val, order) }
565     }
566
567     /// Bitwise xor with the current isize, returning the previous value.
568     ///
569     /// # Examples
570     ///
571     /// ```
572     /// use std::sync::atomic::{AtomicIsize, Ordering};
573     ///
574     /// let foo = AtomicIsize::new(0b101101);
575     /// assert_eq!(0b101101, foo.fetch_xor(0b110011, Ordering::SeqCst));
576     /// assert_eq!(0b011110, foo.load(Ordering::SeqCst));
577     #[inline]
578     pub fn fetch_xor(&self, val: isize, order: Ordering) -> isize {
579         unsafe { atomic_xor(self.v.get(), val, order) }
580     }
581 }
582
583 #[stable]
584 impl AtomicUsize {
585     /// Creates a new `AtomicUsize`.
586     ///
587     /// # Examples
588     ///
589     /// ```
590     /// use std::sync::atomic::AtomicUsize;
591     ///
592     /// let atomic_forty_two = AtomicUsize::new(42u);
593     /// ```
594     #[inline]
595     pub fn new(v: usize) -> AtomicUsize {
596         AtomicUsize { v: UnsafeCell::new(v) }
597     }
598
599     /// Loads a value from the usize.
600     ///
601     /// `load` takes an `Ordering` argument which describes the memory ordering of this operation.
602     ///
603     /// # Panics
604     ///
605     /// Panics if `order` is `Release` or `AcqRel`.
606     ///
607     /// # Examples
608     ///
609     /// ```
610     /// use std::sync::atomic::{AtomicUsize, Ordering};
611     ///
612     /// let some_usize = AtomicUsize::new(5);
613     ///
614     /// let value = some_usize.load(Ordering::Relaxed);
615     /// ```
616     #[inline]
617     pub fn load(&self, order: Ordering) -> usize {
618         unsafe { atomic_load(self.v.get() as *const usize, order) }
619     }
620
621     /// Stores a value into the usize.
622     ///
623     /// `store` takes an `Ordering` argument which describes the memory ordering of this operation.
624     ///
625     /// # Examples
626     ///
627     /// ```
628     /// use std::sync::atomic::{AtomicUsize, Ordering};
629     ///
630     /// let some_usize = AtomicUsize::new(5);
631     ///
632     /// some_usize.store(10, Ordering::Relaxed);
633     /// ```
634     ///
635     /// # Panics
636     ///
637     /// Panics if `order` is `Acquire` or `AcqRel`.
638     #[inline]
639     pub fn store(&self, val: usize, order: Ordering) {
640         unsafe { atomic_store(self.v.get(), val, order); }
641     }
642
643     /// Stores a value into the usize, returning the old value.
644     ///
645     /// `swap` takes an `Ordering` argument which describes the memory ordering of this operation.
646     ///
647     /// # Examples
648     ///
649     /// ```
650     /// use std::sync::atomic::{AtomicUsize, Ordering};
651     ///
652     /// let some_usize= AtomicUsize::new(5);
653     ///
654     /// let value = some_usize.swap(10, Ordering::Relaxed);
655     /// ```
656     #[inline]
657     pub fn swap(&self, val: usize, order: Ordering) -> usize {
658         unsafe { atomic_swap(self.v.get(), val, order) }
659     }
660
661     /// Stores a value into the usize if the current value is the same as the expected value.
662     ///
663     /// If the return value is equal to `old` then the value was updated.
664     ///
665     /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
666     /// this operation.
667     ///
668     /// # Examples
669     ///
670     /// ```
671     /// use std::sync::atomic::{AtomicUsize, Ordering};
672     ///
673     /// let some_usize = AtomicUsize::new(5);
674     ///
675     /// let value = some_usize.compare_and_swap(5, 10, Ordering::Relaxed);
676     /// ```
677     #[inline]
678     pub fn compare_and_swap(&self, old: usize, new: usize, order: Ordering) -> usize {
679         unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
680     }
681
682     /// Add to the current usize, returning the previous value.
683     ///
684     /// # Examples
685     ///
686     /// ```
687     /// use std::sync::atomic::{AtomicUsize, Ordering};
688     ///
689     /// let foo = AtomicUsize::new(0);
690     /// assert_eq!(0, foo.fetch_add(10, Ordering::SeqCst));
691     /// assert_eq!(10, foo.load(Ordering::SeqCst));
692     /// ```
693     #[inline]
694     pub fn fetch_add(&self, val: usize, order: Ordering) -> usize {
695         unsafe { atomic_add(self.v.get(), val, order) }
696     }
697
698     /// Subtract from the current usize, returning the previous value.
699     ///
700     /// # Examples
701     ///
702     /// ```
703     /// use std::sync::atomic::{AtomicUsize, Ordering};
704     ///
705     /// let foo = AtomicUsize::new(10);
706     /// assert_eq!(10, foo.fetch_sub(10, Ordering::SeqCst));
707     /// assert_eq!(0, foo.load(Ordering::SeqCst));
708     /// ```
709     #[inline]
710     pub fn fetch_sub(&self, val: usize, order: Ordering) -> usize {
711         unsafe { atomic_sub(self.v.get(), val, order) }
712     }
713
714     /// Bitwise and with the current usize, returning the previous value.
715     ///
716     /// # Examples
717     ///
718     /// ```
719     /// use std::sync::atomic::{AtomicUsize, Ordering};
720     ///
721     /// let foo = AtomicUsize::new(0b101101);
722     /// assert_eq!(0b101101, foo.fetch_and(0b110011, Ordering::SeqCst));
723     /// assert_eq!(0b100001, foo.load(Ordering::SeqCst));
724     #[inline]
725     pub fn fetch_and(&self, val: usize, order: Ordering) -> usize {
726         unsafe { atomic_and(self.v.get(), val, order) }
727     }
728
729     /// Bitwise or with the current usize, returning the previous value.
730     ///
731     /// # Examples
732     ///
733     /// ```
734     /// use std::sync::atomic::{AtomicUsize, Ordering};
735     ///
736     /// let foo = AtomicUsize::new(0b101101);
737     /// assert_eq!(0b101101, foo.fetch_or(0b110011, Ordering::SeqCst));
738     /// assert_eq!(0b111111, foo.load(Ordering::SeqCst));
739     #[inline]
740     pub fn fetch_or(&self, val: usize, order: Ordering) -> usize {
741         unsafe { atomic_or(self.v.get(), val, order) }
742     }
743
744     /// Bitwise xor with the current usize, returning the previous value.
745     ///
746     /// # Examples
747     ///
748     /// ```
749     /// use std::sync::atomic::{AtomicUsize, Ordering};
750     ///
751     /// let foo = AtomicUsize::new(0b101101);
752     /// assert_eq!(0b101101, foo.fetch_xor(0b110011, Ordering::SeqCst));
753     /// assert_eq!(0b011110, foo.load(Ordering::SeqCst));
754     #[inline]
755     pub fn fetch_xor(&self, val: usize, order: Ordering) -> usize {
756         unsafe { atomic_xor(self.v.get(), val, order) }
757     }
758 }
759
760 impl<T> AtomicPtr<T> {
761     /// Creates a new `AtomicPtr`.
762     ///
763     /// # Examples
764     ///
765     /// ```
766     /// use std::sync::atomic::AtomicPtr;
767     ///
768     /// let ptr = &mut 5i;
769     /// let atomic_ptr  = AtomicPtr::new(ptr);
770     /// ```
771     #[inline]
772     #[stable]
773     pub fn new(p: *mut T) -> AtomicPtr<T> {
774         AtomicPtr { p: UnsafeCell::new(p as usize) }
775     }
776
777     /// Loads a value from the pointer.
778     ///
779     /// `load` takes an `Ordering` argument which describes the memory ordering of this operation.
780     ///
781     /// # Panics
782     ///
783     /// Panics if `order` is `Release` or `AcqRel`.
784     ///
785     /// # Examples
786     ///
787     /// ```
788     /// use std::sync::atomic::{AtomicPtr, Ordering};
789     ///
790     /// let ptr = &mut 5i;
791     /// let some_ptr  = AtomicPtr::new(ptr);
792     ///
793     /// let value = some_ptr.load(Ordering::Relaxed);
794     /// ```
795     #[inline]
796     #[stable]
797     pub fn load(&self, order: Ordering) -> *mut T {
798         unsafe {
799             atomic_load(self.p.get() as *const *mut T, order) as *mut T
800         }
801     }
802
803     /// Stores a value into the pointer.
804     ///
805     /// `store` takes an `Ordering` argument which describes the memory ordering of this operation.
806     ///
807     /// # Examples
808     ///
809     /// ```
810     /// use std::sync::atomic::{AtomicPtr, Ordering};
811     ///
812     /// let ptr = &mut 5i;
813     /// let some_ptr  = AtomicPtr::new(ptr);
814     ///
815     /// let other_ptr = &mut 10i;
816     ///
817     /// some_ptr.store(other_ptr, Ordering::Relaxed);
818     /// ```
819     ///
820     /// # Panics
821     ///
822     /// Panics if `order` is `Acquire` or `AcqRel`.
823     #[inline]
824     #[stable]
825     pub fn store(&self, ptr: *mut T, order: Ordering) {
826         unsafe { atomic_store(self.p.get(), ptr as usize, order); }
827     }
828
829     /// Stores a value into the pointer, returning the old value.
830     ///
831     /// `swap` takes an `Ordering` argument which describes the memory ordering of this operation.
832     ///
833     /// # Examples
834     ///
835     /// ```
836     /// use std::sync::atomic::{AtomicPtr, Ordering};
837     ///
838     /// let ptr = &mut 5i;
839     /// let some_ptr  = AtomicPtr::new(ptr);
840     ///
841     /// let other_ptr = &mut 10i;
842     ///
843     /// let value = some_ptr.swap(other_ptr, Ordering::Relaxed);
844     /// ```
845     #[inline]
846     #[stable]
847     pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
848         unsafe { atomic_swap(self.p.get(), ptr as usize, order) as *mut T }
849     }
850
851     /// Stores a value into the pointer if the current value is the same as the expected value.
852     ///
853     /// If the return value is equal to `old` then the value was updated.
854     ///
855     /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
856     /// this operation.
857     ///
858     /// # Examples
859     ///
860     /// ```
861     /// use std::sync::atomic::{AtomicPtr, Ordering};
862     ///
863     /// let ptr = &mut 5i;
864     /// let some_ptr  = AtomicPtr::new(ptr);
865     ///
866     /// let other_ptr   = &mut 10i;
867     /// let another_ptr = &mut 10i;
868     ///
869     /// let value = some_ptr.compare_and_swap(other_ptr, another_ptr, Ordering::Relaxed);
870     /// ```
871     #[inline]
872     #[stable]
873     pub fn compare_and_swap(&self, old: *mut T, new: *mut T, order: Ordering) -> *mut T {
874         unsafe {
875             atomic_compare_and_swap(self.p.get(), old as usize,
876                                     new as usize, order) as *mut T
877         }
878     }
879 }
880
881 #[inline]
882 unsafe fn atomic_store<T>(dst: *mut T, val: T, order:Ordering) {
883     match order {
884         Release => intrinsics::atomic_store_rel(dst, val),
885         Relaxed => intrinsics::atomic_store_relaxed(dst, val),
886         SeqCst  => intrinsics::atomic_store(dst, val),
887         Acquire => panic!("there is no such thing as an acquire store"),
888         AcqRel  => panic!("there is no such thing as an acquire/release store"),
889     }
890 }
891
892 #[inline]
893 #[stable]
894 unsafe fn atomic_load<T>(dst: *const T, order:Ordering) -> T {
895     match order {
896         Acquire => intrinsics::atomic_load_acq(dst),
897         Relaxed => intrinsics::atomic_load_relaxed(dst),
898         SeqCst  => intrinsics::atomic_load(dst),
899         Release => panic!("there is no such thing as a release load"),
900         AcqRel  => panic!("there is no such thing as an acquire/release load"),
901     }
902 }
903
904 #[inline]
905 #[stable]
906 unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
907     match order {
908         Acquire => intrinsics::atomic_xchg_acq(dst, val),
909         Release => intrinsics::atomic_xchg_rel(dst, val),
910         AcqRel  => intrinsics::atomic_xchg_acqrel(dst, val),
911         Relaxed => intrinsics::atomic_xchg_relaxed(dst, val),
912         SeqCst  => intrinsics::atomic_xchg(dst, val)
913     }
914 }
915
916 /// Returns the old value (like __sync_fetch_and_add).
917 #[inline]
918 #[stable]
919 unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
920     match order {
921         Acquire => intrinsics::atomic_xadd_acq(dst, val),
922         Release => intrinsics::atomic_xadd_rel(dst, val),
923         AcqRel  => intrinsics::atomic_xadd_acqrel(dst, val),
924         Relaxed => intrinsics::atomic_xadd_relaxed(dst, val),
925         SeqCst  => intrinsics::atomic_xadd(dst, val)
926     }
927 }
928
929 /// Returns the old value (like __sync_fetch_and_sub).
930 #[inline]
931 #[stable]
932 unsafe fn atomic_sub<T>(dst: *mut T, val: T, order: Ordering) -> T {
933     match order {
934         Acquire => intrinsics::atomic_xsub_acq(dst, val),
935         Release => intrinsics::atomic_xsub_rel(dst, val),
936         AcqRel  => intrinsics::atomic_xsub_acqrel(dst, val),
937         Relaxed => intrinsics::atomic_xsub_relaxed(dst, val),
938         SeqCst  => intrinsics::atomic_xsub(dst, val)
939     }
940 }
941
942 #[inline]
943 #[stable]
944 unsafe fn atomic_compare_and_swap<T>(dst: *mut T, old:T, new:T, order: Ordering) -> T {
945     match order {
946         Acquire => intrinsics::atomic_cxchg_acq(dst, old, new),
947         Release => intrinsics::atomic_cxchg_rel(dst, old, new),
948         AcqRel  => intrinsics::atomic_cxchg_acqrel(dst, old, new),
949         Relaxed => intrinsics::atomic_cxchg_relaxed(dst, old, new),
950         SeqCst  => intrinsics::atomic_cxchg(dst, old, new),
951     }
952 }
953
954 #[inline]
955 #[stable]
956 unsafe fn atomic_and<T>(dst: *mut T, val: T, order: Ordering) -> T {
957     match order {
958         Acquire => intrinsics::atomic_and_acq(dst, val),
959         Release => intrinsics::atomic_and_rel(dst, val),
960         AcqRel  => intrinsics::atomic_and_acqrel(dst, val),
961         Relaxed => intrinsics::atomic_and_relaxed(dst, val),
962         SeqCst  => intrinsics::atomic_and(dst, val)
963     }
964 }
965
966 #[inline]
967 #[stable]
968 unsafe fn atomic_nand<T>(dst: *mut T, val: T, order: Ordering) -> T {
969     match order {
970         Acquire => intrinsics::atomic_nand_acq(dst, val),
971         Release => intrinsics::atomic_nand_rel(dst, val),
972         AcqRel  => intrinsics::atomic_nand_acqrel(dst, val),
973         Relaxed => intrinsics::atomic_nand_relaxed(dst, val),
974         SeqCst  => intrinsics::atomic_nand(dst, val)
975     }
976 }
977
978
979 #[inline]
980 #[stable]
981 unsafe fn atomic_or<T>(dst: *mut T, val: T, order: Ordering) -> T {
982     match order {
983         Acquire => intrinsics::atomic_or_acq(dst, val),
984         Release => intrinsics::atomic_or_rel(dst, val),
985         AcqRel  => intrinsics::atomic_or_acqrel(dst, val),
986         Relaxed => intrinsics::atomic_or_relaxed(dst, val),
987         SeqCst  => intrinsics::atomic_or(dst, val)
988     }
989 }
990
991
992 #[inline]
993 #[stable]
994 unsafe fn atomic_xor<T>(dst: *mut T, val: T, order: Ordering) -> T {
995     match order {
996         Acquire => intrinsics::atomic_xor_acq(dst, val),
997         Release => intrinsics::atomic_xor_rel(dst, val),
998         AcqRel  => intrinsics::atomic_xor_acqrel(dst, val),
999         Relaxed => intrinsics::atomic_xor_relaxed(dst, val),
1000         SeqCst  => intrinsics::atomic_xor(dst, val)
1001     }
1002 }
1003
1004
1005 /// An atomic fence.
1006 ///
1007 /// A fence 'A' which has `Release` ordering semantics, synchronizes with a
1008 /// fence 'B' with (at least) `Acquire` semantics, if and only if there exists
1009 /// atomic operations X and Y, both operating on some atomic object 'M' such
1010 /// that A is sequenced before X, Y is synchronized before B and Y observes
1011 /// the change to M. This provides a happens-before dependence between A and B.
1012 ///
1013 /// Atomic operations with `Release` or `Acquire` semantics can also synchronize
1014 /// with a fence.
1015 ///
1016 /// A fence which has `SeqCst` ordering, in addition to having both `Acquire`
1017 /// and `Release` semantics, participates in the global program order of the
1018 /// other `SeqCst` operations and/or fences.
1019 ///
1020 /// Accepts `Acquire`, `Release`, `AcqRel` and `SeqCst` orderings.
1021 ///
1022 /// # Panics
1023 ///
1024 /// Panics if `order` is `Relaxed`.
1025 #[inline]
1026 #[stable]
1027 pub fn fence(order: Ordering) {
1028     unsafe {
1029         match order {
1030             Acquire => intrinsics::atomic_fence_acq(),
1031             Release => intrinsics::atomic_fence_rel(),
1032             AcqRel  => intrinsics::atomic_fence_acqrel(),
1033             SeqCst  => intrinsics::atomic_fence(),
1034             Relaxed => panic!("there is no such thing as a relaxed fence")
1035         }
1036     }
1037 }
1038
1039 #[deprecated="renamed to AtomicIsize"]
1040 #[allow(missing_docs)]
1041 pub struct AtomicInt {
1042     v: UnsafeCell<int>,
1043 }
1044
1045 unsafe impl Sync for AtomicInt {}
1046
1047 #[deprecated="renamed to AtomicUsize"]
1048 #[allow(missing_docs)]
1049 pub struct AtomicUint {
1050     v: UnsafeCell<uint>,
1051 }
1052
1053 unsafe impl Sync for AtomicUint {}
1054
1055 #[deprecated="use ATOMIC_ISIZE_INIT instead"]
1056 #[allow(missing_docs, deprecated)]
1057 pub const ATOMIC_INT_INIT: AtomicInt =
1058         AtomicInt { v: UnsafeCell { value: 0 } };
1059 #[deprecated="use ATOMIC_USIZE_INIT instead"]
1060 #[allow(missing_docs, deprecated)]
1061 pub const ATOMIC_UINT_INIT: AtomicUint =
1062         AtomicUint { v: UnsafeCell { value: 0, } };
1063
1064 #[allow(missing_docs, deprecated)]
1065 impl AtomicInt {
1066     #[inline]
1067     pub fn new(v: int) -> AtomicInt {
1068         AtomicInt {v: UnsafeCell::new(v)}
1069     }
1070
1071     #[inline]
1072     pub fn load(&self, order: Ordering) -> int {
1073         unsafe { atomic_load(self.v.get() as *const int, order) }
1074     }
1075
1076     #[inline]
1077     pub fn store(&self, val: int, order: Ordering) {
1078         unsafe { atomic_store(self.v.get(), val, order); }
1079     }
1080
1081     #[inline]
1082     pub fn swap(&self, val: int, order: Ordering) -> int {
1083         unsafe { atomic_swap(self.v.get(), val, order) }
1084     }
1085
1086     #[inline]
1087     pub fn compare_and_swap(&self, old: int, new: int, order: Ordering) -> int {
1088         unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
1089     }
1090
1091     #[inline]
1092     pub fn fetch_add(&self, val: int, order: Ordering) -> int {
1093         unsafe { atomic_add(self.v.get(), val, order) }
1094     }
1095
1096     #[inline]
1097     pub fn fetch_sub(&self, val: int, order: Ordering) -> int {
1098         unsafe { atomic_sub(self.v.get(), val, order) }
1099     }
1100
1101     #[inline]
1102     pub fn fetch_and(&self, val: int, order: Ordering) -> int {
1103         unsafe { atomic_and(self.v.get(), val, order) }
1104     }
1105
1106     #[inline]
1107     pub fn fetch_or(&self, val: int, order: Ordering) -> int {
1108         unsafe { atomic_or(self.v.get(), val, order) }
1109     }
1110
1111     #[inline]
1112     pub fn fetch_xor(&self, val: int, order: Ordering) -> int {
1113         unsafe { atomic_xor(self.v.get(), val, order) }
1114     }
1115 }
1116
1117 #[allow(missing_docs, deprecated)]
1118 impl AtomicUint {
1119     #[inline]
1120     pub fn new(v: uint) -> AtomicUint {
1121         AtomicUint { v: UnsafeCell::new(v) }
1122     }
1123
1124     #[inline]
1125     pub fn load(&self, order: Ordering) -> uint {
1126         unsafe { atomic_load(self.v.get() as *const uint, order) }
1127     }
1128
1129     #[inline]
1130     pub fn store(&self, val: uint, order: Ordering) {
1131         unsafe { atomic_store(self.v.get(), val, order); }
1132     }
1133
1134     #[inline]
1135     pub fn swap(&self, val: uint, order: Ordering) -> uint {
1136         unsafe { atomic_swap(self.v.get(), val, order) }
1137     }
1138
1139     #[inline]
1140     pub fn compare_and_swap(&self, old: uint, new: uint, order: Ordering) -> uint {
1141         unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) }
1142     }
1143
1144     #[inline]
1145     pub fn fetch_add(&self, val: uint, order: Ordering) -> uint {
1146         unsafe { atomic_add(self.v.get(), val, order) }
1147     }
1148
1149     #[inline]
1150     pub fn fetch_sub(&self, val: uint, order: Ordering) -> uint {
1151         unsafe { atomic_sub(self.v.get(), val, order) }
1152     }
1153
1154     #[inline]
1155     pub fn fetch_and(&self, val: uint, order: Ordering) -> uint {
1156         unsafe { atomic_and(self.v.get(), val, order) }
1157     }
1158
1159     #[inline]
1160     pub fn fetch_or(&self, val: uint, order: Ordering) -> uint {
1161         unsafe { atomic_or(self.v.get(), val, order) }
1162     }
1163
1164     #[inline]
1165     pub fn fetch_xor(&self, val: uint, order: Ordering) -> uint {
1166         unsafe { atomic_xor(self.v.get(), val, order) }
1167     }
1168 }