atomic_int/fallback/
mod.rs

1/*
2 * Copyright 2023, 2025 taylor.fish <contact@taylor.fish>
3 *
4 * This file is part of atomic-int.
5 *
6 * atomic-int is licensed under the Apache License, Version 2.0
7 * (the "License"); you may not use atomic-int except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#![allow(unused_macros)]
20#[allow(unused_imports)]
21use core::cell::UnsafeCell;
22use core::ops::{Deref, DerefMut};
23#[cfg(doc)]
24use core::sync::atomic;
25use core::sync::atomic::{AtomicBool, Ordering};
26
27#[cfg_attr(not(all(feature = "signal", unix)), path = "signal_none.rs")]
28mod signal;
29use signal::SignalGuard;
30
31struct Guard<'a, T> {
32    value: &'a mut T,
33    lock: &'a AtomicBool,
34    order: Ordering,
35    _signal: SignalGuard,
36}
37
38impl<'a, T> Deref for Guard<'a, T> {
39    type Target = T;
40
41    fn deref(&self) -> &T {
42        self.value
43    }
44}
45
46impl<'a, T> DerefMut for Guard<'a, T> {
47    fn deref_mut(&mut self) -> &mut T {
48        self.value
49    }
50}
51
52impl<'a, T> Drop for Guard<'a, T> {
53    fn drop(&mut self) {
54        self.lock.store(false, match self.order {
55            Ordering::SeqCst => Ordering::SeqCst,
56            _ => Ordering::Release,
57        });
58    }
59}
60
61#[allow(dead_code)]
62#[allow(unused_imports)]
63use Guard as _;
64
65macro_rules! define_fallback {
66    ($atomic:ident$(<$generic:ident>)?, $type:ty, $doc:expr) => {
67        pub struct $atomic$(<$generic>)? {
68            value: UnsafeCell<$type>,
69            lock: AtomicBool,
70        }
71
72        impl$(<$generic>)? $atomic$(<$generic>)? {
73            /// Creates a new atomic.
74            #[doc = concat!("\n\n", $doc, "::new`].")]
75            pub const fn new(v: $type) -> Self {
76                Self {
77                    value: UnsafeCell::new(v),
78                    lock: AtomicBool::new(false),
79                }
80            }
81
82            fn lock(&self, order: Ordering) -> Guard<'_, $type> {
83                let signal = SignalGuard::new();
84                while self
85                    .lock
86                    .compare_exchange_weak(
87                        false,
88                        true,
89                        match order {
90                            Ordering::SeqCst => Ordering::SeqCst,
91                            _ => Ordering::Acquire,
92                        },
93                        Ordering::Relaxed,
94                    )
95                    .is_err()
96                {
97                    while self.lock.load(Ordering::Relaxed) {
98                        core::hint::spin_loop();
99                    }
100                }
101                Guard {
102                    // SAFETY: This type uses locks to ensure the value won't
103                    // be accessed concurrently.
104                    value: unsafe { &mut *self.value.get() },
105                    lock: &self.lock,
106                    order,
107                    _signal: signal,
108                }
109            }
110
111            /// Returns a mutable reference to the underlying value.
112            #[doc = concat!("\n\n", $doc, "::get_mut`].")]
113            pub fn get_mut(&mut self) -> &mut $type {
114                self.value.get_mut()
115            }
116
117            /// Consumes the atomic and returns the contained value.
118            #[doc = concat!("\n\n", $doc, "::into_inner`].")]
119            pub fn into_inner(self) -> $type {
120                self.value.into_inner()
121            }
122
123            /// Loads a value from the atomic.
124            #[doc = concat!("\n\n", $doc, "::load`].")]
125            pub fn load(&self, order: Ordering) -> $type {
126                *self.lock(order)
127            }
128
129            /// Stores a value into the atomic.
130            #[doc = concat!("\n\n", $doc, "::store`].")]
131            pub fn store(&self, val: $type, order: Ordering) {
132                let mut guard = self.lock(order);
133                *guard = val;
134            }
135
136            /// Stores a value into the atomic, returning the previous
137            /// value.
138            #[doc = concat!("\n\n", $doc, "::swap`].")]
139            pub fn swap(&self, val: $type, order: Ordering) -> $type {
140                let mut guard = self.lock(order);
141                core::mem::replace(&mut *guard, val)
142            }
143
144            /// Stores a value into the atomic if the current value is the same
145            /// as the `current` value.
146            #[doc = concat!("\n\n", $doc, "::compare_and_swap`].")]
147            pub fn compare_and_swap(
148                &self,
149                current: $type,
150                new: $type,
151                order: Ordering,
152            ) -> $type {
153                match self.compare_exchange(current, new, order, order) {
154                    Ok(prev) => prev,
155                    Err(prev) => prev,
156                }
157            }
158
159            /// Stores a value into the atomic if the current value is the same
160            /// as the `current` value.
161            #[doc = concat!("\n\n", $doc, "::compare_exchange`].")]
162            pub fn compare_exchange(
163                &self,
164                current: $type,
165                new: $type,
166                success: Ordering,
167                failure: Ordering,
168            ) -> Result<$type, $type> {
169                let mut guard = self.lock(success);
170                let prev = *guard;
171                if prev == current {
172                    *guard = new;
173                    Ok(prev)
174                } else {
175                    guard.order = failure;
176                    Err(prev)
177                }
178            }
179
180            /// Stores a value into the atomic if the current value is the same
181            /// as the `current` value.
182            #[doc = concat!("\n\n", $doc, "::compare_exchange_weak`].")]
183            pub fn compare_exchange_weak(
184                &self,
185                current: $type,
186                new: $type,
187                success: Ordering,
188                failure: Ordering,
189            ) -> Result<$type, $type> {
190                self.compare_exchange(current, new, success, failure)
191            }
192
193            /// Fetches the value, and applies a function to it that returns an
194            /// optional new value.
195            #[doc = concat!("\n\n", $doc, "::fetch_update`].")]
196            pub fn fetch_update<F>(
197                &self,
198                set_order: Ordering,
199                fetch_order: Ordering,
200                mut f: F,
201            ) -> Result<$type, $type>
202            where
203                F: FnMut($type) -> Option<$type>,
204            {
205                let _ = fetch_order;
206                let mut guard = self.lock(set_order);
207                let prev = *guard;
208                if let Some(value) = f(prev) {
209                    *guard = value;
210                    Ok(prev)
211                } else {
212                    Err(prev)
213                }
214            }
215
216            /// Returns a mutable pointer to the underlying value.
217            #[doc = concat!("\n\n", $doc, "::as_ptr`].")]
218            pub const fn as_ptr(&self) -> *mut $type {
219                self.value.get()
220            }
221        }
222
223        // SAFETY: This type uses locks to ensure concurrent access is sound.
224        unsafe impl$(<$generic>)? Sync for $atomic$(<$generic>)? {}
225    };
226}
227
228macro_rules! define_fallback_int {
229    ($atomic:ident, $int:ty, $doc:expr) => {
230        define_fallback!($atomic, $int, $doc);
231
232        impl $atomic {
233            /// Adds to the current value, returning the previous value.
234            #[doc = concat!("\n\n", $doc, "::fetch_add`].")]
235            pub fn fetch_add(&self, val: $int, order: Ordering) -> $int {
236                let mut guard = self.lock(order);
237                let prev = *guard;
238                *guard += val;
239                prev
240            }
241
242            /// Subtracts from the current value, returning the previous value.
243            #[doc = concat!("\n\n", $doc, "::fetch_sub`].")]
244            pub fn fetch_sub(&self, val: $int, order: Ordering) -> $int {
245                let mut guard = self.lock(order);
246                let prev = *guard;
247                *guard -= val;
248                prev
249            }
250
251            /// Bitwise “and” with the current value.
252            #[doc = concat!("\n\n", $doc, "::fetch_and`].")]
253            pub fn fetch_and(&self, val: $int, order: Ordering) -> $int {
254                let mut guard = self.lock(order);
255                let prev = *guard;
256                *guard &= val;
257                prev
258            }
259
260            /// Bitwise “nand” with the current value.
261            #[doc = concat!("\n\n", $doc, "::fetch_nand`].")]
262            pub fn fetch_nand(&self, val: $int, order: Ordering) -> $int {
263                let mut guard = self.lock(order);
264                let prev = *guard;
265                *guard = !(prev & val);
266                prev
267            }
268
269            /// Bitwise “or” with the current value.
270            #[doc = concat!("\n\n", $doc, "::fetch_or`].")]
271            pub fn fetch_or(&self, val: $int, order: Ordering) -> $int {
272                let mut guard = self.lock(order);
273                let prev = *guard;
274                *guard |= val;
275                prev
276            }
277
278            /// Bitwise “xor” with the current value.
279            #[doc = concat!("\n\n", $doc, "::fetch_xor`].")]
280            pub fn fetch_xor(&self, val: $int, order: Ordering) -> $int {
281                let mut guard = self.lock(order);
282                let prev = *guard;
283                *guard ^= val;
284                prev
285            }
286
287            /// Maximum with the current value.
288            #[doc = concat!("\n\n", $doc, "::fetch_max`].")]
289            pub fn fetch_max(&self, val: $int, order: Ordering) -> $int {
290                let mut guard = self.lock(order);
291                let prev = *guard;
292                *guard = prev.max(val);
293                prev
294            }
295
296            /// Minimum with the current value.
297            #[doc = concat!("\n\n", $doc, "::fetch_min`].")]
298            pub fn fetch_min(&self, val: $int, order: Ordering) -> $int {
299                let mut guard = self.lock(order);
300                let prev = *guard;
301                *guard = prev.min(val);
302                prev
303            }
304        }
305    };
306}
307
308macro_rules! define_primitive_fallback {
309    ($atomic:ident, $int:ident, [$($cfg:tt)*], $($x:tt)*) => {
310        #[cfg(any(doc, feature = "force-fallback", not($($cfg)*)))]
311        define_fallback_int!(
312            $atomic,
313            $int,
314            concat!("See [`atomic::", stringify!($atomic))
315        );
316    };
317}
318
319#[cfg(feature = "primitives")]
320with_primitive_atomics!(define_primitive_fallback);
321
322#[cfg(feature = "primitives")]
323#[cfg(any(doc, feature = "force-fallback", not(target_has_atomic = "ptr")))]
324define_fallback!(AtomicPtr<T>, *mut T, "See [`atomic::AtomicPtr");
325
326macro_rules! define_c_fallback {
327    ($atomic:ident, $int:ident, $($x:tt)*) => {
328        define_fallback_int!(
329            $atomic,
330            super::c_types::$int,
331            "See, e.g., [`atomic::AtomicI32"
332        );
333    };
334}
335
336with_c_atomics!(define_c_fallback);
337
338#[cfg(doc)]
339define_fallback_int!(AtomicFallback, i32, "See, e.g., [`atomic::AtomicI32");
340
341#[cfg(doc)]
342define_fallback!(AtomicFallbackPtr<T>, *mut T, "See [`atomic::AtomicPtr");
343
344#[allow(dead_code)]
345fn allow_unused() {
346    let _ = SignalGuard::new;
347}