     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

    //! Implementation of an atomic u64 cell. On 64 bit platforms, this is a
    //! re-export of `AtomicU64`. On 32 bit platforms, this is implemented using a
    //! `Mutex`.

    pub(crate) use self::imp::AtomicU64;

    // `AtomicU64` can only be used on targets with `target_has_atomic` is 64 or greater.
    // Once `cfg_target_has_atomic` feature is stable, we can replace it with
    // `#[cfg(target_has_atomic = "64")]`.
    // Refs: https://github.com/rust-lang/rust/tree/master/src/librustc_target
    #[cfg(not(any(target_arch = "arm", target_arch = "mips", target_arch = "powerpc")))]
    mod imp {
        pub(crate) use std::sync::atomic::AtomicU64;
    }

    #[cfg(any(target_arch = "arm", target_arch = "mips", target_arch = "powerpc"))]
    mod imp {
        use std::sync::atomic::Ordering;
        use std::sync::Mutex;

        #[derive(Debug)]
        pub(crate) struct AtomicU64 {
            inner: Mutex<u64>,
        }

        impl AtomicU64 {
            pub(crate) fn new(val: u64) -> AtomicU64 {
                AtomicU64 {
                    inner: Mutex::new(val),
                }
            }

            pub(crate) fn load(&self, _: Ordering) -> u64 {
                *self.inner.lock().unwrap()
            }

            pub(crate) fn store(&self, val: u64, _: Ordering) {
                *self.inner.lock().unwrap() = val;
            }

            pub(crate) fn fetch_or(&self, val: u64, _: Ordering) -> u64 {
                let mut lock = self.inner.lock().unwrap();
                let prev = *lock;
                *lock = prev | val;
                prev
            }

            pub(crate) fn compare_and_swap(&self, old: u64, new: u64, _: Ordering) -> u64 {
                let mut lock = self.inner.lock().unwrap();
                let prev = *lock;

                if prev != old {
                    return prev;
                }

                *lock = new;
                prev
            }
        }
    }