Coverage Report

Created: 2021-01-22 16:54

crossbeam-epoch/src/collector.rs
Line
Count
Source (jump to first uncovered line)
1
/// Epoch-based garbage collector.
2
///
3
/// # Examples
4
///
5
/// ```
6
/// use crossbeam_epoch::Collector;
7
///
8
/// let collector = Collector::new();
9
///
10
/// let handle = collector.register();
11
/// drop(collector); // `handle` still works after dropping `collector`
12
///
13
/// handle.pin().flush();
14
/// ```
15
use core::fmt;
16
17
use crate::primitive::sync::Arc;
18
use crate::guard::Guard;
19
use crate::internal::{Global, Local};
20
21
/// An epoch-based garbage collector.
22
pub struct Collector {
23
    pub(crate) global: Arc<Global>,
24
}
25
26
unsafe impl Send for Collector {}
27
unsafe impl Sync for Collector {}
28
29
impl Default for Collector {
30
59
    fn default() -> Self {
31
59
        Self {
32
59
            global: Arc::new(Global::new()),
33
59
        }
34
59
    }
35
}
36
37
impl Collector {
38
    /// Creates a new collector.
39
59
    pub fn new() -> Self {
40
59
        Self::default()
41
59
    }
<crossbeam_epoch::collector::Collector>::new
Line
Count
Source
39
43
    pub fn new() -> Self {
40
43
        Self::default()
41
43
    }
<crossbeam_epoch::collector::Collector>::new
Line
Count
Source
39
16
    pub fn new() -> Self {
40
16
        Self::default()
41
16
    }
42
43
    /// Registers a new handle for the collector.
44
214
    pub fn register(&self) -> LocalHandle {
45
214
        Local::register(self)
46
214
    }
<crossbeam_epoch::collector::Collector>::register
Line
Count
Source
44
146
    pub fn register(&self) -> LocalHandle {
45
146
        Local::register(self)
46
146
    }
<crossbeam_epoch::collector::Collector>::register
Line
Count
Source
44
68
    pub fn register(&self) -> LocalHandle {
45
68
        Local::register(self)
46
68
    }
47
}
48
49
impl Clone for Collector {
50
    /// Creates another reference to the same garbage collector.
51
238
    fn clone(&self) -> Self {
52
238
        Collector {
53
238
            global: self.global.clone(),
54
238
        }
55
238
    }
<crossbeam_epoch::collector::Collector as core::clone::Clone>::clone
Line
Count
Source
51
170
    fn clone(&self) -> Self {
52
170
        Collector {
53
170
            global: self.global.clone(),
54
170
        }
55
170
    }
<crossbeam_epoch::collector::Collector as core::clone::Clone>::clone
Line
Count
Source
51
68
    fn clone(&self) -> Self {
52
68
        Collector {
53
68
            global: self.global.clone(),
54
68
        }
55
68
    }
56
}
57
58
impl fmt::Debug for Collector {
59
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60
0
        f.pad("Collector { .. }")
61
0
    }
