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 // `i32` and `i64` are only supported atomic implementations. 17 impl private::Sealed for i32 {} 18 impl private::Sealed for i64 {} 19 20 /// A marker trait for types that implement atomic operations with C side primitives. 21 /// 22 /// This trait is sealed, and only types that have directly mapping to the C side atomics should 23 /// impl this: 24 /// 25 /// - `i32` maps to `atomic_t`. 26 /// - `i64` maps to `atomic64_t`. 27 pub trait AtomicImpl: Sized + Send + Copy + private::Sealed { 28 /// The type of the delta in arithmetic or logical operations. 29 /// 30 /// For example, in `atomic_add(ptr, v)`, it's the type of `v`. Usually it's the same type of 31 /// [`Self`], but it may be different for the atomic pointer type. 32 type Delta; 33 } 34 35 // `atomic_t` implements atomic operations on `i32`. 36 impl AtomicImpl for i32 { 37 type Delta = Self; 38 } 39 40 // `atomic64_t` implements atomic operations on `i64`. 41 impl AtomicImpl for i64 { 42 type Delta = Self; 43 } 44 45 /// Atomic representation. 46 #[repr(transparent)] 47 pub struct AtomicRepr<T: AtomicImpl>(UnsafeCell<T>); 48 49 impl<T: AtomicImpl> AtomicRepr<T> { 50 /// Creates a new atomic representation `T`. new(v: T) -> Self51 pub const fn new(v: T) -> Self { 52 Self(UnsafeCell::new(v)) 53 } 54 55 /// Returns a pointer to the underlying `T`. 56 /// 57 /// # Guarantees 58 /// 59 /// The returned pointer is valid and properly aligned (i.e. aligned to [`align_of::<T>()`]). as_ptr(&self) -> *mut T60 pub const fn as_ptr(&self) -> *mut T { 61 // GUARANTEE: `self.0` is an `UnsafeCell<T>`, therefore the pointer returned by `.get()` 62 // must be valid and properly aligned. 63 self.0.get() 64 } 65 } 66 67 // This macro generates the function signature with given argument list and return type. 68 macro_rules! declare_atomic_method { 69 ( 70 $(#[doc=$doc:expr])* 71 $func:ident($($arg:ident : $arg_type:ty),*) $(-> $ret:ty)? 72 ) => { 73 paste!( 74 $(#[doc = $doc])* 75 fn [< atomic_ $func >]($($arg: $arg_type,)*) $(-> $ret)?; 76 ); 77 }; 78 ( 79 $(#[doc=$doc:expr])* 80 $func:ident [$variant:ident $($rest:ident)*]($($arg_sig:tt)*) $(-> $ret:ty)? 81 ) => { 82 paste!( 83 declare_atomic_method!( 84 $(#[doc = $doc])* 85 [< $func _ $variant >]($($arg_sig)*) $(-> $ret)? 86 ); 87 ); 88 89 declare_atomic_method!( 90 $(#[doc = $doc])* 91 $func [$($rest)*]($($arg_sig)*) $(-> $ret)? 92 ); 93 }; 94 ( 95 $(#[doc=$doc:expr])* 96 $func:ident []($($arg_sig:tt)*) $(-> $ret:ty)? 97 ) => { 98 declare_atomic_method!( 99 $(#[doc = $doc])* 100 $func($($arg_sig)*) $(-> $ret)? 101 ); 102 } 103 } 104 105 // This macro generates the function implementation with given argument list and return type, and it 106 // will replace "call(...)" expression with "$ctype _ $func" to call the real C function. 107 macro_rules! impl_atomic_method { 108 ( 109 ($ctype:ident) $func:ident($($arg:ident: $arg_type:ty),*) $(-> $ret:ty)? { 110 $unsafe:tt { call($($c_arg:expr),*) } 111 } 112 ) => { 113 paste!( 114 #[inline(always)] 115 fn [< atomic_ $func >]($($arg: $arg_type,)*) $(-> $ret)? { 116 // TODO: Ideally we want to use the SAFETY comments written at the macro invocation 117 // (e.g. in `declare_and_impl_atomic_methods!()`, however, since SAFETY comments 118 // are just comments, and they are not passed to macros as tokens, therefore we 119 // cannot use them here. One potential improvement is that if we support using 120 // attributes as an alternative for SAFETY comments, then we can use that for macro 121 // generating code. 122 // 123 // SAFETY: specified on macro invocation. 124 $unsafe { bindings::[< $ctype _ $func >]($($c_arg,)*) } 125 } 126 ); 127 }; 128 ( 129 ($ctype:ident) $func:ident[$variant:ident $($rest:ident)*]($($arg_sig:tt)*) $(-> $ret:ty)? { 130 $unsafe:tt { call($($arg:tt)*) } 131 } 132 ) => { 133 paste!( 134 impl_atomic_method!( 135 ($ctype) [< $func _ $variant >]($($arg_sig)*) $( -> $ret)? { 136 $unsafe { call($($arg)*) } 137 } 138 ); 139 ); 140 impl_atomic_method!( 141 ($ctype) $func [$($rest)*]($($arg_sig)*) $( -> $ret)? { 142 $unsafe { call($($arg)*) } 143 } 144 ); 145 }; 146 ( 147 ($ctype:ident) $func:ident[]($($arg_sig:tt)*) $( -> $ret:ty)? { 148 $unsafe:tt { call($($arg:tt)*) } 149 } 150 ) => { 151 impl_atomic_method!( 152 ($ctype) $func($($arg_sig)*) $(-> $ret)? { 153 $unsafe { call($($arg)*) } 154 } 155 ); 156 } 157 } 158 159 // Delcares $ops trait with methods and implements the trait for `i32` and `i64`. 160 macro_rules! declare_and_impl_atomic_methods { 161 ($(#[$attr:meta])* $pub:vis trait $ops:ident { 162 $( 163 $(#[doc=$doc:expr])* 164 fn $func:ident [$($variant:ident),*]($($arg_sig:tt)*) $( -> $ret:ty)? { 165 $unsafe:tt { bindings::#call($($arg:tt)*) } 166 } 167 )* 168 }) => { 169 $(#[$attr])* 170 $pub trait $ops: AtomicImpl { 171 $( 172 declare_atomic_method!( 173 $(#[doc=$doc])* 174 $func[$($variant)*]($($arg_sig)*) $(-> $ret)? 175 ); 176 )* 177 } 178 179 impl $ops for i32 { 180 $( 181 impl_atomic_method!( 182 (atomic) $func[$($variant)*]($($arg_sig)*) $(-> $ret)? { 183 $unsafe { call($($arg)*) } 184 } 185 ); 186 )* 187 } 188 189 impl $ops for i64 { 190 $( 191 impl_atomic_method!( 192 (atomic64) $func[$($variant)*]($($arg_sig)*) $(-> $ret)? { 193 $unsafe { call($($arg)*) } 194 } 195 ); 196 )* 197 } 198 } 199 } 200 201 declare_and_impl_atomic_methods!( 202 /// Basic atomic operations 203 pub trait AtomicBasicOps { 204 /// Atomic read (load). 205 fn read[acquire](a: &AtomicRepr<Self>) -> Self { 206 // SAFETY: `a.as_ptr()` is valid and properly aligned. 207 unsafe { bindings::#call(a.as_ptr().cast()) } 208 } 209 210 /// Atomic set (store). 211 fn set[release](a: &AtomicRepr<Self>, v: Self) { 212 // SAFETY: `a.as_ptr()` is valid and properly aligned. 213 unsafe { bindings::#call(a.as_ptr().cast(), v) } 214 } 215 } 216 ); 217 218 declare_and_impl_atomic_methods!( 219 /// Exchange and compare-and-exchange atomic operations 220 pub trait AtomicExchangeOps { 221 /// Atomic exchange. 222 /// 223 /// Atomically updates `*a` to `v` and returns the old value. 224 fn xchg[acquire, release, relaxed](a: &AtomicRepr<Self>, v: Self) -> Self { 225 // SAFETY: `a.as_ptr()` is valid and properly aligned. 226 unsafe { bindings::#call(a.as_ptr().cast(), v) } 227 } 228 229 /// Atomic compare and exchange. 230 /// 231 /// If `*a` == `*old`, atomically updates `*a` to `new`. Otherwise, `*a` is not 232 /// modified, `*old` is updated to the current value of `*a`. 233 /// 234 /// Return `true` if the update of `*a` occurred, `false` otherwise. 235 fn try_cmpxchg[acquire, release, relaxed]( 236 a: &AtomicRepr<Self>, old: &mut Self, new: Self 237 ) -> bool { 238 // SAFETY: `a.as_ptr()` is valid and properly aligned. `core::ptr::from_mut(old)` 239 // is valid and properly aligned. 240 unsafe { bindings::#call(a.as_ptr().cast(), core::ptr::from_mut(old), new) } 241 } 242 } 243 ); 244 245 declare_and_impl_atomic_methods!( 246 /// Atomic arithmetic operations 247 pub trait AtomicArithmeticOps { 248 /// Atomic add (wrapping). 249 /// 250 /// Atomically updates `*a` to `(*a).wrapping_add(v)`. 251 fn add[](a: &AtomicRepr<Self>, v: Self::Delta) { 252 // SAFETY: `a.as_ptr()` is valid and properly aligned. 253 unsafe { bindings::#call(v, a.as_ptr().cast()) } 254 } 255 256 /// Atomic fetch and add (wrapping). 257 /// 258 /// Atomically updates `*a` to `(*a).wrapping_add(v)`, and returns the value of `*a` 259 /// before the update. 260 fn fetch_add[acquire, release, relaxed](a: &AtomicRepr<Self>, v: Self::Delta) -> Self { 261 // SAFETY: `a.as_ptr()` is valid and properly aligned. 262 unsafe { bindings::#call(v, a.as_ptr().cast()) } 263 } 264 } 265 ); 266