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