Coverage Report

Created: 2021-01-22 16:54

crossbeam-epoch/src/epoch.rs
Line
Count
Source (jump to first uncovered line)
1
//! The global epoch
2
//!
3
//! The last bit in this number is unused and is always zero. Every so often the global epoch is
4
//! incremented, i.e. we say it "advances". A pinned participant may advance the global epoch only
5
//! if all currently pinned participants have been pinned in the current epoch.
6
//!
7
//! If an object became garbage in some epoch, then we can be sure that after two advancements no
8
//! participant will hold a reference to it. That is the crux of safe memory reclamation.
9
10
use crate::primitive::sync::atomic::AtomicUsize;
11
use core::sync::atomic::Ordering;
12
13
/// An epoch that can be marked as pinned or unpinned.
14
///
15
/// Internally, the epoch is represented as an integer that wraps around at some unspecified point
16
/// and a flag that represents whether it is pinned or unpinned.
17
22.4M
#[derive(Copy, 
C0
lone, Default, Debug,
E0
q,
PartialEq9.39M
)]
<crossbeam_epoch::epoch::Epoch as core::default::Default>::default
Line
Count
Source
17
206
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
<crossbeam_epoch::epoch::Epoch as core::default::Default>::default
Line
Count
Source
17
998k
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
<crossbeam_epoch::epoch::Epoch as core::default::Default>::default
Line
Count
Source
17
3
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
<crossbeam_epoch::epoch::Epoch as core::default::Default>::default
Line
Count
Source
17
21
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
<crossbeam_epoch::epoch::Epoch as core::default::Default>::default
Line
Count
Source
17
1
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
<crossbeam_epoch::epoch::Epoch as core::default::Default>::default
Line
Count
Source
17
426k
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
<crossbeam_epoch::epoch::Epoch as core::default::Default>::default
Line
Count
Source
17
14
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
<crossbeam_epoch::epoch::Epoch as core::default::Default>::default
Line
Count
Source
17
535k
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
<crossbeam_epoch::epoch::Epoch as core::default::Default>::default
Line
Count
Source
17
20.4M
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
<crossbeam_epoch::epoch::Epoch as core::cmp::PartialEq>::ne
Line
Count
Source
17
37.5k
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
<crossbeam_epoch::epoch::Epoch as core::cmp::PartialEq>::ne
Line
Count
Source
17
9.35M
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)]
18
pub(crate) struct Epoch {
19
    /// The least significant bit is set if pinned. The rest of the bits hold the epoch.
20
    data: usize,
21
}
22
23
impl Epoch {
24
    /// Returns the starting epoch in unpinned state.
25
    #[inline]
26
23.5M
    pub(crate) fn starting() -> Self {
27
23.5M
        Self::default()
28
23.5M
    }
<crossbeam_epoch::epoch::Epoch>::starting
Line
Count
Source
26
206
    pub(crate) fn starting() -> Self {
27
206
        Self::default()
28
206
    }
<crossbeam_epoch::epoch::Epoch>::starting
Line
Count
Source
26
993k
    pub(crate) fn starting() -> Self {
27
993k
        Self::default()
28
993k
    }
<crossbeam_epoch::epoch::Epoch>::starting
Line
Count
Source
26
3
    pub(crate) fn starting() -> Self {
27
3
        Self::default()
28
3
    }
<crossbeam_epoch::epoch::Epoch>::starting
Line
Count
Source
26
21
    pub(crate) fn starting() -> Self {
27
21
        Self::default()
28
21
    }
<crossbeam_epoch::epoch::Epoch>::starting
Line
Count
Source
26
1
    pub(crate) fn starting() -> Self {
27
1
        Self::default()
28
1
    }
<crossbeam_epoch::epoch::Epoch>::starting
Line
Count
Source
26
373k
    pub(crate) fn starting() -> Self {
27
373k
        Self::default()
28
373k
    }
<crossbeam_epoch::epoch::Epoch>::starting
Line
Count
Source
26
14
    pub(crate) fn starting() -> Self {
27
14
        Self::default()
28
14
    }
<crossbeam_epoch::epoch::Epoch>::starting
Line
Count
Source
26
560k
    pub(crate) fn starting() -> Self {
27
560k
        Self::default()
28
560k
    }
<crossbeam_epoch::epoch::Epoch>::starting
Line
Count
Source
26
21.6M
    pub(crate) fn starting() -> Self {
27
21.6M
        Self::default()
28
21.6M
    }
29
30
    /// Returns the number of epochs `self` is ahead of `rhs`.
31
    ///
32
    /// Internally, epochs are represented as numbers in the range `(isize::MIN / 2) .. (isize::MAX
33
    /// / 2)`, so the returned distance will be in the same interval.
34
3.59M
    pub(crate) fn wrapping_sub(self, rhs: Self) -> isize {
35
3.59M
        // The result is the same with `(self.data & !1).wrapping_sub(rhs.data & !1) as isize >> 1`,
36
3.59M
        // because the possible difference of LSB in `(self.data & !1).wrapping_sub(rhs.data & !1)`
37
3.59M
        // will be ignored in the shift operation.
38
3.59M
        self.data.wrapping_sub(rhs.data & !1) as isize >> 1
39
3.59M
    }
<crossbeam_epoch::epoch::Epoch>::wrapping_sub
Line
Count
Source
34
6.14k
    pub(crate) fn wrapping_sub(self, rhs: Self) -> isize {
35
6.14k
        // The result is the same with `(self.data & !1).wrapping_sub(rhs.data & !1) as isize >> 1`,
36
6.14k
        // because the possible difference of LSB in `(self.data & !1).wrapping_sub(rhs.data & !1)`
37
6.14k
        // will be ignored in the shift operation.
38
6.14k
        self.data.wrapping_sub(rhs.data & !1) as isize >> 1
39
6.14k
    }
<crossbeam_epoch::epoch::Epoch>::wrapping_sub
Line
Count
Source
34
3.59M
    pub(crate) fn wrapping_sub(self, rhs: Self) -> isize {
35
3.59M
        // The result is the same with `(self.data & !1).wrapping_sub(rhs.data & !1) as isize >> 1`,
36
3.59M
        // because the possible difference of LSB in `(self.data & !1).wrapping_sub(rhs.data & !1)`
37
3.59M
        // will be ignored in the shift operation.
38
3.59M
        self.data.wrapping_sub(rhs.data & !1) as isize >> 1
39
3.59M
    }
40
41
    /// Returns `true` if the epoch is marked as pinned.
42
    #[inline]
43
10.6M
    pub(crate) fn is_pinned(self) -> bool {
44
10.6M
        (self.data & 1) == 1
45
10.6M
    }
<crossbeam_epoch::epoch::Epoch>::is_pinned
Line
Count
Source
43
86.1k
    pub(crate) fn is_pinned(self) -> bool {
44
86.1k
        (self.data & 1) == 1
45
86.1k
    }
<crossbeam_epoch::epoch::Epoch>::is_pinned
Line
Count
Source
43
10.6M
    pub(crate) fn is_pinned(self) -> bool {
44
10.6M
        (self.data & 1) == 1
45
10.6M
    }
46
47
    /// Returns the same epoch, but marked as pinned.
48
    #[inline]
49
13.1M
    pub(crate) fn pinned(self) -> Epoch {
50
13.1M
        Epoch {
51
13.1M
            data: self.data | 1,
52
13.1M
        }
53
13.1M
    }
<crossbeam_epoch::epoch::Epoch>::pinned
Line
Count
Source
49
206
    pub(crate) fn pinned(self) -> Epoch {
50
206
        Epoch {
51
206
            data: self.data | 1,
52
206
        }
53
206
    }
<crossbeam_epoch::epoch::Epoch>::pinned
Line
Count
Source
49
146
    pub(crate) fn pinned(self) -> Epoch {
50
146
        Epoch {
51
146
            data: self.data | 1,
52
146
        }
53
146
    }
<crossbeam_epoch::epoch::Epoch>::pinned
Line
Count
Source
49
3
    pub(crate) fn pinned(self) -> Epoch {
50
3
        Epoch {
51
3
            data: self.data | 1,
52
3
        }
53
3
    }
<crossbeam_epoch::epoch::Epoch>::pinned
Line
Count
Source
49
21
    pub(crate) fn pinned(self) -> Epoch {
50
21
        Epoch {
51
21
            data: self.data | 1,
52
21
        }
53
21
    }
<crossbeam_epoch::epoch::Epoch>::pinned
Line
Count
Source
49
1
    pub(crate) fn pinned(self) -> Epoch {
50
1
        Epoch {
51
1
            data: self.data | 1,
52
1
        }
53
1
    }
<crossbeam_epoch::epoch::Epoch>::pinned
Line
Count
Source
49
433k
    pub(crate) fn pinned(self) -> Epoch {
50
433k
        Epoch {
51
433k
            data: self.data | 1,
52
433k
        }
53
433k
    }
<crossbeam_epoch::epoch::Epoch>::pinned
Line
Count
Source
49
14
    pub(crate) fn pinned(self) -> Epoch {
50
14
        Epoch {
51
14
            data: self.data | 1,
52
14
        }
53
14
    }
<crossbeam_epoch::epoch::Epoch>::pinned
Line
Count
Source
49
573k
    pub(crate) fn pinned(self) -> Epoch {
50
573k
        Epoch {
51
573k
            data: self.data | 1,
52
573k
        }
53
573k
    }
<crossbeam_epoch::epoch::Epoch>::pinned
Line
Count
Source
49
12.1M
    pub(crate) fn pinned(self) -> Epoch {
50
12.1M
        Epoch {
51
12.1M
            data: self.data | 1,
52
12.1M
        }
53
12.1M
    }
54
55
    /// Returns the same epoch, but marked as unpinned.
56
    #[inline]
57
9.75M
    pub(crate) fn unpinned(self) -> Epoch {
58
9.75M
        Epoch {
59
9.75M
            data: self.data & !1,
60
9.75M
        }
61
9.75M
    }
<crossbeam_epoch::epoch::Epoch>::unpinned
Line
Count
Source
57
37.5k
    pub(crate) fn unpinned(self) -> Epoch {
58
37.5k
        Epoch {
59
37.5k
            data: self.data & !1,
60
37.5k
        }
61
37.5k
    }
<crossbeam_epoch::epoch::Epoch>::unpinned
Line
Count
Source
57
9.71M
    pub(crate) fn unpinned(self) -> Epoch {
58
9.71M
        Epoch {
59
9.71M
            data: self.data & !1,
60
9.71M
        }
61
9.71M
    }
62
63
    /// Returns the successor epoch.
64
    ///
65
    /// The returned epoch will be marked as pinned only if the previous one was as well.
66
    #[inline]
67
248k
    pub(crate) fn successor(self) -> Epoch {
68
248k
        Epoch {
69
248k
            data: self.data.wrapping_add(2),
70
248k
        }
71
248k
    }
<crossbeam_epoch::epoch::Epoch>::successor
Line
Count
Source
67
2.54k
    pub(crate) fn successor(self) -> Epoch {
68
2.54k
        Epoch {
69
2.54k
            data: self.data.wrapping_add(2),
70
2.54k
        }
71
2.54k
    }
<crossbeam_epoch::epoch::Epoch>::successor
Line
Count
Source
67
246k
    pub(crate) fn successor(self) -> Epoch {
68
246k
        Epoch {
69
246k
            data: self.data.wrapping_add(2),
70
246k
        }
71
246k
    }
72
}
73
74
/// An atomic value that holds an `Epoch`.
75
0
#[derive(Default, Debug)]
76
pub(crate) struct AtomicEpoch {
77
    /// Since `Epoch` is just a wrapper around `usize`, an `AtomicEpoch` is similarly represented
78
    /// using an `AtomicUsize`.
79
    data: AtomicUsize,
80
}
81
82
impl AtomicEpoch {
83
    /// Creates a new atomic epoch.
84
    #[inline]
85
270
    pub(crate) fn new(epoch: Epoch) -> Self {
86
270
        let data = AtomicUsize::new(epoch.data);
87
270
        AtomicEpoch { data }
88
270
    }
<crossbeam_epoch::epoch::AtomicEpoch>::new
Line
Count
Source
85
187
    pub(crate) fn new(epoch: Epoch) -> Self {
86
187
        let data = AtomicUsize::new(epoch.data);
87
187
        AtomicEpoch { data }
88
187
    }
<crossbeam_epoch::epoch::AtomicEpoch>::new
Line
Count
Source
85
83
    pub(crate) fn new(epoch: Epoch) -> Self {
86
83
        let data = AtomicUsize::new(epoch.data);
87
83
        AtomicEpoch { data }
88
83
    }
89
90
    /// Loads a value from the atomic epoch.
91
    #[inline]
92
25.4M
    pub(crate) fn load(&self, ord: Ordering) -> Epoch {
93
25.4M
        Epoch {
94
25.4M
            data: self.data.load(ord),
95
25.4M
        }
96
25.4M
    }
<crossbeam_epoch::epoch::AtomicEpoch>::load
Line
Count
Source
92
206
    pub(crate) fn load(&self, ord: Ordering) -> Epoch {
93
206
        Epoch {
94
206
            data: self.data.load(ord),
95
206
        }
96
206
    }
<crossbeam_epoch::epoch::AtomicEpoch>::load
Line
Count
Source
92
95.9k
    pub(crate) fn load(&self, ord: Ordering) -> Epoch {
93
95.9k
        Epoch {
94
95.9k
            data: self.data.load(ord),
95
95.9k
        }
96
95.9k
    }
<crossbeam_epoch::epoch::AtomicEpoch>::load
Line
Count
Source
92
3
    pub(crate) fn load(&self, ord: Ordering) -> Epoch {
93
3
        Epoch {
94
3
            data: self.data.load(ord),
95
3
        }
96
3
    }
<crossbeam_epoch::epoch::AtomicEpoch>::load
Line
Count
Source
92
21
    pub(crate) fn load(&self, ord: Ordering) -> Epoch {
93
21
        Epoch {
94
21
            data: self.data.load(ord),
95
21
        }
96
21
    }
<crossbeam_epoch::epoch::AtomicEpoch>::load
Line
Count
Source
92
1
    pub(crate) fn load(&self, ord: Ordering) -> Epoch {
93
1
        Epoch {
94
1
            data: self.data.load(ord),
95
1
        }
96
1
    }
<crossbeam_epoch::epoch::AtomicEpoch>::load
Line
Count
Source
92
432k
    pub(crate) fn load(&self, ord: Ordering) -> Epoch {
93
432k
        Epoch {
94
432k
            data: self.data.load(ord),
95
432k
        }
96
432k
    }
<crossbeam_epoch::epoch::AtomicEpoch>::load
Line
Count
Source
92
14
    pub(crate) fn load(&self, ord: Ordering) -> Epoch {
93
14
        Epoch {
94
14
            data: self.data.load(ord),
95
14
        }
96
14
    }
<crossbeam_epoch::epoch::AtomicEpoch>::load
Line
Count
Source
92
540k
    pub(crate) fn load(&self, ord: Ordering) -> Epoch {
93
540k
        Epoch {
94
540k
            data: self.data.load(ord),
95
540k
        }
96
540k
    }
<crossbeam_epoch::epoch::AtomicEpoch>::load
Line
Count
Source
92
24.3M
    pub(crate) fn load(&self, ord: Ordering) -> Epoch {
93
24.3M
        Epoch {
94
24.3M
            data: self.data.load(ord),
95
24.3M
        }
96
24.3M
    }
97
98
    /// Stores a value into the atomic epoch.
99
    #[inline]
100
13.4M
    pub(crate) fn store(&self, epoch: Epoch, ord: Ordering) {
101
13.4M
        self.data.store(epoch.data, ord);
102
13.4M
    }
<crossbeam_epoch::epoch::AtomicEpoch>::store
Line
Count
Source
100
986k
    pub(crate) fn store(&self, epoch: Epoch, ord: Ordering) {
101
986k
        self.data.store(epoch.data, ord);
102
986k
    }
<crossbeam_epoch::epoch::AtomicEpoch>::store
Line
Count
Source
100
12.5M
    pub(crate) fn store(&self, epoch: Epoch, ord: Ordering) {
101
12.5M
        self.data.store(epoch.data, ord);
102
12.5M
    }
103
104
    /// Stores a value into the atomic epoch if the current value is the same as `current`.
105
    ///
106
    /// The return value is a result indicating whether the new value was written and containing
107
    /// the previous value. On success this value is guaranteed to be equal to `current`.
108
    ///
109
    /// This method takes two `Ordering` arguments to describe the memory
110
    /// ordering of this operation. `success` describes the required ordering for the
111
    /// read-modify-write operation that takes place if the comparison with `current` succeeds.
112
    /// `failure` describes the required ordering for the load operation that takes place when
113
    /// the comparison fails. Using `Acquire` as success ordering makes the store part
114
    /// of this operation `Relaxed`, and using `Release` makes the successful load
115
    /// `Relaxed`. The failure ordering can only be `SeqCst`, `Acquire` or `Relaxed`
116
    /// and must be equivalent to or weaker than the success ordering.
117
    #[inline]
118
12.6M
    pub(crate) fn compare_exchange(
119
12.6M
        &self,
120
12.6M
        current: Epoch,
121
12.6M
        new: Epoch,
122
12.6M
        success: Ordering,
123
12.6M
        failure: Ordering,
124
12.6M
    ) -> Result<Epoch, Epoch> {
125
12.6M
        match self
126
12.6M
            .data
127
12.6M
            .compare_exchange(current.data, new.data, success, failure)
128
        {
129
12.6M
            Ok(data) => Ok(Epoch { data }),
130
0
            Err(data) => Err(Epoch { data }),
131
        }
132
12.6M
    }
<crossbeam_epoch::epoch::AtomicEpoch>::compare_exchange
Line
Count
Source
118
206
    pub(crate) fn compare_exchange(
119
206
        &self,
120
206
        current: Epoch,
121
206
        new: Epoch,
122
206
        success: Ordering,
123
206
        failure: Ordering,
124
206
    ) -> Result<Epoch, Epoch> {
125
206
        match self
126
206
            .data
127
206
            .compare_exchange(current.data, new.data, success, failure)
128
        {
129
206
            Ok(data) => Ok(Epoch { data }),
130
0
            Err(data) => Err(Epoch { data }),
131
        }
132
206
    }
<crossbeam_epoch::epoch::AtomicEpoch>::compare_exchange
Line
Count
Source
118
145
    pub(crate) fn compare_exchange(
119
145
        &self,
120
145
        current: Epoch,
121
145
        new: Epoch,
122
145
        success: Ordering,
123
145
        failure: Ordering,
124
145
    ) -> Result<Epoch, Epoch> {
125
145
        match self
126
145
            .data
127
145
            .compare_exchange(current.data, new.data, success, failure)
128
        {
129
145
            Ok(data) => Ok(Epoch { data }),
130
0
            Err(data) => Err(Epoch { data }),
131
        }
132
145
    }
Unexecuted instantiation: <crossbeam_epoch::epoch::AtomicEpoch>::compare_exchange
<crossbeam_epoch::epoch::AtomicEpoch>::compare_exchange
Line
Count
Source
118
3
    pub(crate) fn compare_exchange(
119
3
        &self,
120
3
        current: Epoch,
121
3
        new: Epoch,
122
3
        success: Ordering,
123
3
        failure: Ordering,
124
3
    ) -> Result<Epoch, Epoch> {
125
3
        match self
126
3
            .data
127
3
            .compare_exchange(current.data, new.data, success, failure)
128
        {
129
3
            Ok(data) => Ok(Epoch { data }),
130
0
            Err(data) => Err(Epoch { data }),
131
        }
132
3
    }
<crossbeam_epoch::epoch::AtomicEpoch>::compare_exchange
Line
Count
Source
118
21
    pub(crate) fn compare_exchange(
119
21
        &self,
120
21
        current: Epoch,
121
21
        new: Epoch,
122
21
        success: Ordering,
123
21
        failure: Ordering,
124
21
    ) -> Result<Epoch, Epoch> {
125
21
        match self
126
21
            .data
127
21
            .compare_exchange(current.data, new.data, success, failure)
128
        {
129
21
            Ok(data) => Ok(Epoch { data }),
130
0
            Err(data) => Err(Epoch { data }),
131
        }
132
21
    }
<crossbeam_epoch::epoch::AtomicEpoch>::compare_exchange
Line
Count
Source
118
1
    pub(crate) fn compare_exchange(
119
1
        &self,
120
1
        current: Epoch,
121
1
        new: Epoch,
122
1
        success: Ordering,
123
1
        failure: Ordering,
124
1
    ) -> Result<Epoch, Epoch> {
125
1
        match self
126
1
            .data
127
1
            .compare_exchange(current.data, new.data, success, failure)
128
        {
129
1
            Ok(data) => Ok(Epoch { data }),
130
0
            Err(data) => Err(Epoch { data }),
131
        }
132
1
    }
<crossbeam_epoch::epoch::AtomicEpoch>::compare_exchange
Line
Count
Source
118
408k
    pub(crate) fn compare_exchange(
119
408k
        &self,
120
408k
        current: Epoch,
121
408k
        new: Epoch,
122
408k
        success: Ordering,
123
408k
        failure: Ordering,
124
408k
    ) -> Result<Epoch, Epoch> {
125
408k
        match self
126
408k
            .data
127
408k
            .compare_exchange(current.data, new.data, success, failure)
128
        {
129
408k
            Ok(data) => Ok(Epoch { data }),
130
0
            Err(data) => Err(Epoch { data }),
131
        }
132
408k
    }
<crossbeam_epoch::epoch::AtomicEpoch>::compare_exchange
Line
Count
Source
118
14
    pub(crate) fn compare_exchange(
119
14
        &self,
120
14
        current: Epoch,
121
14
        new: Epoch,
122
14
        success: Ordering,
123
14
        failure: Ordering,
124
14
    ) -> Result<Epoch, Epoch> {
125
14
        match self
126
14
            .data
127
14
            .compare_exchange(current.data, new.data, success, failure)
128
        {
129
14
            Ok(data) => Ok(Epoch { data }),
130
0
            Err(data) => Err(Epoch { data }),
131
        }
132
14
    }
<crossbeam_epoch::epoch::AtomicEpoch>::compare_exchange
Line
Count
Source
118
550k
    pub(crate) fn compare_exchange(
119
550k
        &self,
120
550k
        current: Epoch,
121
550k
        new: Epoch,
122
550k
        success: Ordering,
123
550k
        failure: Ordering,
124
550k
    ) -> Result<Epoch, Epoch> {
125
550k
        match self
126
550k
            .data
127
550k
            .compare_exchange(current.data, new.data, success, failure)
128
        {
129
550k
            Ok(data) => Ok(Epoch { data }),
130
0
            Err(data) => Err(Epoch { data }),
131
        }
132
550k
    }
<crossbeam_epoch::epoch::AtomicEpoch>::compare_exchange
Line
Count
Source
118
11.7M
    pub(crate) fn compare_exchange(
119
11.7M
        &self,
120
11.7M
        current: Epoch,
121
11.7M
        new: Epoch,
122
11.7M
        success: Ordering,
123
11.7M
        failure: Ordering,
124
11.7M
    ) -> Result<Epoch, Epoch> {
125
11.7M
        match self
126
11.7M
            .data
127
11.7M
            .compare_exchange(current.data, new.data, success, failure)
128
        {
129
11.7M
            Ok(data) => Ok(Epoch { data }),
130
0
            Err(data) => Err(Epoch { data }),
131
        }
132
11.7M
    }
133
}