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
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! A no-op memory reclamation scheme that leaks memory, mainly for exemplary
//! and testing purposes.

use core::sync::atomic::Ordering;

use typenum::Unsigned;

use crate::pointer::{Marked, MarkedPointer, MarkedPtr};
use crate::{AcquireResult, GlobalReclaim, Protect, ProtectRegion, Reclaim};

/// An [`Atomic`][crate::Atomic] type that uses the no-op [`Leaking`]
/// "reclamation" scheme.
pub type Atomic<T, N> = crate::Atomic<T, Leaking, N>;
/// A [`Shared`][crate::Shared] type that uses the no-op [`Leaking`]
/// "reclamation" scheme.
pub type Shared<'g, T, N> = crate::Shared<'g, T, Leaking, N>;
/// An [`Owned`][crate::Owned] type that uses the no-op [`Leaking`]
/// "reclamation" scheme.
pub type Owned<T, N> = crate::Owned<T, Leaking, N>;
/// An [`Unlinked`][crate::Unlinked] type that uses the no-op [`Leaking`]
/// "reclamation" scheme.
pub type Unlinked<T, N> = crate::Unlinked<T, Leaking, N>;
/// An [`Unprotected`][crate::Unprotected] type that uses the no-op [`Leaking`]
/// "reclamation" scheme.
pub type Unprotected<T, N> = crate::Unprotected<T, Leaking, N>;

/// A no-op memory "reclamation" scheme that deliberately leaks all memory.
#[derive(Debug, Default)]
pub struct Leaking;

impl Leaking {
    /// Leaks the given `unlinked`.
    ///
    /// This is safe wrapper for [`retire`][Reclaim::retire], which does not
    /// require any invariants to be maintained, because retired records are
    /// not freed but leaked.
    #[inline]
    pub fn leak<T, N: Unsigned>(unlinked: Unlinked<T, N>) {
        unsafe { Self::retire_unchecked(unlinked) };
    }
}

/// The [`Guard`][Reclaim::Guard] type for the [`Leaking`] "reclamation".
#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
pub struct Guard;

impl Guard {
    /// Creates a new empty `LeakingGuard`.
    #[inline]
    pub fn new() -> Self {
        Self
    }
}

#[cfg(test)]
pub struct Header {
    pub checksum: usize,
}

#[cfg(test)]
impl Default for Header {
    #[inline]
    fn default() -> Self {
        Self { checksum: 0xDEAD_BEEF }
    }
}

unsafe impl GlobalReclaim for Leaking {
    type Guard = Guard;

    #[inline]
    fn try_flush() {}

    #[inline]
    unsafe fn retire<T: 'static, N: Unsigned>(_: Unlinked<T, N>) {}

    #[inline]
    unsafe fn retire_unchecked<T, N: Unsigned>(_: Unlinked<T, N>) {}
}

unsafe impl Reclaim for Leaking {
    type Local = ();

    #[cfg(test)]
    type RecordHeader = Header;
    #[cfg(not(test))]
    type RecordHeader = ();

    /// Leaks the given value.
    ///
    /// # Safety
    ///
    /// Contrary to the specifications of the trait's method, this particular
    /// implementation is always safe to call.
    #[inline]
    unsafe fn retire_local<T: 'static, N: Unsigned>(_: &(), _: Unlinked<T, N>) {}

    /// Leaks the given value.
    ///
    /// # Safety
    ///
    /// Contrary to the specifications of the trait's method, this particular
    /// implementation is always safe to call.
    #[inline]
    unsafe fn retire_local_unchecked<T, N: Unsigned>(_: &(), _: Unlinked<T, N>) {}
}

unsafe impl Protect for Guard {
    type Reclaimer = Leaking;

    /// This is a no-op.
    #[inline]
    fn release(&mut self) {}

    /// Acquires a value from shared memory.
    #[inline]
    fn protect<T, N: Unsigned>(
        &mut self,
        atomic: &Atomic<T, N>,
        order: Ordering,
    ) -> Marked<Shared<T, N>> {
        unsafe { Marked::from_marked_ptr(atomic.load_raw(order)) }
    }

    /// Acquires a value from shared memory if it equals `expected`.
    #[inline]
    fn protect_if_equal<T, N: Unsigned>(
        &mut self,
        atomic: &Atomic<T, N>,
        expected: MarkedPtr<T, N>,
        order: Ordering,
    ) -> AcquireResult<T, Self::Reclaimer, N> {
        match atomic.load_raw(order) {
            raw if raw == expected => Ok(unsafe { Marked::from_marked_ptr(raw) }),
            _ => Err(crate::NotEqualError),
        }
    }
}

unsafe impl ProtectRegion for Guard {}