62
}
63
64
impl PartialEq for Collector {
65
    /// Checks if both handles point to the same collector.
66
693
    fn eq(&self, rhs: &Collector) -> bool {
67
693
        Arc::ptr_eq(&self.global, &rhs.global)
68
693
    }
69
}
70
impl Eq for Collector {}
71
72
/// A handle to a garbage collector.
73
pub struct LocalHandle {
74
    pub(crate) local: *const Local,
75
}
76
77
impl LocalHandle {
78
    /// Pins the handle.
79
    #[inline]
80
13.4M
    pub fn pin(&self) -> Guard {
81
13.4M
        unsafe { (*self.local).pin() }
82
13.4M
    }
<crossbeam_epoch::collector::LocalHandle>::pin
Line
Count
Source
80
206
    pub fn pin(&self) -> Guard {
81
206
        unsafe { (*self.local).pin() }
82
206
    }
<crossbeam_epoch::collector::LocalHandle>::pin
Line
Count
Source
80
3
    pub fn pin(&self) -> Guard {
81
3
        unsafe { (*self.local).pin() }
82
3
    }
<crossbeam_epoch::collector::LocalHandle>::pin
Line
Count
Source
80
21
    pub fn pin(&self) -> Guard {
81
21
        unsafe { (*self.local).pin() }
82
21
    }
<crossbeam_epoch::collector::LocalHandle>::pin
Line
Count
Source
80
1
    pub fn pin(&self) -> Guard {
81
1
        unsafe { (*self.local).pin() }
82
1
    }
<crossbeam_epoch::collector::LocalHandle>::pin
Line
Count
Source
80
427k
    pub fn pin(&self) -> Guard {
81
427k
        unsafe { (*self.local).pin() }
82
427k
    }
<crossbeam_epoch::collector::LocalHandle>::pin
Line
Count
Source
80
14
    pub fn pin(&self) -> Guard {
81
14
        unsafe { (*self.local).pin() }
82
14
    }
<crossbeam_epoch::collector::LocalHandle>::pin
Line
Count
Source
80
559k
    pub fn pin(&self) -> Guard {
81
559k
        unsafe { (*self.local).pin() }
82
559k
    }
<crossbeam_epoch::collector::LocalHandle>::pin
Line
Count
Source
80
12.4M
    pub fn pin(&self) -> Guard {
81
12.4M
        unsafe { (*self.local).pin() }
82
12.4M
    }
83
84
    /// Returns `true` if the handle is pinned.
85
    #[inline]
86
897k
    pub fn is_pinned(&self) -> bool {
87
897k
        unsafe { (*self.local).is_pinned() }
88
897k
    }
<crossbeam_epoch::collector::LocalHandle>::is_pinned
Line
Count
Source
86
389k
    pub fn is_pinned(&self) -> bool {
87
389k
        unsafe { (*self.local).is_pinned() }
88
389k
    }
<crossbeam_epoch::collector::LocalHandle>::is_pinned
Line
Count
Source
86
14
    pub fn is_pinned(&self) -> bool {
87
14
        unsafe { (*self.local).is_pinned() }
88
14
    }
<crossbeam_epoch::collector::LocalHandle>::is_pinned
Line
Count
Source
86
507k
    pub fn is_pinned(&self) -> bool {
87
507k
        unsafe { (*self.local).is_pinned() }
88
507k
    }
<crossbeam_epoch::collector::LocalHandle>::is_pinned
Line
Count
Source
86
5
    pub fn is_pinned(&self) -> bool {
87
5
        unsafe { (*self.local).is_pinned() }
88
5
    }
89
90
    /// Returns the `Collector` associated with this handle.
91
    #[inline]
92
0
    pub fn collector(&self) -> &Collector {
93
0
        unsafe { (*self.local).collector() }
94
0
    }
<crossbeam_epoch::collector::Collector as core::default::Default>::default
Line
Count
Source
30
43
    fn default() -> Self {
31
43
        Self {
32
43
            global: Arc::new(Global::new()),
33
43
        }
34
43
    }
35
}
36
37
impl Collector {
38
    /// Creates a new collector.
39
    pub fn new() -> Self {
40
        Self::default()
41
    }
42
43
    /// Registers a new handle for the collector.
44
    pub fn register(&self) -> LocalHandle {
45
        Local::register(self)
46
    }
47
}
48
49
impl Clone for Collector {
50
    /// Creates another reference to the same garbage collector.
51
    fn clone(&self) -> Self {
52
        Collector {
53
            global: self.global.clone(),
54
        }
55
    }
56
}
57
58
impl fmt::Debug for Collector {
59
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60
        f.pad("Collector { .. }")
61
    }
62
}
63
64
impl PartialEq for Collector {
65
    /// Checks if both handles point to the same collector.
66
    fn eq(&self, rhs: &Collector) -> bool {
67
        Arc::ptr_eq(&self.global, &rhs.global)
68
    }
69
}
70
impl Eq for Collector {}
71
72
/// A handle to a garbage collector.
73
pub struct LocalHandle {
74
    pub(crate) local: *const Local,
75
}
76
77
impl LocalHandle {
78
    /// Pins the handle.
79
    #[inline]
80
0
    pub fn pin(&self) -> Guard {
81
0
        unsafe { (*self.local).pin() }
82
0
    }
83
84
    /// Returns `true` if the handle is pinned.
85
    #[inline]
86
0
    pub fn is_pinned(&self) -> bool {
87
0
        unsafe { (*self.local).is_pinned() }
88
0
    }
89
90
    /// Returns the `Collector` associated with this handle.
91
    #[inline]
92
0
    pub fn collector(&self) -> &Collector {
93
0
        unsafe { (*self.local).collector() }
94
0
    }
95
}
96
97
impl Drop for LocalHandle {
98
    #[inline]
99
215
    fn drop(&mut self) {
100
215
        unsafe {
101
215
            Local::release_handle(&*self.local);
102
215
        }
103
215
    }
<crossbeam_epoch::collector::LocalHandle as core::ops::drop::Drop>::drop
Line
Count
Source
99
145
    fn drop(&mut self) {
100
145
        unsafe {
101
145
            Local::release_handle(&*self.local);
102
145
        }
103
145
    }
<crossbeam_epoch::collector::LocalHandle as core::ops::drop::Drop>::drop
Line
Count
Source
99
70
    fn drop(&mut self) {
100
70
        unsafe {
101
70
            Local::release_handle(&*self.local);
102
70
        }
103
70
    }
104
}
105
106
impl fmt::Debug for LocalHandle {
107
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108
0
        f.pad("LocalHandle { .. }")
109
0
    }
