| 1 | |
| 2 |
|
| 3 | |
| 4 | |
| 5 | |
| 6 |
|
| 7 | use crate::{
|
| 8 | bindings,
|
| 9 | build_assert::static_assert,
|
| 10 | macros::paste, |
| 11 | };
|
| 12 | use core::cell::UnsafeCell;
|
| 13 | use ffi::c_void;
|
| 14 |
|
| 15 | mod private {
|
| 16 | |
| 17 | pub trait Sealed {}
|
| 18 | }
|
| 19 |
|
| 20 | |
| 21 | |
| 22 | |
| 23 | impl private::Sealed for i8 {}
|
| 24 | impl private::Sealed for i16 {}
|
| 25 | impl private::Sealed for *const c_void {}
|
| 26 | impl private::Sealed for i32 {}
|
| 27 | impl private::Sealed for i64 {}
|
| 28 |
|
| 29 | |
| 30 | |
| 31 | |
| 32 | |
| 33 | |
| 34 | |
| 35 | |
| 36 | |
| 37 | pub trait AtomicImpl: Sized + Copy + private::Sealed {
|
| 38 | |
| 39 | |
| 40 | |
| 41 | |
| 42 | type Delta;
|
| 43 | }
|
| 44 |
|
| 45 | |
| 46 | |
| 47 | |
| 48 | |
| 49 | |
| 50 | |
| 51 | |
| 52 | static_assert!(
|
| 53 | cfg!(CONFIG_ARCH_SUPPORTS_ATOMIC_RMW),
|
| 54 | "The current implementation of atomic i8/i16/ptr relies on the architecure being \
|
| 55 | ARCH_SUPPORTS_ATOMIC_RMW"
|
| 56 | );
|
| 57 |
|
| 58 | impl AtomicImpl for i8 {
|
| 59 | type Delta = Self;
|
| 60 | }
|
| 61 |
|
| 62 | impl AtomicImpl for i16 {
|
| 63 | type Delta = Self;
|
| 64 | }
|
| 65 |
|
| 66 | impl AtomicImpl for *const c_void {
|
| 67 | type Delta = isize;
|
| 68 | }
|
| 69 |
|
| 70 | |
| 71 | impl AtomicImpl for i32 {
|
| 72 | type Delta = Self;
|
| 73 | }
|
| 74 |
|
| 75 | |
| 76 | impl AtomicImpl for i64 {
|
| 77 | type Delta = Self;
|
| 78 | }
|
| 79 |
|
| 80 | |
| 81 | #[repr(transparent)]
|
| 82 | pub struct AtomicRepr<T: AtomicImpl>(UnsafeCell<T>);
|
| 83 |
|
| 84 | impl<T: AtomicImpl> AtomicRepr<T> {
|
| 85 | |
| 86 | pub const fn new(v: T) -> Self {
|
| 87 | Self(UnsafeCell::new(v))
|
| 88 | }
|
| 89 |
|
| 90 | |
| 91 | |
| 92 | |
| 93 | |
| 94 | |
| 95 | pub const fn as_ptr(&self) -> *mut T {
|
| 96 | |
| 97 | |
| 98 | self.0.get()
|
| 99 | }
|
| 100 | }
|
| 101 |
|
| 102 | |
| 103 | macro_rules! declare_atomic_method {
|
| 104 | (
|
| 105 | $(#[doc=$doc:expr])*
|
| 106 | $func:ident($($arg:ident : $arg_type:ty),*) $(-> $ret:ty)?
|
| 107 | ) => {
|
| 108 | paste!(
|
| 109 | $(#[doc = $doc])*
|
| 110 | fn [< atomic_ $func >]($($arg: $arg_type,)*) $(-> $ret)?;
|
| 111 | );
|
| 112 | };
|
| 113 | (
|
| 114 | $(#[doc=$doc:expr])*
|
| 115 | $func:ident [$variant:ident $($rest:ident)*]($($arg_sig:tt)*) $(-> $ret:ty)?
|
| 116 | ) => {
|
| 117 | paste!(
|
| 118 | declare_atomic_method!(
|
| 119 | $(#[doc = $doc])*
|
| 120 | [< $func _ $variant >]($($arg_sig)*) $(-> $ret)?
|
| 121 | );
|
| 122 | );
|
| 123 |
|
| 124 | declare_atomic_method!(
|
| 125 | $(#[doc = $doc])*
|
| 126 | $func [$($rest)*]($($arg_sig)*) $(-> $ret)?
|
| 127 | );
|
| 128 | };
|
| 129 | (
|
| 130 | $(#[doc=$doc:expr])*
|
| 131 | $func:ident []($($arg_sig:tt)*) $(-> $ret:ty)?
|
| 132 | ) => {
|
| 133 | declare_atomic_method!(
|
| 134 | $(#[doc = $doc])*
|
| 135 | $func($($arg_sig)*) $(-> $ret)?
|
| 136 | );
|
| 137 | }
|
| 138 | }
|
| 139 |
|
| 140 | |
| 141 | |
| 142 | macro_rules! impl_atomic_method {
|
| 143 | (
|
| 144 | ($ctype:ident) $func:ident($($arg:ident: $arg_type:ty),*) $(-> $ret:ty)? {
|
| 145 | $unsafe:tt { call($($c_arg:expr),*) }
|
| 146 | }
|
| 147 | ) => {
|
| 148 | paste!(
|
| 149 | #[inline(always)]
|
| 150 | fn [< atomic_ $func >]($($arg: $arg_type,)*) $(-> $ret)? {
|
| 151 | |
| 152 | |
| 153 | |
| 154 | |
| 155 | |
| 156 | |
| 157 | |
| 158 | |
| 159 | $unsafe { bindings::[< $ctype _ $func >]($($c_arg,)*) }
|
| 160 | }
|
| 161 | );
|
| 162 | };
|
| 163 | (
|
| 164 | ($ctype:ident) $func:ident[$variant:ident $($rest:ident)*]($($arg_sig:tt)*) $(-> $ret:ty)? {
|
| 165 | $unsafe:tt { call($($arg:tt)*) }
|
| 166 | }
|
| 167 | ) => {
|
| 168 | paste!(
|
| 169 | impl_atomic_method!(
|
| 170 | ($ctype) [< $func _ $variant >]($($arg_sig)*) $( -> $ret)? {
|
| 171 | $unsafe { call($($arg)*) }
|
| 172 | }
|
| 173 | );
|
| 174 | );
|
| 175 | impl_atomic_method!(
|
| 176 | ($ctype) $func [$($rest)*]($($arg_sig)*) $( -> $ret)? {
|
| 177 | $unsafe { call($($arg)*) }
|
| 178 | }
|
| 179 | );
|
| 180 | };
|
| 181 | (
|
| 182 | ($ctype:ident) $func:ident[]($($arg_sig:tt)*) $( -> $ret:ty)? {
|
| 183 | $unsafe:tt { call($($arg:tt)*) }
|
| 184 | }
|
| 185 | ) => {
|
| 186 | impl_atomic_method!(
|
| 187 | ($ctype) $func($($arg_sig)*) $(-> $ret)? {
|
| 188 | $unsafe { call($($arg)*) }
|
| 189 | }
|
| 190 | );
|
| 191 | }
|
| 192 | }
|
| 193 |
|
| 194 | macro_rules! declare_atomic_ops_trait {
|
| 195 | (
|
| 196 | $(#[$attr:meta])* $pub:vis trait $ops:ident {
|
| 197 | $(
|
| 198 | $(#[doc=$doc:expr])*
|
| 199 | fn $func:ident [$($variant:ident),*]($($arg_sig:tt)*) $( -> $ret:ty)? {
|
| 200 | $unsafe:tt { bindings::#call($($arg:tt)*) }
|
| 201 | }
|
| 202 | )*
|
| 203 | }
|
| 204 | ) => {
|
| 205 | $(#[$attr])*
|
| 206 | $pub trait $ops: AtomicImpl {
|
| 207 | $(
|
| 208 | declare_atomic_method!(
|
| 209 | $(#[doc=$doc])*
|
| 210 | $func[$($variant)*]($($arg_sig)*) $(-> $ret)?
|
| 211 | );
|
| 212 | )*
|
| 213 | }
|
| 214 | }
|
| 215 | }
|
| 216 |
|
| 217 | macro_rules! impl_atomic_ops_for_one {
|
| 218 | (
|
| 219 | $ty:ty => $ctype:ident,
|
| 220 | $(#[$attr:meta])* $pub:vis trait $ops:ident {
|
| 221 | $(
|
| 222 | $(#[doc=$doc:expr])*
|
| 223 | fn $func:ident [$($variant:ident),*]($($arg_sig:tt)*) $( -> $ret:ty)? {
|
| 224 | $unsafe:tt { bindings::#call($($arg:tt)*) }
|
| 225 | }
|
| 226 | )*
|
| 227 | }
|
| 228 | ) => {
|
| 229 | impl $ops for $ty {
|
| 230 | $(
|
| 231 | impl_atomic_method!(
|
| 232 | ($ctype) $func[$($variant)*]($($arg_sig)*) $(-> $ret)? {
|
| 233 | $unsafe { call($($arg)*) }
|
| 234 | }
|
| 235 | );
|
| 236 | )*
|
| 237 | }
|
| 238 | }
|
| 239 | }
|
| 240 |
|
| 241 | |
| 242 | macro_rules! declare_and_impl_atomic_methods {
|
| 243 | (
|
| 244 | [ $($map:tt)* ]
|
| 245 | $(#[$attr:meta])* $pub:vis trait $ops:ident { $($body:tt)* }
|
| 246 | ) => {
|
| 247 | declare_and_impl_atomic_methods!(
|
| 248 | @with_ops_def
|
| 249 | [ $($map)* ]
|
| 250 | ( $(#[$attr])* $pub trait $ops { $($body)* } )
|
| 251 | );
|
| 252 | };
|
| 253 |
|
| 254 | (@with_ops_def [ $($map:tt)* ] ( $($ops_def:tt)* )) => {
|
| 255 | declare_atomic_ops_trait!( $($ops_def)* );
|
| 256 |
|
| 257 | declare_and_impl_atomic_methods!(
|
| 258 | @munch
|
| 259 | [ $($map)* ]
|
| 260 | ( $($ops_def)* )
|
| 261 | );
|
| 262 | };
|
| 263 |
|
| 264 | (@munch [] ( $($ops_def:tt)* )) => {};
|
| 265 |
|
| 266 | (@munch [ $ty:ty => $ctype:ident $(, $($rest:tt)*)? ] ( $($ops_def:tt)* )) => {
|
| 267 | impl_atomic_ops_for_one!(
|
| 268 | $ty => $ctype,
|
| 269 | $($ops_def)*
|
| 270 | );
|
| 271 |
|
| 272 | declare_and_impl_atomic_methods!(
|
| 273 | @munch
|
| 274 | [ $($($rest)*)? ]
|
| 275 | ( $($ops_def)* )
|
| 276 | );
|
| 277 | };
|
| 278 | }
|
| 279 |
|
| 280 | declare_and_impl_atomic_methods!(
|
| 281 | [ i8 => atomic_i8, i16 => atomic_i16, *const c_void => atomic_ptr, i32 => atomic, i64 => atomic64 ]
|
| 282 | |
| 283 | pub trait AtomicBasicOps {
|
| 284 | |
| 285 | fn read[acquire](a: &AtomicRepr<Self>) -> Self {
|
| 286 | |
| 287 | unsafe { bindings::#call(a.as_ptr().cast()) }
|
| 288 | }
|
| 289 |
|
| 290 | |
| 291 | fn set[release](a: &AtomicRepr<Self>, v: Self) {
|
| 292 | |
| 293 | unsafe { bindings::#call(a.as_ptr().cast(), v) }
|
| 294 | }
|
| 295 | }
|
| 296 | );
|
| 297 |
|
| 298 | declare_and_impl_atomic_methods!(
|
| 299 | [ i8 => atomic_i8, i16 => atomic_i16, *const c_void => atomic_ptr, i32 => atomic, i64 => atomic64 ]
|
| 300 | |
| 301 | pub trait AtomicExchangeOps {
|
| 302 | |
| 303 | |
| 304 | |
| 305 | fn xchg[acquire, release, relaxed](a: &AtomicRepr<Self>, v: Self) -> Self {
|
| 306 | |
| 307 | unsafe { bindings::#call(a.as_ptr().cast(), v) }
|
| 308 | }
|
| 309 |
|
| 310 | |
| 311 | |
| 312 | |
| 313 | |
| 314 | |
| 315 | |
| 316 | fn try_cmpxchg[acquire, release, relaxed](
|
| 317 | a: &AtomicRepr<Self>, old: &mut Self, new: Self
|
| 318 | ) -> bool {
|
| 319 | |
| 320 | |
| 321 | unsafe { bindings::#call(a.as_ptr().cast(), core::ptr::from_mut(old), new) }
|
| 322 | }
|
| 323 | }
|
| 324 | );
|
| 325 |
|
| 326 | declare_and_impl_atomic_methods!(
|
| 327 | [ i32 => atomic, i64 => atomic64 ]
|
| 328 | |
| 329 | pub trait AtomicArithmeticOps {
|
| 330 | |
| 331 | |
| 332 | |
| 333 | fn add[](a: &AtomicRepr<Self>, v: Self::Delta) {
|
| 334 | |
| 335 | unsafe { bindings::#call(v, a.as_ptr().cast()) }
|
| 336 | }
|
| 337 |
|
| 338 | |
| 339 | |
| 340 | |
| 341 | |
| 342 | fn fetch_add[acquire, release, relaxed](a: &AtomicRepr<Self>, v: Self::Delta) -> Self {
|
| 343 | |
| 344 | unsafe { bindings::#call(v, a.as_ptr().cast()) }
|
| 345 | }
|
| 346 |
|
| 347 | fn fetch_sub[acquire, release, relaxed](a: &AtomicRepr<Self>, v: Self::Delta) -> Self {
|
| 348 | |
| 349 | unsafe { bindings::#call(v, a.as_ptr().cast()) }
|
| 350 | }
|
| 351 | }
|
| 352 | );
|