xref: /linux/rust/kernel/sync/atomic/internal.rs (revision 23b0f90ba871f096474e1c27c3d14f455189d2d9)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 //! Atomic internal implementations.
4 //!
5 //! Provides 1:1 mapping to the C atomic operations.
6 
7 use crate::bindings;
8 use crate::macros::paste;
9 use core::cell::UnsafeCell;
10 
11 mod private {
12     /// Sealed trait marker to disable customized impls on atomic implementation traits.
13     pub trait Sealed {}
14 }
15 
16 // The C side supports atomic primitives only for `i32` and `i64` (`atomic_t` and `atomic64_t`),
17 // while the Rust side also layers provides atomic support for `i8` and `i16`
18 // on top of lower-level C primitives.
19 impl private::Sealed for i8 {}
20 impl private::Sealed for i16 {}
21 impl private::Sealed for i32 {}
22 impl private::Sealed for i64 {}
23 
24 /// A marker trait for types that implement atomic operations with C side primitives.
25 ///
26 /// This trait is sealed, and only types that map directly to the C side atomics
27 /// or can be implemented with lower-level C primitives are allowed to implement this:
28 ///
29 /// - `i8` and `i16` are implemented with lower-level C primitives.
30 /// - `i32` map to `atomic_t`
31 /// - `i64` map to `atomic64_t`
32 pub trait AtomicImpl: Sized + Send + Copy + private::Sealed {
33     /// The type of the delta in arithmetic or logical operations.
34     ///
35     /// For example, in `atomic_add(ptr, v)`, it's the type of `v`. Usually it's the same type of
36     /// [`Self`], but it may be different for the atomic pointer type.
37     type Delta;
38 }
39 
40 // The current helpers of load/store uses `{WRITE,READ}_ONCE()` hence the atomicity is only
41 // guaranteed against read-modify-write operations if the architecture supports native atomic RmW.
42 #[cfg(CONFIG_ARCH_SUPPORTS_ATOMIC_RMW)]
43 impl AtomicImpl for i8 {
44     type Delta = Self;
45 }
46 
47 // The current helpers of load/store uses `{WRITE,READ}_ONCE()` hence the atomicity is only
48 // guaranteed against read-modify-write operations if the architecture supports native atomic RmW.
49 #[cfg(CONFIG_ARCH_SUPPORTS_ATOMIC_RMW)]
50 impl AtomicImpl for i16 {
51     type Delta = Self;
52 }
53 
54 // `atomic_t` implements atomic operations on `i32`.
55 impl AtomicImpl for i32 {
56     type Delta = Self;
57 }
58 
59 // `atomic64_t` implements atomic operations on `i64`.
60 impl AtomicImpl for i64 {
61     type Delta = Self;
62 }
63 
64 /// Atomic representation.
65 #[repr(transparent)]
66 pub struct AtomicRepr<T: AtomicImpl>(UnsafeCell<T>);
67 
68 impl<T: AtomicImpl> AtomicRepr<T> {
69     /// Creates a new atomic representation `T`.
70     pub const fn new(v: T) -> Self {
71         Self(UnsafeCell::new(v))
72     }
73 
74     /// Returns a pointer to the underlying `T`.
75     ///
76     /// # Guarantees
77     ///
78     /// The returned pointer is valid and properly aligned (i.e. aligned to [`align_of::<T>()`]).
79     pub const fn as_ptr(&self) -> *mut T {
80         // GUARANTEE: `self.0` is an `UnsafeCell<T>`, therefore the pointer returned by `.get()`
81         // must be valid and properly aligned.
82         self.0.get()
83     }
84 }
85 
86 // This macro generates the function signature with given argument list and return type.
87 macro_rules! declare_atomic_method {
88     (
89         $(#[doc=$doc:expr])*
90         $func:ident($($arg:ident : $arg_type:ty),*) $(-> $ret:ty)?
91     ) => {
92         paste!(
93             $(#[doc = $doc])*
94             fn [< atomic_ $func >]($($arg: $arg_type,)*) $(-> $ret)?;
95         );
96     };
97     (
98         $(#[doc=$doc:expr])*
99         $func:ident [$variant:ident $($rest:ident)*]($($arg_sig:tt)*) $(-> $ret:ty)?
100     ) => {
101         paste!(
102             declare_atomic_method!(
103                 $(#[doc = $doc])*
104                 [< $func _ $variant >]($($arg_sig)*) $(-> $ret)?
105             );
106         );
107 
108         declare_atomic_method!(
109             $(#[doc = $doc])*
110             $func [$($rest)*]($($arg_sig)*) $(-> $ret)?
111         );
112     };
113     (
114         $(#[doc=$doc:expr])*
115         $func:ident []($($arg_sig:tt)*) $(-> $ret:ty)?
116     ) => {
117         declare_atomic_method!(
118             $(#[doc = $doc])*
119             $func($($arg_sig)*) $(-> $ret)?
120         );
121     }
122 }
123 
124 // This macro generates the function implementation with given argument list and return type, and it
125 // will replace "call(...)" expression with "$ctype _ $func" to call the real C function.
126 macro_rules! impl_atomic_method {
127     (
128         ($ctype:ident) $func:ident($($arg:ident: $arg_type:ty),*) $(-> $ret:ty)? {
129             $unsafe:tt { call($($c_arg:expr),*) }
130         }
131     ) => {
132         paste!(
133             #[inline(always)]
134             fn [< atomic_ $func >]($($arg: $arg_type,)*) $(-> $ret)? {
135                 // TODO: Ideally we want to use the SAFETY comments written at the macro invocation
136                 // (e.g. in `declare_and_impl_atomic_methods!()`, however, since SAFETY comments
137                 // are just comments, and they are not passed to macros as tokens, therefore we
138                 // cannot use them here. One potential improvement is that if we support using
139                 // attributes as an alternative for SAFETY comments, then we can use that for macro
140                 // generating code.
141                 //
142                 // SAFETY: specified on macro invocation.
143                 $unsafe { bindings::[< $ctype _ $func >]($($c_arg,)*) }
144             }
145         );
146     };
147     (
148         ($ctype:ident) $func:ident[$variant:ident $($rest:ident)*]($($arg_sig:tt)*) $(-> $ret:ty)? {
149             $unsafe:tt { call($($arg:tt)*) }
150         }
151     ) => {
152         paste!(
153             impl_atomic_method!(
154                 ($ctype) [< $func _ $variant >]($($arg_sig)*) $( -> $ret)? {
155                     $unsafe { call($($arg)*) }
156             }
157             );
158         );
159         impl_atomic_method!(
160             ($ctype) $func [$($rest)*]($($arg_sig)*) $( -> $ret)? {
161                 $unsafe { call($($arg)*) }
162             }
163         );
164     };
165     (
166         ($ctype:ident) $func:ident[]($($arg_sig:tt)*) $( -> $ret:ty)? {
167             $unsafe:tt { call($($arg:tt)*) }
168         }
169     ) => {
170         impl_atomic_method!(
171             ($ctype) $func($($arg_sig)*) $(-> $ret)? {
172                 $unsafe { call($($arg)*) }
173             }
174         );
175     }
176 }
177 
178 macro_rules! declare_atomic_ops_trait {
179     (
180         $(#[$attr:meta])* $pub:vis trait $ops:ident {
181             $(
182                 $(#[doc=$doc:expr])*
183                 fn $func:ident [$($variant:ident),*]($($arg_sig:tt)*) $( -> $ret:ty)? {
184                     $unsafe:tt { bindings::#call($($arg:tt)*) }
185                 }
186             )*
187         }
188     ) => {
189         $(#[$attr])*
190         $pub trait $ops: AtomicImpl {
191             $(
192                 declare_atomic_method!(
193                     $(#[doc=$doc])*
194                     $func[$($variant)*]($($arg_sig)*) $(-> $ret)?
195                 );
196             )*
197         }
198     }
199 }
200 
201 macro_rules! impl_atomic_ops_for_one {
202     (
203         $ty:ty => $ctype:ident,
204         $(#[$attr:meta])* $pub:vis trait $ops:ident {
205             $(
206                 $(#[doc=$doc:expr])*
207                 fn $func:ident [$($variant:ident),*]($($arg_sig:tt)*) $( -> $ret:ty)? {
208                     $unsafe:tt { bindings::#call($($arg:tt)*) }
209                 }
210             )*
211         }
212     ) => {
213         impl $ops for $ty {
214             $(
215                 impl_atomic_method!(
216                     ($ctype) $func[$($variant)*]($($arg_sig)*) $(-> $ret)? {
217                         $unsafe { call($($arg)*) }
218                     }
219                 );
220             )*
221         }
222     }
223 }
224 
225 // Declares $ops trait with methods and implements the trait.
226 macro_rules! declare_and_impl_atomic_methods {
227     (
228         [ $($map:tt)* ]
229         $(#[$attr:meta])* $pub:vis trait $ops:ident { $($body:tt)* }
230     ) => {
231         declare_and_impl_atomic_methods!(
232             @with_ops_def
233             [ $($map)* ]
234             ( $(#[$attr])* $pub trait $ops { $($body)* } )
235         );
236     };
237 
238     (@with_ops_def [ $($map:tt)* ] ( $($ops_def:tt)* )) => {
239         declare_atomic_ops_trait!( $($ops_def)* );
240 
241         declare_and_impl_atomic_methods!(
242             @munch
243             [ $($map)* ]
244             ( $($ops_def)* )
245         );
246     };
247 
248     (@munch [] ( $($ops_def:tt)* )) => {};
249 
250     (@munch [ $ty:ty => $ctype:ident $(, $($rest:tt)*)? ] ( $($ops_def:tt)* )) => {
251         impl_atomic_ops_for_one!(
252             $ty => $ctype,
253             $($ops_def)*
254         );
255 
256         declare_and_impl_atomic_methods!(
257             @munch
258             [ $($($rest)*)? ]
259             ( $($ops_def)* )
260         );
261     };
262 }
263 
264 declare_and_impl_atomic_methods!(
265     [ i8 => atomic_i8, i16 => atomic_i16, i32 => atomic, i64 => atomic64 ]
266     /// Basic atomic operations
267     pub trait AtomicBasicOps {
268         /// Atomic read (load).
269         fn read[acquire](a: &AtomicRepr<Self>) -> Self {
270             // SAFETY: `a.as_ptr()` is valid and properly aligned.
271             unsafe { bindings::#call(a.as_ptr().cast()) }
272         }
273 
274         /// Atomic set (store).
275         fn set[release](a: &AtomicRepr<Self>, v: Self) {
276             // SAFETY: `a.as_ptr()` is valid and properly aligned.
277             unsafe { bindings::#call(a.as_ptr().cast(), v) }
278         }
279     }
280 );
281 
282 declare_and_impl_atomic_methods!(
283     [ i8 => atomic_i8, i16 => atomic_i16, i32 => atomic, i64 => atomic64 ]
284     /// Exchange and compare-and-exchange atomic operations
285     pub trait AtomicExchangeOps {
286         /// Atomic exchange.
287         ///
288         /// Atomically updates `*a` to `v` and returns the old value.
289         fn xchg[acquire, release, relaxed](a: &AtomicRepr<Self>, v: Self) -> Self {
290             // SAFETY: `a.as_ptr()` is valid and properly aligned.
291             unsafe { bindings::#call(a.as_ptr().cast(), v) }
292         }
293 
294         /// Atomic compare and exchange.
295         ///
296         /// If `*a` == `*old`, atomically updates `*a` to `new`. Otherwise, `*a` is not
297         /// modified, `*old` is updated to the current value of `*a`.
298         ///
299         /// Return `true` if the update of `*a` occurred, `false` otherwise.
300         fn try_cmpxchg[acquire, release, relaxed](
301             a: &AtomicRepr<Self>, old: &mut Self, new: Self
302         ) -> bool {
303             // SAFETY: `a.as_ptr()` is valid and properly aligned. `core::ptr::from_mut(old)`
304             // is valid and properly aligned.
305             unsafe { bindings::#call(a.as_ptr().cast(), core::ptr::from_mut(old), new) }
306         }
307     }
308 );
309 
310 declare_and_impl_atomic_methods!(
311     [ i32 => atomic, i64 => atomic64 ]
312     /// Atomic arithmetic operations
313     pub trait AtomicArithmeticOps {
314         /// Atomic add (wrapping).
315         ///
316         /// Atomically updates `*a` to `(*a).wrapping_add(v)`.
317         fn add[](a: &AtomicRepr<Self>, v: Self::Delta) {
318             // SAFETY: `a.as_ptr()` is valid and properly aligned.
319             unsafe { bindings::#call(v, a.as_ptr().cast()) }
320         }
321 
322         /// Atomic fetch and add (wrapping).
323         ///
324         /// Atomically updates `*a` to `(*a).wrapping_add(v)`, and returns the value of `*a`
325         /// before the update.
326         fn fetch_add[acquire, release, relaxed](a: &AtomicRepr<Self>, v: Self::Delta) -> Self {
327             // SAFETY: `a.as_ptr()` is valid and properly aligned.
328             unsafe { bindings::#call(v, a.as_ptr().cast()) }
329         }
330     }
331 );
332