1 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
2 use crate::primitive::sync::atomic::compiler_fence;
3 use core::sync::atomic::Ordering;
4 
5 /// Trait which allows reading from primitive atomic types with "consume" ordering.
6 pub trait AtomicConsume {
7     /// Type returned by `load_consume`.
8     type Val;
9 
10     /// Loads a value from the atomic using a "consume" memory ordering.
11     ///
12     /// This is similar to the "acquire" ordering, except that an ordering is
13     /// only guaranteed with operations that "depend on" the result of the load.
14     /// However consume loads are usually much faster than acquire loads on
15     /// architectures with a weak memory model since they don't require memory
16     /// fence instructions.
17     ///
18     /// The exact definition of "depend on" is a bit vague, but it works as you
19     /// would expect in practice since a lot of software, especially the Linux
20     /// kernel, rely on this behavior.
21     ///
22     /// This is currently only implemented on ARM and AArch64, where a fence
23     /// can be avoided. On other architectures this will fall back to a simple
24     /// `load(Ordering::Acquire)`.
load_consume(&self) -> Self::Val25     fn load_consume(&self) -> Self::Val;
26 }
27 
28 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
29 macro_rules! impl_consume {
30     () => {
31         #[inline]
32         fn load_consume(&self) -> Self::Val {
33             let result = self.load(Ordering::Relaxed);
34             compiler_fence(Ordering::Acquire);
35             result
36         }
37     };
38 }
39 
40 #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
41 macro_rules! impl_consume {
42     () => {
43         #[inline]
44         fn load_consume(&self) -> Self::Val {
45             self.load(Ordering::Acquire)
46         }
47     };
48 }
49 
50 macro_rules! impl_atomic {
51     ($atomic:ident, $val:ty) => {
52         impl AtomicConsume for ::core::sync::atomic::$atomic {
53             type Val = $val;
54             impl_consume!();
55         }
56         #[cfg(crossbeam_loom)]
57         impl AtomicConsume for ::loom::sync::atomic::$atomic {
58             type Val = $val;
59             impl_consume!();
60         }
61     };
62 }
63 
64 impl_atomic!(AtomicBool, bool);
65 impl_atomic!(AtomicUsize, usize);
66 #[cfg(not(crossbeam_loom))]
67 impl_atomic!(AtomicIsize, isize);
68 #[cfg(has_atomic_u8)]
69 impl_atomic!(AtomicU8, u8);
70 #[cfg(has_atomic_u8)]
71 impl_atomic!(AtomicI8, i8);
72 #[cfg(has_atomic_u16)]
73 impl_atomic!(AtomicU16, u16);
74 #[cfg(has_atomic_u16)]
75 impl_atomic!(AtomicI16, i16);
76 #[cfg(has_atomic_u32)]
77 impl_atomic!(AtomicU32, u32);
78 #[cfg(has_atomic_u32)]
79 impl_atomic!(AtomicI32, i32);
80 #[cfg(has_atomic_u64)]
81 impl_atomic!(AtomicU64, u64);
82 #[cfg(has_atomic_u64)]
83 impl_atomic!(AtomicI64, i64);
84 
85 impl<T> AtomicConsume for ::core::sync::atomic::AtomicPtr<T> {
86     type Val = *mut T;
87     impl_consume!();
88 }
89 
90 #[cfg(crossbeam_loom)]
91 impl<T> AtomicConsume for ::loom::sync::atomic::AtomicPtr<T> {
92     type Val = *mut T;
93     impl_consume!();
94 }
95