<crossbeam_epoch::collector::Collector as core::default::Default>::default
Line
Count
Source
30
16
    fn default() -> Self {
31
16
        Self {
32
16
            global: Arc::new(Global::new()),
33
16
        }
34
16
    }
35
}
36
37
impl Collector {
38
    /// Creates a new collector.
39
    pub fn new() -> Self {
40
        Self::default()
41
    }
42
43
    /// Registers a new handle for the collector.
44
    pub fn register(&self) -> LocalHandle {
45
        Local::register(self)
46
    }
47
}
48
49
impl Clone for Collector {
50
    /// Creates another reference to the same garbage collector.
51
    fn clone(&self) -> Self {
52
        Collector {
53
            global: self.global.clone(),
54
        }
55
    }
56
}
57
58
impl fmt::Debug for Collector {
59
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60
0
        f.pad("Collector { .. }")
61
0
    }
62
}
63
64
impl PartialEq for Collector {
65
    /// Checks if both handles point to the same collector.
66
0
    fn eq(&self, rhs: &Collector) -> bool {
67
0
        Arc::ptr_eq(&self.global, &rhs.global)
68
0
    }
69
}
70
impl Eq for Collector {}
71
72
/// A handle to a garbage collector.
73
pub struct LocalHandle {
74
    pub(crate) local: *const Local,
75
}
76
77
impl LocalHandle {
78
    /// Pins the handle.
79
    #[inline]
80
    pub fn pin(&self) -> Guard {
81
        unsafe { (*self.local).pin() }
82
    }
83
84
    /// Returns `true` if the handle is pinned.
85
    #[inline]
86
    pub fn is_pinned(&self) -> bool {
87
        unsafe { (*self.local).is_pinned() }
88
    }
89
90
    /// Returns the `Collector` associated with this handle.
91
    #[inline]
92
0
    pub fn collector(&self) -> &Collector {
93
0
        unsafe { (*self.local).collector() }
94
0
    }
95
}
96
97
impl Drop for LocalHandle {
98
    #[inline]
99
    fn drop(&mut self) {
100
        unsafe {
101
            Local::release_handle(&*self.local);
102
        }
103
    }
104
}
105
106
impl fmt::Debug for LocalHandle {
107
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108
0
        f.pad("LocalHandle { .. }")
109
0
    }
