1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Pre-defined atomic types 4 5 use crate::static_assert; 6 use core::mem::{align_of, size_of}; 7 8 // SAFETY: `i32` has the same size and alignment with itself, and is round-trip transmutable to 9 // itself. 10 unsafe impl super::AtomicType for i32 { 11 type Repr = i32; 12 } 13 14 // SAFETY: The wrapping add result of two `i32`s is a valid `i32`. 15 unsafe impl super::AtomicAdd<i32> for i32 { rhs_into_delta(rhs: i32) -> i3216 fn rhs_into_delta(rhs: i32) -> i32 { 17 rhs 18 } 19 } 20 21 // SAFETY: `i64` has the same size and alignment with itself, and is round-trip transmutable to 22 // itself. 23 unsafe impl super::AtomicType for i64 { 24 type Repr = i64; 25 } 26 27 // SAFETY: The wrapping add result of two `i64`s is a valid `i64`. 28 unsafe impl super::AtomicAdd<i64> for i64 { rhs_into_delta(rhs: i64) -> i6429 fn rhs_into_delta(rhs: i64) -> i64 { 30 rhs 31 } 32 } 33 34 // Defines an internal type that always maps to the integer type which has the same size alignment 35 // as `isize` and `usize`, and `isize` and `usize` are always bi-directional transmutable to 36 // `isize_atomic_repr`, which also always implements `AtomicImpl`. 37 #[allow(non_camel_case_types)] 38 #[cfg(not(CONFIG_64BIT))] 39 type isize_atomic_repr = i32; 40 #[allow(non_camel_case_types)] 41 #[cfg(CONFIG_64BIT)] 42 type isize_atomic_repr = i64; 43 44 // Ensure size and alignment requirements are checked. 45 static_assert!(size_of::<isize>() == size_of::<isize_atomic_repr>()); 46 static_assert!(align_of::<isize>() == align_of::<isize_atomic_repr>()); 47 static_assert!(size_of::<usize>() == size_of::<isize_atomic_repr>()); 48 static_assert!(align_of::<usize>() == align_of::<isize_atomic_repr>()); 49 50 // SAFETY: `isize` has the same size and alignment with `isize_atomic_repr`, and is round-trip 51 // transmutable to `isize_atomic_repr`. 52 unsafe impl super::AtomicType for isize { 53 type Repr = isize_atomic_repr; 54 } 55 56 // SAFETY: The wrapping add result of two `isize_atomic_repr`s is a valid `usize`. 57 unsafe impl super::AtomicAdd<isize> for isize { rhs_into_delta(rhs: isize) -> isize_atomic_repr58 fn rhs_into_delta(rhs: isize) -> isize_atomic_repr { 59 rhs as isize_atomic_repr 60 } 61 } 62 63 // SAFETY: `u32` and `i32` has the same size and alignment, and `u32` is round-trip transmutable to 64 // `i32`. 65 unsafe impl super::AtomicType for u32 { 66 type Repr = i32; 67 } 68 69 // SAFETY: The wrapping add result of two `i32`s is a valid `u32`. 70 unsafe impl super::AtomicAdd<u32> for u32 { rhs_into_delta(rhs: u32) -> i3271 fn rhs_into_delta(rhs: u32) -> i32 { 72 rhs as i32 73 } 74 } 75 76 // SAFETY: `u64` and `i64` has the same size and alignment, and `u64` is round-trip transmutable to 77 // `i64`. 78 unsafe impl super::AtomicType for u64 { 79 type Repr = i64; 80 } 81 82 // SAFETY: The wrapping add result of two `i64`s is a valid `u64`. 83 unsafe impl super::AtomicAdd<u64> for u64 { rhs_into_delta(rhs: u64) -> i6484 fn rhs_into_delta(rhs: u64) -> i64 { 85 rhs as i64 86 } 87 } 88 89 // SAFETY: `usize` has the same size and alignment with `isize_atomic_repr`, and is round-trip 90 // transmutable to `isize_atomic_repr`. 91 unsafe impl super::AtomicType for usize { 92 type Repr = isize_atomic_repr; 93 } 94 95 // SAFETY: The wrapping add result of two `isize_atomic_repr`s is a valid `usize`. 96 unsafe impl super::AtomicAdd<usize> for usize { rhs_into_delta(rhs: usize) -> isize_atomic_repr97 fn rhs_into_delta(rhs: usize) -> isize_atomic_repr { 98 rhs as isize_atomic_repr 99 } 100 } 101 102 use crate::macros::kunit_tests; 103 104 #[kunit_tests(rust_atomics)] 105 mod tests { 106 use super::super::*; 107 108 // Call $fn($val) with each $type of $val. 109 macro_rules! for_each_type { 110 ($val:literal in [$($type:ty),*] $fn:expr) => { 111 $({ 112 let v: $type = $val; 113 114 $fn(v); 115 })* 116 } 117 } 118 119 #[test] atomic_basic_tests()120 fn atomic_basic_tests() { 121 for_each_type!(42 in [i32, i64, u32, u64, isize, usize] |v| { 122 let x = Atomic::new(v); 123 124 assert_eq!(v, x.load(Relaxed)); 125 }); 126 } 127 128 #[test] atomic_xchg_tests()129 fn atomic_xchg_tests() { 130 for_each_type!(42 in [i32, i64, u32, u64, isize, usize] |v| { 131 let x = Atomic::new(v); 132 133 let old = v; 134 let new = v + 1; 135 136 assert_eq!(old, x.xchg(new, Full)); 137 assert_eq!(new, x.load(Relaxed)); 138 }); 139 } 140 141 #[test] atomic_cmpxchg_tests()142 fn atomic_cmpxchg_tests() { 143 for_each_type!(42 in [i32, i64, u32, u64, isize, usize] |v| { 144 let x = Atomic::new(v); 145 146 let old = v; 147 let new = v + 1; 148 149 assert_eq!(Err(old), x.cmpxchg(new, new, Full)); 150 assert_eq!(old, x.load(Relaxed)); 151 assert_eq!(Ok(old), x.cmpxchg(old, new, Relaxed)); 152 assert_eq!(new, x.load(Relaxed)); 153 }); 154 } 155 156 #[test] atomic_arithmetic_tests()157 fn atomic_arithmetic_tests() { 158 for_each_type!(42 in [i32, i64, u32, u64, isize, usize] |v| { 159 let x = Atomic::new(v); 160 161 assert_eq!(v, x.fetch_add(12, Full)); 162 assert_eq!(v + 12, x.load(Relaxed)); 163 164 x.add(13, Relaxed); 165 166 assert_eq!(v + 25, x.load(Relaxed)); 167 }); 168 } 169 } 170