xref: /linux/rust/kernel/sync/atomic/predefine.rs (revision 367b81ef010ad3d0986af32f594c3a2e5807b40a)
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(testlib))]
39 #[cfg(not(CONFIG_64BIT))]
40 type isize_atomic_repr = i32;
41 #[allow(non_camel_case_types)]
42 #[cfg(not(testlib))]
43 #[cfg(CONFIG_64BIT)]
44 type isize_atomic_repr = i64;
45 
46 #[allow(non_camel_case_types)]
47 #[cfg(testlib)]
48 #[cfg(target_pointer_width = "32")]
49 type isize_atomic_repr = i32;
50 #[allow(non_camel_case_types)]
51 #[cfg(testlib)]
52 #[cfg(target_pointer_width = "64")]
53 type isize_atomic_repr = i64;
54 
55 // Ensure size and alignment requirements are checked.
56 static_assert!(size_of::<isize>() == size_of::<isize_atomic_repr>());
57 static_assert!(align_of::<isize>() == align_of::<isize_atomic_repr>());
58 static_assert!(size_of::<usize>() == size_of::<isize_atomic_repr>());
59 static_assert!(align_of::<usize>() == align_of::<isize_atomic_repr>());
60 
61 // SAFETY: `isize` has the same size and alignment with `isize_atomic_repr`, and is round-trip
62 // transmutable to `isize_atomic_repr`.
63 unsafe impl super::AtomicType for isize {
64     type Repr = isize_atomic_repr;
65 }
66 
67 // SAFETY: The wrapping add result of two `isize_atomic_repr`s is a valid `usize`.
68 unsafe impl super::AtomicAdd<isize> for isize {
rhs_into_delta(rhs: isize) -> isize_atomic_repr69     fn rhs_into_delta(rhs: isize) -> isize_atomic_repr {
70         rhs as isize_atomic_repr
71     }
72 }
73 
74 // SAFETY: `u32` and `i32` has the same size and alignment, and `u32` is round-trip transmutable to
75 // `i32`.
76 unsafe impl super::AtomicType for u32 {
77     type Repr = i32;
78 }
79 
80 // SAFETY: The wrapping add result of two `i32`s is a valid `u32`.
81 unsafe impl super::AtomicAdd<u32> for u32 {
rhs_into_delta(rhs: u32) -> i3282     fn rhs_into_delta(rhs: u32) -> i32 {
83         rhs as i32
84     }
85 }
86 
87 // SAFETY: `u64` and `i64` has the same size and alignment, and `u64` is round-trip transmutable to
88 // `i64`.
89 unsafe impl super::AtomicType for u64 {
90     type Repr = i64;
91 }
92 
93 // SAFETY: The wrapping add result of two `i64`s is a valid `u64`.
94 unsafe impl super::AtomicAdd<u64> for u64 {
rhs_into_delta(rhs: u64) -> i6495     fn rhs_into_delta(rhs: u64) -> i64 {
96         rhs as i64
97     }
98 }
99 
100 // SAFETY: `usize` has the same size and alignment with `isize_atomic_repr`, and is round-trip
101 // transmutable to `isize_atomic_repr`.
102 unsafe impl super::AtomicType for usize {
103     type Repr = isize_atomic_repr;
104 }
105 
106 // SAFETY: The wrapping add result of two `isize_atomic_repr`s is a valid `usize`.
107 unsafe impl super::AtomicAdd<usize> for usize {
rhs_into_delta(rhs: usize) -> isize_atomic_repr108     fn rhs_into_delta(rhs: usize) -> isize_atomic_repr {
109         rhs as isize_atomic_repr
110     }
111 }
112 
113 use crate::macros::kunit_tests;
114 
115 #[kunit_tests(rust_atomics)]
116 mod tests {
117     use super::super::*;
118 
119     // Call $fn($val) with each $type of $val.
120     macro_rules! for_each_type {
121         ($val:literal in [$($type:ty),*] $fn:expr) => {
122             $({
123                 let v: $type = $val;
124 
125                 $fn(v);
126             })*
127         }
128     }
129 
130     #[test]
atomic_basic_tests()131     fn atomic_basic_tests() {
132         for_each_type!(42 in [i32, i64, u32, u64, isize, usize] |v| {
133             let x = Atomic::new(v);
134 
135             assert_eq!(v, x.load(Relaxed));
136         });
137     }
138 
139     #[test]
atomic_xchg_tests()140     fn atomic_xchg_tests() {
141         for_each_type!(42 in [i32, i64, u32, u64, isize, usize] |v| {
142             let x = Atomic::new(v);
143 
144             let old = v;
145             let new = v + 1;
146 
147             assert_eq!(old, x.xchg(new, Full));
148             assert_eq!(new, x.load(Relaxed));
149         });
150     }
151 
152     #[test]
atomic_cmpxchg_tests()153     fn atomic_cmpxchg_tests() {
154         for_each_type!(42 in [i32, i64, u32, u64, isize, usize] |v| {
155             let x = Atomic::new(v);
156 
157             let old = v;
158             let new = v + 1;
159 
160             assert_eq!(Err(old), x.cmpxchg(new, new, Full));
161             assert_eq!(old, x.load(Relaxed));
162             assert_eq!(Ok(old), x.cmpxchg(old, new, Relaxed));
163             assert_eq!(new, x.load(Relaxed));
164         });
165     }
166 
167     #[test]
atomic_arithmetic_tests()168     fn atomic_arithmetic_tests() {
169         for_each_type!(42 in [i32, i64, u32, u64, isize, usize] |v| {
170             let x = Atomic::new(v);
171 
172             assert_eq!(v, x.fetch_add(12, Full));
173             assert_eq!(v + 12, x.load(Relaxed));
174 
175             x.add(13, Relaxed);
176 
177             assert_eq!(v + 25, x.load(Relaxed));
178         });
179     }
180 }
181