portable_atomic/imp/interrupt/
mod.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3/*
4Critical section based fallback implementations
5
6This module supports two different critical section implementations:
7- Built-in "disable all interrupts".
8- Call into the `critical-section` crate (which allows the user to plug any implementation).
9
10The `critical-section`-based fallback is enabled when the user asks for it with the `critical-section`
11Cargo feature.
12
13The "disable interrupts" fallback is not sound on multi-core systems.
14Also, this uses privileged instructions to disable interrupts, so it usually
15doesn't work on unprivileged mode. Using this fallback in an environment where privileged
16instructions are not available is also usually considered **unsound**,
17although the details are system-dependent.
18
19Therefore, this implementation will only be enabled in one of the following cases:
20
21- When the user explicitly declares that the system is single-core and that
22  privileged instructions are available using an unsafe cfg.
23- When we can safely assume that the system is single-core and that
24  privileged instructions are available on the system.
25
26AVR, which is single core[^avr1] and LLVM also generates code that disables
27interrupts [^avr2] in atomic ops by default, is considered the latter.
28MSP430 as well.
29
30See also README.md of this directory.
31
32[^avr1]: https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc1/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp#L1074
33[^avr2]: https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0-rc1/llvm/test/CodeGen/AVR/atomics/load16.ll#L5
34*/
35
36// On some platforms, atomic load/store can be implemented in a more efficient
37// way than disabling interrupts. On MSP430, some RMWs that do not return the
38// previous value can also be optimized.
39//
40// Note: On single-core systems, it is okay to use critical session-based
41// CAS together with atomic load/store. The load/store will not be
42// called while interrupts are disabled, and since the load/store is
43// atomic, it is not affected by interrupts even if interrupts are enabled.
44#[cfg(not(any(
45    all(target_arch = "avr", portable_atomic_no_asm),
46    feature = "critical-section",
47)))]
48use self::arch::atomic;
49
50#[cfg(not(feature = "critical-section"))]
51#[cfg_attr(
52    all(
53        target_arch = "arm",
54        any(target_feature = "mclass", portable_atomic_target_feature = "mclass"),
55    ),
56    path = "armv6m.rs"
57)]
58#[cfg_attr(
59    all(
60        target_arch = "arm",
61        not(any(target_feature = "mclass", portable_atomic_target_feature = "mclass")),
62    ),
63    path = "armv4t.rs"
64)]
65#[cfg_attr(target_arch = "avr", path = "avr.rs")]
66#[cfg_attr(target_arch = "msp430", path = "msp430.rs")]
67#[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), path = "riscv.rs")]
68#[cfg_attr(target_arch = "xtensa", path = "xtensa.rs")]
69mod arch;
70
71use core::{cell::UnsafeCell, sync::atomic::Ordering};
72
73// Critical section implementations might use locks internally.
74#[cfg(feature = "critical-section")]
75const IS_ALWAYS_LOCK_FREE: bool = false;
76// Consider atomic operations based on disabling interrupts on single-core
77// systems are lock-free. (We consider the pre-v6 Arm Linux's atomic operations
78// provided in a similar way by the Linux kernel to be lock-free.)
79#[cfg(not(feature = "critical-section"))]
80const IS_ALWAYS_LOCK_FREE: bool = true;
81
82#[cfg(feature = "critical-section")]
83#[inline]
84fn with<F, R>(f: F) -> R
85where
86    F: FnOnce() -> R,
87{
88    critical_section::with(|_| f())
89}
90#[cfg(not(feature = "critical-section"))]
91#[inline(always)]
92fn with<F, R>(f: F) -> R
93where
94    F: FnOnce() -> R,
95{
96    // Get current interrupt state and disable interrupts
97    let state = arch::disable();
98
99    let r = f();
100
101    // Restore interrupt state
102    // SAFETY: the state was retrieved by the previous `disable`.
103    unsafe { arch::restore(state) }
104
105    r
106}
107
108#[cfg_attr(target_pointer_width = "16", repr(C, align(2)))]
109#[cfg_attr(target_pointer_width = "32", repr(C, align(4)))]
110#[cfg_attr(target_pointer_width = "64", repr(C, align(8)))]
111#[cfg_attr(target_pointer_width = "128", repr(C, align(16)))]
112pub(crate) struct AtomicPtr<T> {
113    p: UnsafeCell<*mut T>,
114}
115
116// SAFETY: any data races are prevented by disabling interrupts or
117// atomic intrinsics (see module-level comments).
118unsafe impl<T> Send for AtomicPtr<T> {}
119// SAFETY: any data races are prevented by disabling interrupts or
120// atomic intrinsics (see module-level comments).
121unsafe impl<T> Sync for AtomicPtr<T> {}
122
123impl<T> AtomicPtr<T> {
124    #[inline]
125    pub(crate) const fn new(p: *mut T) -> Self {
126        Self { p: UnsafeCell::new(p) }
127    }
128
129    #[inline]
130    pub(crate) fn is_lock_free() -> bool {
131        Self::IS_ALWAYS_LOCK_FREE
132    }
133    pub(crate) const IS_ALWAYS_LOCK_FREE: bool = IS_ALWAYS_LOCK_FREE;
134
135    #[inline]
136    #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
137    pub(crate) fn load(&self, order: Ordering) -> *mut T {
138        crate::utils::assert_load_ordering(order);
139        #[cfg(not(any(target_arch = "avr", feature = "critical-section")))]
140        {
141            self.as_native().load(order)
142        }
143        #[cfg(any(target_arch = "avr", feature = "critical-section"))]
144        // SAFETY: any data races are prevented by disabling interrupts (see
145        // module-level comments) and the raw pointer is valid because we got it
146        // from a reference.
147        with(|| unsafe { self.p.get().read() })
148    }
149
150    #[inline]
151    #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
152    pub(crate) fn store(&self, ptr: *mut T, order: Ordering) {
153        crate::utils::assert_store_ordering(order);
154        #[cfg(not(any(target_arch = "avr", feature = "critical-section")))]
155        {
156            self.as_native().store(ptr, order);
157        }
158        #[cfg(any(target_arch = "avr", feature = "critical-section"))]
159        // SAFETY: any data races are prevented by disabling interrupts (see
160        // module-level comments) and the raw pointer is valid because we got it
161        // from a reference.
162        with(|| unsafe { self.p.get().write(ptr) });
163    }
164
165    #[inline]
166    pub(crate) fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
167        let _ = order;
168        #[cfg(all(
169            any(target_arch = "riscv32", target_arch = "riscv64"),
170            not(feature = "critical-section"),
171            any(
172                portable_atomic_force_amo,
173                target_feature = "zaamo",
174                portable_atomic_target_feature = "zaamo",
175            ),
176        ))]
177        {
178            self.as_native().swap(ptr, order)
179        }
180        #[cfg(not(all(
181            any(target_arch = "riscv32", target_arch = "riscv64"),
182            not(feature = "critical-section"),
183            any(
184                portable_atomic_force_amo,
185                target_feature = "zaamo",
186                portable_atomic_target_feature = "zaamo",
187            ),
188        )))]
189        // SAFETY: any data races are prevented by disabling interrupts (see
190        // module-level comments) and the raw pointer is valid because we got it
191        // from a reference.
192        with(|| unsafe {
193            let prev = self.p.get().read();
194            self.p.get().write(ptr);
195            prev
196        })
197    }
198
199    #[inline]
200    #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
201    pub(crate) fn compare_exchange(
202        &self,
203        current: *mut T,
204        new: *mut T,
205        success: Ordering,
206        failure: Ordering,
207    ) -> Result<*mut T, *mut T> {
208        crate::utils::assert_compare_exchange_ordering(success, failure);
209        // SAFETY: any data races are prevented by disabling interrupts (see
210        // module-level comments) and the raw pointer is valid because we got it
211        // from a reference.
212        with(|| unsafe {
213            let prev = self.p.get().read();
214            if prev == current {
215                self.p.get().write(new);
216                Ok(prev)
217            } else {
218                Err(prev)
219            }
220        })
221    }
222
223    #[inline]
224    #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
225    pub(crate) fn compare_exchange_weak(
226        &self,
227        current: *mut T,
228        new: *mut T,
229        success: Ordering,
230        failure: Ordering,
231    ) -> Result<*mut T, *mut T> {
232        self.compare_exchange(current, new, success, failure)
233    }
234
235    #[inline]
236    pub(crate) const fn as_ptr(&self) -> *mut *mut T {
237        self.p.get()
238    }
239
240    #[cfg(not(any(target_arch = "avr", feature = "critical-section")))]
241    #[inline(always)]
242    fn as_native(&self) -> &atomic::AtomicPtr<T> {
243        // SAFETY: AtomicPtr and atomic::AtomicPtr have the same layout and
244        // guarantee atomicity in a compatible way. (see module-level comments)
245        unsafe { &*(self as *const Self as *const atomic::AtomicPtr<T>) }
246    }
247}
248
249macro_rules! atomic_int {
250    (base, $atomic_type:ident, $int_type:ident, $align:literal) => {
251        #[repr(C, align($align))]
252        pub(crate) struct $atomic_type {
253            v: UnsafeCell<$int_type>,
254        }
255
256        // Send is implicitly implemented.
257        // SAFETY: any data races are prevented by disabling interrupts or
258        // atomic intrinsics (see module-level comments).
259        unsafe impl Sync for $atomic_type {}
260
261        impl $atomic_type {
262            #[inline]
263            pub(crate) const fn new(v: $int_type) -> Self {
264                Self { v: UnsafeCell::new(v) }
265            }
266
267            #[inline]
268            pub(crate) fn is_lock_free() -> bool {
269                Self::IS_ALWAYS_LOCK_FREE
270            }
271            pub(crate) const IS_ALWAYS_LOCK_FREE: bool = IS_ALWAYS_LOCK_FREE;
272
273            #[inline]
274            pub(crate) const fn as_ptr(&self) -> *mut $int_type {
275                self.v.get()
276            }
277        }
278    };
279    (load_store_atomic $([$kind:ident])?, $atomic_type:ident, $int_type:ident, $align:literal) => {
280        atomic_int!(base, $atomic_type, $int_type, $align);
281        #[cfg(all(
282            any(target_arch = "riscv32", target_arch = "riscv64"),
283            not(feature = "critical-section"),
284            any(
285                portable_atomic_force_amo,
286                target_feature = "zaamo",
287                portable_atomic_target_feature = "zaamo",
288            ),
289        ))]
290        atomic_int!(cas $([$kind])?, $atomic_type, $int_type);
291        #[cfg(not(all(
292            any(target_arch = "riscv32", target_arch = "riscv64"),
293            not(feature = "critical-section"),
294            any(
295                portable_atomic_force_amo,
296                target_feature = "zaamo",
297                portable_atomic_target_feature = "zaamo",
298            ),
299        )))]
300        atomic_int!(cas[emulate], $atomic_type, $int_type);
301        impl $atomic_type {
302            #[inline]
303            #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
304            pub(crate) fn load(&self, order: Ordering) -> $int_type {
305                crate::utils::assert_load_ordering(order);
306                #[cfg(not(any(
307                    all(target_arch = "avr", portable_atomic_no_asm),
308                    feature = "critical-section",
309                )))]
310                {
311                    self.as_native().load(order)
312                }
313                #[cfg(any(
314                    all(target_arch = "avr", portable_atomic_no_asm),
315                    feature = "critical-section",
316                ))]
317                // SAFETY: any data races are prevented by disabling interrupts (see
318                // module-level comments) and the raw pointer is valid because we got it
319                // from a reference.
320                with(|| unsafe { self.v.get().read() })
321            }
322
323            #[inline]
324            #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
325            pub(crate) fn store(&self, val: $int_type, order: Ordering) {
326                crate::utils::assert_store_ordering(order);
327                #[cfg(not(any(
328                    all(target_arch = "avr", portable_atomic_no_asm),
329                    feature = "critical-section",
330                )))]
331                {
332                    self.as_native().store(val, order);
333                }
334                #[cfg(any(
335                    all(target_arch = "avr", portable_atomic_no_asm),
336                    feature = "critical-section",
337                ))]
338                // SAFETY: any data races are prevented by disabling interrupts (see
339                // module-level comments) and the raw pointer is valid because we got it
340                // from a reference.
341                with(|| unsafe { self.v.get().write(val) });
342            }
343
344            #[cfg(not(any(
345                all(target_arch = "avr", portable_atomic_no_asm),
346                feature = "critical-section",
347            )))]
348            #[inline(always)]
349            fn as_native(&self) -> &atomic::$atomic_type {
350                // SAFETY: $atomic_type and atomic::$atomic_type have the same layout and
351                // guarantee atomicity in a compatible way. (see module-level comments)
352                unsafe { &*(self as *const Self as *const atomic::$atomic_type) }
353            }
354        }
355
356        #[cfg(not(all(target_arch = "msp430", not(feature = "critical-section"))))]
357        impl_default_no_fetch_ops!($atomic_type, $int_type);
358        impl_default_bit_opts!($atomic_type, $int_type);
359        #[cfg(not(all(target_arch = "msp430", not(feature = "critical-section"))))]
360        impl $atomic_type {
361            #[inline]
362            pub(crate) fn not(&self, order: Ordering) {
363                self.fetch_not(order);
364            }
365        }
366        #[cfg(all(target_arch = "msp430", not(feature = "critical-section")))]
367        impl $atomic_type {
368            #[inline]
369            pub(crate) fn add(&self, val: $int_type, order: Ordering) {
370                self.as_native().add(val, order);
371            }
372            #[inline]
373            pub(crate) fn sub(&self, val: $int_type, order: Ordering) {
374                self.as_native().sub(val, order);
375            }
376            #[inline]
377            pub(crate) fn and(&self, val: $int_type, order: Ordering) {
378                self.as_native().and(val, order);
379            }
380            #[inline]
381            pub(crate) fn or(&self, val: $int_type, order: Ordering) {
382                self.as_native().or(val, order);
383            }
384            #[inline]
385            pub(crate) fn xor(&self, val: $int_type, order: Ordering) {
386                self.as_native().xor(val, order);
387            }
388            #[inline]
389            pub(crate) fn not(&self, order: Ordering) {
390                self.as_native().not(order);
391            }
392        }
393    };
394    (all_critical_session, $atomic_type:ident, $int_type:ident, $align:literal) => {
395        atomic_int!(base, $atomic_type, $int_type, $align);
396        atomic_int!(cas[emulate], $atomic_type, $int_type);
397        impl_default_no_fetch_ops!($atomic_type, $int_type);
398        impl_default_bit_opts!($atomic_type, $int_type);
399        impl $atomic_type {
400            #[inline]
401            #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
402            pub(crate) fn load(&self, order: Ordering) -> $int_type {
403                crate::utils::assert_load_ordering(order);
404                // SAFETY: any data races are prevented by disabling interrupts (see
405                // module-level comments) and the raw pointer is valid because we got it
406                // from a reference.
407                with(|| unsafe { self.v.get().read() })
408            }
409
410            #[inline]
411            #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
412            pub(crate) fn store(&self, val: $int_type, order: Ordering) {
413                crate::utils::assert_store_ordering(order);
414                // SAFETY: any data races are prevented by disabling interrupts (see
415                // module-level comments) and the raw pointer is valid because we got it
416                // from a reference.
417                with(|| unsafe { self.v.get().write(val) });
418            }
419
420            #[inline]
421            pub(crate) fn not(&self, order: Ordering) {
422                self.fetch_not(order);
423            }
424        }
425    };
426    (cas[emulate], $atomic_type:ident, $int_type:ident) => {
427        impl $atomic_type {
428            #[inline]
429            pub(crate) fn swap(&self, val: $int_type, _order: Ordering) -> $int_type {
430                // SAFETY: any data races are prevented by disabling interrupts (see
431                // module-level comments) and the raw pointer is valid because we got it
432                // from a reference.
433                with(|| unsafe {
434                    let prev = self.v.get().read();
435                    self.v.get().write(val);
436                    prev
437                })
438            }
439
440            #[inline]
441            #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
442            pub(crate) fn compare_exchange(
443                &self,
444                current: $int_type,
445                new: $int_type,
446                success: Ordering,
447                failure: Ordering,
448            ) -> Result<$int_type, $int_type> {
449                crate::utils::assert_compare_exchange_ordering(success, failure);
450                // SAFETY: any data races are prevented by disabling interrupts (see
451                // module-level comments) and the raw pointer is valid because we got it
452                // from a reference.
453                with(|| unsafe {
454                    let prev = self.v.get().read();
455                    if prev == current {
456                        self.v.get().write(new);
457                        Ok(prev)
458                    } else {
459                        Err(prev)
460                    }
461                })
462            }
463
464            #[inline]
465            #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
466            pub(crate) fn compare_exchange_weak(
467                &self,
468                current: $int_type,
469                new: $int_type,
470                success: Ordering,
471                failure: Ordering,
472            ) -> Result<$int_type, $int_type> {
473                self.compare_exchange(current, new, success, failure)
474            }
475
476            #[inline]
477            pub(crate) fn fetch_add(&self, val: $int_type, _order: Ordering) -> $int_type {
478                // SAFETY: any data races are prevented by disabling interrupts (see
479                // module-level comments) and the raw pointer is valid because we got it
480                // from a reference.
481                with(|| unsafe {
482                    let prev = self.v.get().read();
483                    self.v.get().write(prev.wrapping_add(val));
484                    prev
485                })
486            }
487
488            #[inline]
489            pub(crate) fn fetch_sub(&self, val: $int_type, _order: Ordering) -> $int_type {
490                // SAFETY: any data races are prevented by disabling interrupts (see
491                // module-level comments) and the raw pointer is valid because we got it
492                // from a reference.
493                with(|| unsafe {
494                    let prev = self.v.get().read();
495                    self.v.get().write(prev.wrapping_sub(val));
496                    prev
497                })
498            }
499
500            #[inline]
501            pub(crate) fn fetch_and(&self, val: $int_type, _order: Ordering) -> $int_type {
502                // SAFETY: any data races are prevented by disabling interrupts (see
503                // module-level comments) and the raw pointer is valid because we got it
504                // from a reference.
505                with(|| unsafe {
506                    let prev = self.v.get().read();
507                    self.v.get().write(prev & val);
508                    prev
509                })
510            }
511
512            #[inline]
513            pub(crate) fn fetch_nand(&self, val: $int_type, _order: Ordering) -> $int_type {
514                // SAFETY: any data races are prevented by disabling interrupts (see
515                // module-level comments) and the raw pointer is valid because we got it
516                // from a reference.
517                with(|| unsafe {
518                    let prev = self.v.get().read();
519                    self.v.get().write(!(prev & val));
520                    prev
521                })
522            }
523
524            #[inline]
525            pub(crate) fn fetch_or(&self, val: $int_type, _order: Ordering) -> $int_type {
526                // SAFETY: any data races are prevented by disabling interrupts (see
527                // module-level comments) and the raw pointer is valid because we got it
528                // from a reference.
529                with(|| unsafe {
530                    let prev = self.v.get().read();
531                    self.v.get().write(prev | val);
532                    prev
533                })
534            }
535
536            #[inline]
537            pub(crate) fn fetch_xor(&self, val: $int_type, _order: Ordering) -> $int_type {
538                // SAFETY: any data races are prevented by disabling interrupts (see
539                // module-level comments) and the raw pointer is valid because we got it
540                // from a reference.
541                with(|| unsafe {
542                    let prev = self.v.get().read();
543                    self.v.get().write(prev ^ val);
544                    prev
545                })
546            }
547
548            #[inline]
549            pub(crate) fn fetch_max(&self, val: $int_type, _order: Ordering) -> $int_type {
550                // SAFETY: any data races are prevented by disabling interrupts (see
551                // module-level comments) and the raw pointer is valid because we got it
552                // from a reference.
553                with(|| unsafe {
554                    let prev = self.v.get().read();
555                    self.v.get().write(core::cmp::max(prev, val));
556                    prev
557                })
558            }
559
560            #[inline]
561            pub(crate) fn fetch_min(&self, val: $int_type, _order: Ordering) -> $int_type {
562                // SAFETY: any data races are prevented by disabling interrupts (see
563                // module-level comments) and the raw pointer is valid because we got it
564                // from a reference.
565                with(|| unsafe {
566                    let prev = self.v.get().read();
567                    self.v.get().write(core::cmp::min(prev, val));
568                    prev
569                })
570            }
571
572            #[inline]
573            pub(crate) fn fetch_not(&self, _order: Ordering) -> $int_type {
574                // SAFETY: any data races are prevented by disabling interrupts (see
575                // module-level comments) and the raw pointer is valid because we got it
576                // from a reference.
577                with(|| unsafe {
578                    let prev = self.v.get().read();
579                    self.v.get().write(!prev);
580                    prev
581                })
582            }
583
584            #[inline]
585            pub(crate) fn fetch_neg(&self, _order: Ordering) -> $int_type {
586                // SAFETY: any data races are prevented by disabling interrupts (see
587                // module-level comments) and the raw pointer is valid because we got it
588                // from a reference.
589                with(|| unsafe {
590                    let prev = self.v.get().read();
591                    self.v.get().write(prev.wrapping_neg());
592                    prev
593                })
594            }
595            #[inline]
596            pub(crate) fn neg(&self, order: Ordering) {
597                self.fetch_neg(order);
598            }
599        }
600    };
601    // RISC-V 32-bit(RV32)/{32,64}-bit(RV64) RMW with Zaamo extension
602    // RISC-V 8-bit/16-bit RMW with Zabha extension
603    (cas, $atomic_type:ident, $int_type:ident) => {
604        impl $atomic_type {
605            #[inline]
606            pub(crate) fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
607                self.as_native().swap(val, order)
608            }
609
610            #[inline]
611            #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
612            pub(crate) fn compare_exchange(
613                &self,
614                current: $int_type,
615                new: $int_type,
616                success: Ordering,
617                failure: Ordering,
618            ) -> Result<$int_type, $int_type> {
619                crate::utils::assert_compare_exchange_ordering(success, failure);
620                // SAFETY: any data races are prevented by disabling interrupts (see
621                // module-level comments) and the raw pointer is valid because we got it
622                // from a reference.
623                with(|| unsafe {
624                    let prev = self.v.get().read();
625                    if prev == current {
626                        self.v.get().write(new);
627                        Ok(prev)
628                    } else {
629                        Err(prev)
630                    }
631                })
632            }
633
634            #[inline]
635            #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
636            pub(crate) fn compare_exchange_weak(
637                &self,
638                current: $int_type,
639                new: $int_type,
640                success: Ordering,
641                failure: Ordering,
642            ) -> Result<$int_type, $int_type> {
643                self.compare_exchange(current, new, success, failure)
644            }
645
646            #[inline]
647            pub(crate) fn fetch_add(&self, val: $int_type, order: Ordering) -> $int_type {
648                self.as_native().fetch_add(val, order)
649            }
650            #[inline]
651            pub(crate) fn fetch_sub(&self, val: $int_type, order: Ordering) -> $int_type {
652                self.as_native().fetch_sub(val, order)
653            }
654            #[inline]
655            pub(crate) fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
656                self.as_native().fetch_and(val, order)
657            }
658
659            #[inline]
660            pub(crate) fn fetch_nand(&self, val: $int_type, _order: Ordering) -> $int_type {
661                // SAFETY: any data races are prevented by disabling interrupts (see
662                // module-level comments) and the raw pointer is valid because we got it
663                // from a reference.
664                with(|| unsafe {
665                    let prev = self.v.get().read();
666                    self.v.get().write(!(prev & val));
667                    prev
668                })
669            }
670
671            #[inline]
672            pub(crate) fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
673                self.as_native().fetch_or(val, order)
674            }
675            #[inline]
676            pub(crate) fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
677                self.as_native().fetch_xor(val, order)
678            }
679            #[inline]
680            pub(crate) fn fetch_max(&self, val: $int_type, order: Ordering) -> $int_type {
681                self.as_native().fetch_max(val, order)
682            }
683            #[inline]
684            pub(crate) fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
685                self.as_native().fetch_min(val, order)
686            }
687            #[inline]
688            pub(crate) fn fetch_not(&self, order: Ordering) -> $int_type {
689                self.as_native().fetch_not(order)
690            }
691
692            #[inline]
693            pub(crate) fn fetch_neg(&self, _order: Ordering) -> $int_type {
694                // SAFETY: any data races are prevented by disabling interrupts (see
695                // module-level comments) and the raw pointer is valid because we got it
696                // from a reference.
697                with(|| unsafe {
698                    let prev = self.v.get().read();
699                    self.v.get().write(prev.wrapping_neg());
700                    prev
701                })
702            }
703            #[inline]
704            pub(crate) fn neg(&self, order: Ordering) {
705                self.fetch_neg(order);
706            }
707        }
708    };
709    // RISC-V 8-bit/16-bit RMW with Zaamo extension
710    (cas[sub_word], $atomic_type:ident, $int_type:ident) => {
711        #[cfg(any(target_feature = "zabha", portable_atomic_target_feature = "zabha"))]
712        atomic_int!(cas, $atomic_type, $int_type);
713        #[cfg(not(any(target_feature = "zabha", portable_atomic_target_feature = "zabha")))]
714        impl $atomic_type {
715            #[inline]
716            pub(crate) fn swap(&self, val: $int_type, _order: Ordering) -> $int_type {
717                // SAFETY: any data races are prevented by disabling interrupts (see
718                // module-level comments) and the raw pointer is valid because we got it
719                // from a reference.
720                with(|| unsafe {
721                    let prev = self.v.get().read();
722                    self.v.get().write(val);
723                    prev
724                })
725            }
726
727            #[inline]
728            #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
729            pub(crate) fn compare_exchange(
730                &self,
731                current: $int_type,
732                new: $int_type,
733                success: Ordering,
734                failure: Ordering,
735            ) -> Result<$int_type, $int_type> {
736                crate::utils::assert_compare_exchange_ordering(success, failure);
737                // SAFETY: any data races are prevented by disabling interrupts (see
738                // module-level comments) and the raw pointer is valid because we got it
739                // from a reference.
740                with(|| unsafe {
741                    let prev = self.v.get().read();
742                    if prev == current {
743                        self.v.get().write(new);
744                        Ok(prev)
745                    } else {
746                        Err(prev)
747                    }
748                })
749            }
750
751            #[inline]
752            #[cfg_attr(all(debug_assertions, not(portable_atomic_no_track_caller)), track_caller)]
753            pub(crate) fn compare_exchange_weak(
754                &self,
755                current: $int_type,
756                new: $int_type,
757                success: Ordering,
758                failure: Ordering,
759            ) -> Result<$int_type, $int_type> {
760                self.compare_exchange(current, new, success, failure)
761            }
762
763            #[inline]
764            pub(crate) fn fetch_add(&self, val: $int_type, _order: Ordering) -> $int_type {
765                // SAFETY: any data races are prevented by disabling interrupts (see
766                // module-level comments) and the raw pointer is valid because we got it
767                // from a reference.
768                with(|| unsafe {
769                    let prev = self.v.get().read();
770                    self.v.get().write(prev.wrapping_add(val));
771                    prev
772                })
773            }
774
775            #[inline]
776            pub(crate) fn fetch_sub(&self, val: $int_type, _order: Ordering) -> $int_type {
777                // SAFETY: any data races are prevented by disabling interrupts (see
778                // module-level comments) and the raw pointer is valid because we got it
779                // from a reference.
780                with(|| unsafe {
781                    let prev = self.v.get().read();
782                    self.v.get().write(prev.wrapping_sub(val));
783                    prev
784                })
785            }
786
787            #[inline]
788            pub(crate) fn fetch_and(&self, val: $int_type, order: Ordering) -> $int_type {
789                self.as_native().fetch_and(val, order)
790            }
791
792            #[inline]
793            pub(crate) fn fetch_nand(&self, val: $int_type, _order: Ordering) -> $int_type {
794                // SAFETY: any data races are prevented by disabling interrupts (see
795                // module-level comments) and the raw pointer is valid because we got it
796                // from a reference.
797                with(|| unsafe {
798                    let prev = self.v.get().read();
799                    self.v.get().write(!(prev & val));
800                    prev
801                })
802            }
803
804            #[inline]
805            pub(crate) fn fetch_or(&self, val: $int_type, order: Ordering) -> $int_type {
806                self.as_native().fetch_or(val, order)
807            }
808            #[inline]
809            pub(crate) fn fetch_xor(&self, val: $int_type, order: Ordering) -> $int_type {
810                self.as_native().fetch_xor(val, order)
811            }
812
813            #[inline]
814            pub(crate) fn fetch_max(&self, val: $int_type, _order: Ordering) -> $int_type {
815                // SAFETY: any data races are prevented by disabling interrupts (see
816                // module-level comments) and the raw pointer is valid because we got it
817                // from a reference.
818                with(|| unsafe {
819                    let prev = self.v.get().read();
820                    self.v.get().write(core::cmp::max(prev, val));
821                    prev
822                })
823            }
824
825            #[inline]
826            pub(crate) fn fetch_min(&self, val: $int_type, _order: Ordering) -> $int_type {
827                // SAFETY: any data races are prevented by disabling interrupts (see
828                // module-level comments) and the raw pointer is valid because we got it
829                // from a reference.
830                with(|| unsafe {
831                    let prev = self.v.get().read();
832                    self.v.get().write(core::cmp::min(prev, val));
833                    prev
834                })
835            }
836
837            #[inline]
838            pub(crate) fn fetch_not(&self, order: Ordering) -> $int_type {
839                self.as_native().fetch_not(order)
840            }
841
842            #[inline]
843            pub(crate) fn fetch_neg(&self, _order: Ordering) -> $int_type {
844                // SAFETY: any data races are prevented by disabling interrupts (see
845                // module-level comments) and the raw pointer is valid because we got it
846                // from a reference.
847                with(|| unsafe {
848                    let prev = self.v.get().read();
849                    self.v.get().write(prev.wrapping_neg());
850                    prev
851                })
852            }
853            #[inline]
854            pub(crate) fn neg(&self, order: Ordering) {
855                self.fetch_neg(order);
856            }
857        }
858    };
859}
860
861#[cfg(target_pointer_width = "16")]
862#[cfg(not(target_arch = "avr"))]
863atomic_int!(load_store_atomic, AtomicIsize, isize, 2);
864#[cfg(target_pointer_width = "16")]
865#[cfg(not(target_arch = "avr"))]
866atomic_int!(load_store_atomic, AtomicUsize, usize, 2);
867#[cfg(target_arch = "avr")]
868atomic_int!(all_critical_session, AtomicIsize, isize, 2);
869#[cfg(target_arch = "avr")]
870atomic_int!(all_critical_session, AtomicUsize, usize, 2);
871#[cfg(target_pointer_width = "32")]
872atomic_int!(load_store_atomic, AtomicIsize, isize, 4);
873#[cfg(target_pointer_width = "32")]
874atomic_int!(load_store_atomic, AtomicUsize, usize, 4);
875#[cfg(target_pointer_width = "64")]
876atomic_int!(load_store_atomic, AtomicIsize, isize, 8);
877#[cfg(target_pointer_width = "64")]
878atomic_int!(load_store_atomic, AtomicUsize, usize, 8);
879#[cfg(target_pointer_width = "128")]
880atomic_int!(load_store_atomic, AtomicIsize, isize, 16);
881#[cfg(target_pointer_width = "128")]
882atomic_int!(load_store_atomic, AtomicUsize, usize, 16);
883
884#[cfg(not(all(target_arch = "avr", portable_atomic_no_asm)))]
885atomic_int!(load_store_atomic[sub_word], AtomicI8, i8, 1);
886#[cfg(not(all(target_arch = "avr", portable_atomic_no_asm)))]
887atomic_int!(load_store_atomic[sub_word], AtomicU8, u8, 1);
888#[cfg(all(target_arch = "avr", portable_atomic_no_asm))]
889atomic_int!(all_critical_session, AtomicI8, i8, 1);
890#[cfg(all(target_arch = "avr", portable_atomic_no_asm))]
891atomic_int!(all_critical_session, AtomicU8, u8, 1);
892#[cfg(not(target_arch = "avr"))]
893atomic_int!(load_store_atomic[sub_word], AtomicI16, i16, 2);
894#[cfg(not(target_arch = "avr"))]
895atomic_int!(load_store_atomic[sub_word], AtomicU16, u16, 2);
896#[cfg(target_arch = "avr")]
897atomic_int!(all_critical_session, AtomicI16, i16, 2);
898#[cfg(target_arch = "avr")]
899atomic_int!(all_critical_session, AtomicU16, u16, 2);
900
901#[cfg(not(target_pointer_width = "16"))]
902atomic_int!(load_store_atomic, AtomicI32, i32, 4);
903#[cfg(not(target_pointer_width = "16"))]
904atomic_int!(load_store_atomic, AtomicU32, u32, 4);
905#[cfg(target_pointer_width = "16")]
906#[cfg(any(test, feature = "fallback"))]
907atomic_int!(all_critical_session, AtomicI32, i32, 4);
908#[cfg(target_pointer_width = "16")]
909#[cfg(any(test, feature = "fallback"))]
910atomic_int!(all_critical_session, AtomicU32, u32, 4);
911
912cfg_has_fast_atomic_64! {
913    atomic_int!(load_store_atomic, AtomicI64, i64, 8);
914    atomic_int!(load_store_atomic, AtomicU64, u64, 8);
915}
916#[cfg(any(test, feature = "fallback"))]
917cfg_no_fast_atomic_64! {
918    atomic_int!(all_critical_session, AtomicI64, i64, 8);
919    atomic_int!(all_critical_session, AtomicU64, u64, 8);
920}
921
922#[cfg(any(test, feature = "fallback"))]
923atomic_int!(all_critical_session, AtomicI128, i128, 16);
924#[cfg(any(test, feature = "fallback"))]
925atomic_int!(all_critical_session, AtomicU128, u128, 16);
926
927#[cfg(test)]
928mod tests {
929    use super::*;
930
931    test_atomic_ptr_single_thread!();
932    test_atomic_int_single_thread!(i8);
933    test_atomic_int_single_thread!(u8);
934    test_atomic_int_single_thread!(i16);
935    test_atomic_int_single_thread!(u16);
936    test_atomic_int_single_thread!(i32);
937    test_atomic_int_single_thread!(u32);
938    test_atomic_int_single_thread!(i64);
939    test_atomic_int_single_thread!(u64);
940    test_atomic_int_single_thread!(i128);
941    test_atomic_int_single_thread!(u128);
942    test_atomic_int_single_thread!(isize);
943    test_atomic_int_single_thread!(usize);
944}