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 impl AtomicImpl for i8 { 41 type Delta = Self; 42 } 43 44 impl AtomicImpl for i16 { 45 type Delta = Self; 46 } 47 48 // `atomic_t` implements atomic operations on `i32`. 49 impl AtomicImpl for i32 { 50 type Delta = Self; 51 } 52 53 // `atomic64_t` implements atomic operations on `i64`. 54 impl AtomicImpl for i64 { 55 type Delta = Self; 56 } 57 58 /// Atomic representation. 59 #[repr(transparent)] 60 pub struct AtomicRepr<T: AtomicImpl>(UnsafeCell<T>); 61 62 impl<T: AtomicImpl> AtomicRepr<T> { 63 /// Creates a new atomic representation `T`. 64 pub const fn new(v: T) -> Self { 65 Self(UnsafeCell::new(v)) 66 } 67 68 /// Returns a pointer to the underlying `T`. 69 /// 70 /// # Guarantees 71 /// 72 /// The returned pointer is valid and properly aligned (i.e. aligned to [`align_of::<T>()`]). 73 pub const fn as_ptr(&self) -> *mut T { 74 // GUARANTEE: `self.0` is an `UnsafeCell<T>`, therefore the pointer returned by `.get()` 75 // must be valid and properly aligned. 76 self.0.get() 77 } 78 } 79 80 // This macro generates the function signature with given argument list and return type. 81 macro_rules! declare_atomic_method { 82 ( 83 $(#[doc=$doc:expr])* 84 $func:ident($($arg:ident : $arg_type:ty),*) $(-> $ret:ty)? 85 ) => { 86 paste!( 87 $(#[doc = $doc])* 88 fn [< atomic_ $func >]($($arg: $arg_type,)*) $(-> $ret)?; 89 ); 90 }; 91 ( 92 $(#[doc=$doc:expr])* 93 $func:ident [$variant:ident $($rest:ident)*]($($arg_sig:tt)*) $(-> $ret:ty)? 94 ) => { 95 paste!( 96 declare_atomic_method!( 97 $(#[doc = $doc])* 98 [< $func _ $variant >]($($arg_sig)*) $(-> $ret)? 99 ); 100 ); 101 102 declare_atomic_method!( 103 $(#[doc = $doc])* 104 $func [$($rest)*]($($arg_sig)*) $(-> $ret)? 105 ); 106 }; 107 ( 108 $(#[doc=$doc:expr])* 109 $func:ident []($($arg_sig:tt)*) $(-> $ret:ty)? 110 ) => { 111 declare_atomic_method!( 112 $(#[doc = $doc])* 113 $func($($arg_sig)*) $(-> $ret)? 114 ); 115 } 116 } 117 118 // This macro generates the function implementation with given argument list and return type, and it 119 // will replace "call(...)" expression with "$ctype _ $func" to call the real C function. 120 macro_rules! impl_atomic_method { 121 ( 122 ($ctype:ident) $func:ident($($arg:ident: $arg_type:ty),*) $(-> $ret:ty)? { 123 $unsafe:tt { call($($c_arg:expr),*) } 124 } 125 ) => { 126 paste!( 127 #[inline(always)] 128 fn [< atomic_ $func >]($($arg: $arg_type,)*) $(-> $ret)? { 129 // TODO: Ideally we want to use the SAFETY comments written at the macro invocation 130 // (e.g. in `declare_and_impl_atomic_methods!()`, however, since SAFETY comments 131 // are just comments, and they are not passed to macros as tokens, therefore we 132 // cannot use them here. One potential improvement is that if we support using 133 // attributes as an alternative for SAFETY comments, then we can use that for macro 134 // generating code. 135 // 136 // SAFETY: specified on macro invocation. 137 $unsafe { bindings::[< $ctype _ $func >]($($c_arg,)*) } 138 } 139 ); 140 }; 141 ( 142 ($ctype:ident) $func:ident[$variant:ident $($rest:ident)*]($($arg_sig:tt)*) $(-> $ret:ty)? { 143 $unsafe:tt { call($($arg:tt)*) } 144 } 145 ) => { 146 paste!( 147 impl_atomic_method!( 148 ($ctype) [< $func _ $variant >]($($arg_sig)*) $( -> $ret)? { 149 $unsafe { call($($arg)*) } 150 } 151 ); 152 ); 153 impl_atomic_method!( 154 ($ctype) $func [$($rest)*]($($arg_sig)*) $( -> $ret)? { 155 $unsafe { call($($arg)*) } 156 } 157 ); 158 }; 159 ( 160 ($ctype:ident) $func:ident[]($($arg_sig:tt)*) $( -> $ret:ty)? { 161 $unsafe:tt { call($($arg:tt)*) } 162 } 163 ) => { 164 impl_atomic_method!( 165 ($ctype) $func($($arg_sig)*) $(-> $ret)? { 166 $unsafe { call($($arg)*) } 167 } 168 ); 169 } 170 } 171 172 macro_rules! declare_atomic_ops_trait { 173 ( 174 $(#[$attr:meta])* $pub:vis trait $ops:ident { 175 $( 176 $(#[doc=$doc:expr])* 177 fn $func:ident [$($variant:ident),*]($($arg_sig:tt)*) $( -> $ret:ty)? { 178 $unsafe:tt { bindings::#call($($arg:tt)*) } 179 } 180 )* 181 } 182 ) => { 183 $(#[$attr])* 184 $pub trait $ops: AtomicImpl { 185 $( 186 declare_atomic_method!( 187 $(#[doc=$doc])* 188 $func[$($variant)*]($($arg_sig)*) $(-> $ret)? 189 ); 190 )* 191 } 192 } 193 } 194 195 macro_rules! impl_atomic_ops_for_one { 196 ( 197 $ty:ty => $ctype:ident, 198 $(#[$attr:meta])* $pub:vis trait $ops:ident { 199 $( 200 $(#[doc=$doc:expr])* 201 fn $func:ident [$($variant:ident),*]($($arg_sig:tt)*) $( -> $ret:ty)? { 202 $unsafe:tt { bindings::#call($($arg:tt)*) } 203 } 204 )* 205 } 206 ) => { 207 impl $ops for $ty { 208 $( 209 impl_atomic_method!( 210 ($ctype) $func[$($variant)*]($($arg_sig)*) $(-> $ret)? { 211 $unsafe { call($($arg)*) } 212 } 213 ); 214 )* 215 } 216 } 217 } 218 219 // Declares $ops trait with methods and implements the trait. 220 macro_rules! declare_and_impl_atomic_methods { 221 ( 222 [ $($map:tt)* ] 223 $(#[$attr:meta])* $pub:vis trait $ops:ident { $($body:tt)* } 224 ) => { 225 declare_and_impl_atomic_methods!( 226 @with_ops_def 227 [ $($map)* ] 228 ( $(#[$attr])* $pub trait $ops { $($body)* } ) 229 ); 230 }; 231 232 (@with_ops_def [ $($map:tt)* ] ( $($ops_def:tt)* )) => { 233 declare_atomic_ops_trait!( $($ops_def)* ); 234 235 declare_and_impl_atomic_methods!( 236 @munch 237 [ $($map)* ] 238 ( $($ops_def)* ) 239 ); 240 }; 241 242 (@munch [] ( $($ops_def:tt)* )) => {}; 243 244 (@munch [ $ty:ty => $ctype:ident $(, $($rest:tt)*)? ] ( $($ops_def:tt)* )) => { 245 impl_atomic_ops_for_one!( 246 $ty => $ctype, 247 $($ops_def)* 248 ); 249 250 declare_and_impl_atomic_methods!( 251 @munch 252 [ $($($rest)*)? ] 253 ( $($ops_def)* ) 254 ); 255 }; 256 } 257 258 declare_and_impl_atomic_methods!( 259 [ i8 => atomic_i8, i16 => atomic_i16, i32 => atomic, i64 => atomic64 ] 260 /// Basic atomic operations 261 pub trait AtomicBasicOps { 262 /// Atomic read (load). 263 fn read[acquire](a: &AtomicRepr<Self>) -> Self { 264 // SAFETY: `a.as_ptr()` is valid and properly aligned. 265 unsafe { bindings::#call(a.as_ptr().cast()) } 266 } 267 268 /// Atomic set (store). 269 fn set[release](a: &AtomicRepr<Self>, v: Self) { 270 // SAFETY: `a.as_ptr()` is valid and properly aligned. 271 unsafe { bindings::#call(a.as_ptr().cast(), v) } 272 } 273 } 274 ); 275 276 declare_and_impl_atomic_methods!( 277 [ i32 => atomic, i64 => atomic64 ] 278 /// Exchange and compare-and-exchange atomic operations 279 pub trait AtomicExchangeOps { 280 /// Atomic exchange. 281 /// 282 /// Atomically updates `*a` to `v` and returns the old value. 283 fn xchg[acquire, release, relaxed](a: &AtomicRepr<Self>, v: Self) -> Self { 284 // SAFETY: `a.as_ptr()` is valid and properly aligned. 285 unsafe { bindings::#call(a.as_ptr().cast(), v) } 286 } 287 288 /// Atomic compare and exchange. 289 /// 290 /// If `*a` == `*old`, atomically updates `*a` to `new`. Otherwise, `*a` is not 291 /// modified, `*old` is updated to the current value of `*a`. 292 /// 293 /// Return `true` if the update of `*a` occurred, `false` otherwise. 294 fn try_cmpxchg[acquire, release, relaxed]( 295 a: &AtomicRepr<Self>, old: &mut Self, new: Self 296 ) -> bool { 297 // SAFETY: `a.as_ptr()` is valid and properly aligned. `core::ptr::from_mut(old)` 298 // is valid and properly aligned. 299 unsafe { bindings::#call(a.as_ptr().cast(), core::ptr::from_mut(old), new) } 300 } 301 } 302 ); 303 304 declare_and_impl_atomic_methods!( 305 [ i32 => atomic, i64 => atomic64 ] 306 /// Atomic arithmetic operations 307 pub trait AtomicArithmeticOps { 308 /// Atomic add (wrapping). 309 /// 310 /// Atomically updates `*a` to `(*a).wrapping_add(v)`. 311 fn add[](a: &AtomicRepr<Self>, v: Self::Delta) { 312 // SAFETY: `a.as_ptr()` is valid and properly aligned. 313 unsafe { bindings::#call(v, a.as_ptr().cast()) } 314 } 315 316 /// Atomic fetch and add (wrapping). 317 /// 318 /// Atomically updates `*a` to `(*a).wrapping_add(v)`, and returns the value of `*a` 319 /// before the update. 320 fn fetch_add[acquire, release, relaxed](a: &AtomicRepr<Self>, v: Self::Delta) -> Self { 321 // SAFETY: `a.as_ptr()` is valid and properly aligned. 322 unsafe { bindings::#call(v, a.as_ptr().cast()) } 323 } 324 } 325 ); 326