110
}
111
112
#[cfg(all(test, not(loom_crossbeam)))]
113
mod tests {
114
    use std::mem;
115
    use std::sync::atomic::{AtomicUsize, Ordering};
116
117
    use crossbeam_utils::thread;
118
119
    use crate::{Collector, Owned};
120
121
    const NUM_THREADS: usize = 8;
122
123
    #[test]
124
1
    fn pin_reentrant() {
crossbeam_epoch::collector::tests::pin_reentrant::{closure#0}
Line
Count
Source
124
1
    fn pin_reentrant() {
125
1
        let collector = Collector::new();
126
1
        let handle = collector.register();
127
1
        drop(collector);
128
129
1
        assert!(!handle.is_pinned());
130
        {
131
1
            let _guard = &handle.pin();
132
1
            assert!(handle.is_pinned());
133
            {
134
1
                let _guard = &handle.pin();
135
1
                assert!(handle.is_pinned());
136
            }
137
1
            assert!(handle.is_pinned());
138
        }
139
1
        assert!(!handle.is_pinned());
140
1
    }
crossbeam_epoch::collector::tests::pin_reentrant
Line
Count
Source
124
1
    fn pin_reentrant() {
125
1
        let collector = Collector::new();
126
1
        let handle = collector.register();
127
1
        drop(collector);
128
129
1
        assert!(!handle.is_pinned());
130
        {
131
1
            let _guard = &handle.pin();
132
1
            assert!(handle.is_pinned());
133
            {
134
1
                let _guard = &handle.pin();
135
1
                assert!(handle.is_pinned());
136
            }
137
1
            assert!(handle.is_pinned());
138
        }
139
1
        assert!(!handle.is_pinned());
140
1
    }
141
142
    #[test]
143
1
    fn flush_local_bag() {
crossbeam_epoch::collector::tests::flush_local_bag::{closure#0}
Line
Count
Source
143
1
    fn flush_local_bag() {
144
1
        let collector = Collector::new();
145
1
        let handle = collector.register();
146
1
        drop(collector);
147
148
101
        for 
_100
in 0..100 {
149
100
            let guard = &handle.pin();
150
100
            unsafe {
151
100
                let a = Owned::new(7).into_shared(guard);
152
100
                guard.defer_destroy(a);
153
154
100
                assert!(!(*guard.local).bag.with(|b| (*b).is_empty()));
155
156
298
                while !(*guard.local).bag.with(|b| (*b).is_empty()) {
157
198
                    guard.flush();
158
198
                }
159
            }
160
        }
161
1
    }
crossbeam_epoch::collector::tests::flush_local_bag
Line
Count
Source
143
1
    fn flush_local_bag() {
144
1
        let collector = Collector::new();
145
1
        let handle = collector.register();
146
1
        drop(collector);
147
148
101
        for 
_100
in 0..100 {
149
100
            let guard = &handle.pin();
150
100
            unsafe {
151
100
                let a = Owned::new(7).into_shared(guard);
152
100
                guard.defer_destroy(a);
153
154
100
                assert!(!(*guard.local).bag.with(|b| (*b).is_empty()));
155
156
298
                while !(*guard.local).bag.with(|b| (*b).is_empty()) {
157
198
                    guard.flush();
158
198
                }
159
            }
160
        }
161
1
    }
162
163
    #[test]
164
1
    fn garbage_buffering() {
crossbeam_epoch::collector::tests::garbage_buffering::{closure#0}
Line
Count
Source
164
1
    fn garbage_buffering() {
165
1
        let collector = Collector::new();
166
1
        let handle = collector.register();
167
1
        drop(collector);
168
1
169
1
        let guard = &handle.pin();
170
        unsafe {
171
11
            for 
_10
in 0..10 {
172
10
                let a = Owned::new(7).into_shared(guard);
173
10
                guard.defer_destroy(a);
174
10
            }
175
1
            assert!(!(*guard.local).bag.with(|b| (*b).is_empty()));
176
        }
177
1
    }
crossbeam_epoch::collector::tests::garbage_buffering
Line
Count
Source
164
1
    fn garbage_buffering() {
165
1
        let collector = Collector::new();
166
1
        let handle = collector.register();
167
1
        drop(collector);
168
1
169
1
        let guard = &handle.pin();
170
        unsafe {
171
11
            for 
_10
in 0..10 {
172
10
                let a = Owned::new(7).into_shared(guard);
173
10
                guard.defer_destroy(a);
174
10
            }
175
1
            assert!(!(*guard.local).bag.with(|b| (*b).is_empty()));
176
        }
177
1
    }
178
179
    #[test]
180
1
    fn pin_holds_advance() {
crossbeam_epoch::collector::tests::pin_holds_advance::{closure#0}
Line
Count
Source
180
1
    fn pin_holds_advance() {
181
1
        let collector = Collector::new();
182
1
183
1
        thread::scope(|scope| {
184
9
            for 
_8
in 0..NUM_THREADS {
185
8
                scope.spawn(|_| {
186
8
                    let handle = collector.register();
187
3.50M
                    for 
_3.50M
in 0..500_000 {
188
3.50M
                        let guard = &handle.pin();
189
3.50M
190
3.50M
                        let before = collector.global.epoch.load(Ordering::Relaxed);
191
3.50M
                        collector.global.collect(guard);
192
3.50M
                        let after = collector.global.epoch.load(Ordering::Relaxed);
193
194
3.50M
                        assert!(after.wrapping_sub(before) <= 2);
195
                    }
196
8
                });
197
8
            }
198
1
        })
199
1
        .unwrap();
200
1
    }
crossbeam_epoch::collector::tests::pin_holds_advance
Line
Count
Source
180
1
    fn pin_holds_advance() {
181
1
        let collector = Collector::new();
182
1
183
1
        thread::scope(|scope| {
184
            for _ in 0..NUM_THREADS {
185
                scope.spawn(|_| {
186
                    let handle = collector.register();
187
                    for _ in 0..500_000 {
188
                        let guard = &handle.pin();
189
190
                        let before = collector.global.epoch.load(Ordering::Relaxed);
191
                        collector.global.collect(guard);
192
                        let after = collector.global.epoch.load(Ordering::Relaxed);
193
194
                        assert!(after.wrapping_sub(before) <= 2);
195
                    }
196
                });
197
            }
198
1
        })
199
1
        .unwrap();
200
1
    }
201
202
    #[test]
203
1
    fn incremental() {
crossbeam_epoch::collector::tests::incremental::{closure#0}
Line
Count
Source
203
1
    fn incremental() {
204
        const COUNT: usize = 100_000;
205
        static DESTROYS: AtomicUsize = AtomicUsize::new(0);
206
207
1
        let collector = Collector::new();
208
1
        let handle = collector.register();
209
210
        unsafe {
211
1
            let guard = &handle.pin();
212
100k
            for 
_100k
in 0..COUNT {
213
100k
                let a = Owned::new(7i32).into_shared(guard);
214
100k
                guard.defer_unchecked(move || {
215
100k
                    drop(a.into_owned());
216
100k
                    DESTROYS.fetch_add(1, Ordering::Relaxed);
217
100k
                });
218
100k
            }
219
1
            guard.flush();
220
1
        }
221
1
222
1
        let mut last = 0;
223
224
204
        while last < COUNT {
225
203
            let curr = DESTROYS.load(Ordering::Relaxed);
226
203
            assert!(curr - last <= 1024);
227
203
            last = curr;
228
203
229
203
            let guard = &handle.pin();
230
203
            collector.global.collect(guard);
231
        }
232
1
        assert!(DESTROYS.load(Ordering::Relaxed) == 100_000);
233
1
    }
crossbeam_epoch::collector::tests::incremental
Line
Count
Source
203
1
    fn incremental() {
204
        const COUNT: usize = 100_000;
205
        static DESTROYS: AtomicUsize = AtomicUsize::new(0);
206
207
1
        let collector = Collector::new();
208
1
        let handle = collector.register();
209
210
        unsafe {
211
1
            let guard = &handle.pin();
212
100k
            for 
_100k
in 0..COUNT {
213
100k
                let a = Owned::new(7i32).into_shared(guard);
214
100k
                guard.defer_unchecked(move || {
215
                    drop(a.into_owned());
216
                    DESTROYS.fetch_add(1, Ordering::Relaxed);
217
100k
                });
218
100k
            }
219
1
            guard.flush();
220
1
        }
221
1
222
1
        let mut last = 0;
223
224
204
        while last < COUNT {
225
203
            let curr = DESTROYS.load(Ordering::Relaxed);
226
203
            assert!(curr - last <= 1024);
227
203
            last = curr;
228
203
229
203
            let guard = &handle.pin();
230
203
            collector.global.collect(guard);
231
        }
232
1
        assert!(DESTROYS.load(Ordering::Relaxed) == 100_000);
233
1
    }
234
235
    #[test]
236
1
    fn buffering() {
crossbeam_epoch::collector::tests::buffering::{closure#0}
Line
Count
Source
236
1
    fn buffering() {
237
        const COUNT: usize = 10;
238
        static DESTROYS: AtomicUsize = AtomicUsize::new(0);
239
240
1
        let collector = Collector::new();
241
1
        let handle = collector.register();
242
1
243
1
        unsafe {
244
1
            let guard = &handle.pin();
245
11
            for 
_10
in 0..COUNT {
246
10
                let a = Owned::new(7i32).into_shared(guard);
247
10
                guard.defer_unchecked(move || {
248
10
                    drop(a.into_owned());
249
10
                    DESTROYS.fetch_add(1, Ordering::Relaxed);
250
10
                });
251
10
            }
252
        }
253
254
100k
        for 
_100k
in 0..100_000 {
255
100k
            collector.global.collect(&handle.pin());
256
100k
        }
257
1
        assert!(DESTROYS.load(Ordering::Relaxed) < COUNT);
258
259
1
        handle.pin().flush();
260
261
2
        while DESTROYS.load(Ordering::Relaxed) < COUNT {
262
1
            let guard = &handle.pin();
263
1
            collector.global.collect(guard);
264
1
        }
265
1
        assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT);
266
1
    }
crossbeam_epoch::collector::tests::buffering
Line
Count
Source
236
1
    fn buffering() {
237
        const COUNT: usize = 10;
238
        static DESTROYS: AtomicUsize = AtomicUsize::new(0);
239
240
1
        let collector = Collector::new();
241
1
        let handle = collector.register();
242
1
243
1
        unsafe {
244
1
            let guard = &handle.pin();
245
11
            for 
_10
in 0..COUNT {
246
10
                let a = Owned::new(7i32).into_shared(guard);
247
10
                guard.defer_unchecked(move || {
248
                    drop(a.into_owned());
249
                    DESTROYS.fetch_add(1, Ordering::Relaxed);
250
10
                });
251
10
            }
252
        }
253
254
100k
        for 
_100k
in 0..100_000 {
255
100k
            collector.global.collect(&handle.pin());
256
100k
        }
257
1
        assert!(DESTROYS.load(Ordering::Relaxed) < COUNT);
258
259
1
        handle.pin().flush();
260
261
2
        while DESTROYS.load(Ordering::Relaxed) < COUNT {
262
1
            let guard = &handle.pin();
263
1
            collector.global.collect(guard);
264
1
        }
265
1
        assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT);
266
1
    }
267
268
    #[test]
269
1
    fn count_drops() {
crossbeam_epoch::collector::tests::count_drops::{closure#0}
Line
Count
Source
269
1
    fn count_drops() {
270
        const COUNT: usize = 100_000;
271
        static DROPS: AtomicUsize = AtomicUsize::new(0);
272
273
        struct Elem(i32);
274
275
        impl Drop for Elem {
276
100k
            fn drop(&mut self) {
277
100k
                DROPS.fetch_add(1, Ordering::Relaxed);
278
100k
            }
279
        }
280
281
1
        let collector = Collector::new();
282
1
        let handle = collector.register();
283
284
        unsafe {
285
1
            let guard = &handle.pin();
286
287
100k
            for 
_100k
in 0..COUNT {
288
100k
                let a = Owned::new(Elem(7i32)).into_shared(guard);
289
100k
                guard.defer_destroy(a);
290
100k
            }
291
1
            guard.flush();
292
        }
293
294
203
        while DROPS.load(Ordering::Relaxed) < COUNT {
295
202
            let guard = &handle.pin();
296
202
            collector.global.collect(guard);
297
202
        }
298
1
        assert_eq!(DROPS.load(Ordering::Relaxed), COUNT);
299
1
    }
crossbeam_epoch::collector::tests::count_drops
Line
Count
Source
269
1
    fn count_drops() {
270
        const COUNT: usize = 100_000;
271
        static DROPS: AtomicUsize = AtomicUsize::new(0);
272
273
        struct Elem(i32);
274
275
        impl Drop for Elem {
276
            fn drop(&mut self) {
277
                DROPS.fetch_add(1, Ordering::Relaxed);
278
            }
279
        }
280
281
1
        let collector = Collector::new();
282
1
        let handle = collector.register();
283
284
        unsafe {
285
1
            let guard = &handle.pin();
286
287
100k
            for 
_100k
in 0..COUNT {
288
100k
                let a = Owned::new(Elem(7i32)).into_shared(guard);
289
100k
                guard.defer_destroy(a);
290
100k
            }
291
1
            guard.flush();
292
        }
293
294
203
        while DROPS.load(Ordering::Relaxed) < COUNT {
295
202
            let guard = &handle.pin();
296
202
            collector.global.collect(guard);
297
202
        }
298
1
        assert_eq!(DROPS.load(Ordering::Relaxed), COUNT);
299
1
    }
300
301
    #[test]
302
1
    fn count_destroy() {
crossbeam_epoch::collector::tests::count_destroy::{closure#0}
Line
Count
Source
302
1
    fn count_destroy() {
303
        const COUNT: usize = 100_000;
304
        static DESTROYS: AtomicUsize = AtomicUsize::new(0);
305
306
1
        let collector = Collector::new();
307
1
        let handle = collector.register();
308
309
        unsafe {
310
1
            let guard = &handle.pin();
311
312
100k
            for 
_100k
in 0..COUNT {
313
100k
                let a = Owned::new(7i32).into_shared(guard);
314
100k
                guard.defer_unchecked(move || {
315
100k
                    drop(a.into_owned());
316
100k
                    DESTROYS.fetch_add(1, Ordering::Relaxed);
317
100k
                });
318
100k
            }
319
1
            guard.flush();
320
        }
321
322
203
        while DESTROYS.load(Ordering::Relaxed) < COUNT {
323
202
            let guard = &handle.pin();
324
202
            collector.global.collect(guard);
325
202
        }
326
1
        assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT);
327
1
    }
crossbeam_epoch::collector::tests::count_destroy
Line
Count
Source
302
1
    fn count_destroy() {
303
        const COUNT: usize = 100_000;
304
        static DESTROYS: AtomicUsize = AtomicUsize::new(0);
305
306
1
        let collector = Collector::new();
307
1
        let handle = collector.register();
308
309
        unsafe {
310
1
            let guard = &handle.pin();
311
312
100k
            for 
_100k
in 0..COUNT {
313
100k
                let a = Owned::new(7i32).into_shared(guard);
314
100k
                guard.defer_unchecked(move || {
315
                    drop(a.into_owned());
316
                    DESTROYS.fetch_add(1, Ordering::Relaxed);
317
100k
                });
318
100k
            }
319
1
            guard.flush();
320
        }
321
322
203
        while DESTROYS.load(Ordering::Relaxed) < COUNT {
323
202
            let guard = &handle.pin();
324
202
            collector.global.collect(guard);
325
202
        }
326
1
        assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT);
327
1
    }
328
329
    #[test]
330
1
    fn drop_array() {
crossbeam_epoch::collector::tests::drop_array::{closure#0}
Line
Count
Source
330
1
    fn drop_array() {
331
        const COUNT: usize = 700;
332
        static DROPS: AtomicUsize = AtomicUsize::new(0);
333
334
        struct Elem(i32);
335
336
        impl Drop for Elem {
337
700
            fn drop(&mut self) {
338
700
                DROPS.fetch_add(1, Ordering::Relaxed);
339
700
            }
340
        }
341
342
1
        let collector = Collector::new();
343
1
        let handle = collector.register();
344
1
345
1
        let mut guard = handle.pin();
346
1
347
1
        let mut v = Vec::with_capacity(COUNT);
348
700
        for i in 0..COUNT {
349
700
            v.push(Elem(i as i32));
350
700
        }
351
352
1
        {
353
1
            let a = Owned::new(v).into_shared(&guard);
354
1
            unsafe {
355
1
                guard.defer_destroy(a);
356
1
            }
357
1
            guard.flush();
358
1
        }
359
360
3
        while DROPS.load(Ordering::Relaxed) < COUNT {
361
2
            guard.repin();
362
2
            collector.global.collect(&guard);
363
2
        }
364
1
        assert_eq!(DROPS.load(Ordering::Relaxed), COUNT);
365
1
    }
crossbeam_epoch::collector::tests::drop_array
Line
Count
Source
330
1
    fn drop_array() {
331
        const COUNT: usize = 700;
332
        static DROPS: AtomicUsize = AtomicUsize::new(0);
333
334
        struct Elem(i32);
335
336
        impl Drop for Elem {
337
            fn drop(&mut self) {
338
                DROPS.fetch_add(1, Ordering::Relaxed);
339
            }
340
        }
341
342
1
        let collector = Collector::new();
343
1
        let handle = collector.register();
344
1
345
1
        let mut guard = handle.pin();
346
1
347
1
        let mut v = Vec::with_capacity(COUNT);
348
700
        for i in 0..COUNT {
349
700
            v.push(Elem(i as i32));
350
700
        }
351
352
1
        {
353
1
            let a = Owned::new(v).into_shared(&guard);
354
1
            unsafe {
355
1
                guard.defer_destroy(a);
356
1
            }
357
1
            guard.flush();
358
1
        }
359
360
3
        while DROPS.load(Ordering::Relaxed) < COUNT {
361
2
            guard.repin();
362
2
            collector.global.collect(&guard);
363
2
        }
364
1
        assert_eq!(DROPS.load(Ordering::Relaxed), COUNT);
365
1
    }
366
367
    #[test]
368
1
    fn destroy_array() {
crossbeam_epoch::collector::tests::destroy_array::{closure#0}
Line
Count
Source
368
1
    fn destroy_array() {
369
        const COUNT: usize = 100_000;
370
        static DESTROYS: AtomicUsize = AtomicUsize::new(0);
371
372
1
        let collector = Collector::new();
373
1
        let handle = collector.register();
374
375
        unsafe {
376
1
            let guard = &handle.pin();
377
1
378
1
            let mut v = Vec::with_capacity(COUNT);
379
100k
            for i in 0..COUNT {
380
100k
                v.push(i as i32);
381
100k
            }
382
383
1
            let ptr = v.as_mut_ptr() as usize;
384
1
            let len = v.len();
385
1
            guard.defer_unchecked(move || {
386
1
                drop(Vec::from_raw_parts(ptr as *const i32 as *mut i32, len, len));
387
1
                DESTROYS.fetch_add(len, Ordering::Relaxed);
388
1
            });
389
1
            guard.flush();
390
1
391
1
            mem::forget(v);
392
        }
393
394
3
        while DESTROYS.load(Ordering::Relaxed) < COUNT {
395
2
            let guard = &handle.pin();
396
2
            collector.global.collect(guard);
397
2
        }
398
1
        assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT);
399
1
    }
crossbeam_epoch::collector::tests::destroy_array
Line
Count
Source
368
1
    fn destroy_array() {
369
        const COUNT: usize = 100_000;
370
        static DESTROYS: AtomicUsize = AtomicUsize::new(0);
371
372
1
        let collector = Collector::new();
373
1
        let handle = collector.register();
374
375
        unsafe {
376
1
            let guard = &handle.pin();
377
1
378
1
            let mut v = Vec::with_capacity(COUNT);
379
100k
            for i in 0..COUNT {
380
100k
                v.push(i as i32);
381
100k
            }
382
383
1
            let ptr = v.as_mut_ptr() as usize;
384
1
            let len = v.len();
385
1
            guard.defer_unchecked(move || {
386
                drop(Vec::from_raw_parts(ptr as *const i32 as *mut i32, len, len));
387
                DESTROYS.fetch_add(len, Ordering::Relaxed);
388
1
            });
389
1
            guard.flush();
390
1
391
1
            mem::forget(v);
392
        }
393
394
3
        while DESTROYS.load(Ordering::Relaxed) < COUNT {
395
2
            let guard = &handle.pin();
396
2
            collector.global.collect(guard);
397
2
        }
398
1
        assert_eq!(DESTROYS.load(Ordering::Relaxed), COUNT);
399
1
    }
400
401
    #[test]
402
1
    fn stress() {
crossbeam_epoch::collector::tests::stress::{closure#0}
Line
Count
Source
402
1
    fn stress() {
403
        const THREADS: usize = 8;
404
        const COUNT: usize = 100_000;
405
        static DROPS: AtomicUsize = AtomicUsize::new(0);
406
407
        struct Elem(i32);
408
409
        impl Drop for Elem {
410
685k
            fn drop(&mut self) {
411
685k
                DROPS.fetch_add(1, Ordering::Relaxed);
412
685k
            }
413
        }
414
415
1
        let collector = Collector::new();
416
1
417
1
        thread::scope(|scope| {
418
9
            for 
_8
in 0..THREADS {
419
8
                scope.spawn(|_| {
420
8
                    let handle = collector.register();
421
722k
                    for 
_722k
in 0..COUNT {
422
722k
                        let guard = &handle.pin();
423
722k
                        unsafe {
424
722k
                            let a = Owned::new(Elem(7i32)).into_shared(guard);
425
722k
                            guard.defer_destroy(a);
426
722k
                        }
427
                    }
428
8
                });
429
8
            }
430
1
        })
431
1
        .unwrap();
432
1
433
1
        let handle = collector.register();
434
3
        while DROPS.load(Ordering::Relaxed) < COUNT * THREADS {
435
2
            let guard = &handle.pin();
436
2
            collector.global.collect(guard);
437
2
        }
438
1
        assert_eq!(DROPS.load(Ordering::Relaxed), COUNT * THREADS);
439
1
    }
crossbeam_epoch::collector::tests::stress
Line
Count
Source
402
1
    fn stress() {
403
        const THREADS: usize = 8;
404
        const COUNT: usize = 100_000;
405
        static DROPS: AtomicUsize = AtomicUsize::new(0);
406
407
        struct Elem(i32);
408
409
        impl Drop for Elem {
410
            fn drop(&mut self) {
411
                DROPS.fetch_add(1, Ordering::Relaxed);
412
            }
413
        }
414
415
1
        let collector = Collector::new();
416
1
417
1
        thread::scope(|scope| {
418
            for _ in 0..THREADS {
419
                scope.spawn(|_| {
420
                    let handle = collector.register();
421
                    for _ in 0..COUNT {
422
                        let guard = &handle.pin();
423
                        unsafe {
424
                            let a = Owned::new(Elem(7i32)).into_shared(guard);
425
                            guard.defer_destroy(a);
426
                        }
427
                    }
428
                });
429
            }
430
1
        })
431
1
        .unwrap();
432
1
433
1
        let handle = collector.register();
434
3
        while DROPS.load(Ordering::Relaxed) < COUNT * THREADS {
435
2
            let guard = &handle.pin();
436
2
            collector.global.collect(guard);
437
2
        }
438
1
        assert_eq!(DROPS.load(Ordering::Relaxed), COUNT * THREADS);
439
1
    }
440
}