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