Coverage Report

Created: 2025-11-24 07:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/crossbeam-epoch-0.9.18/src/sync/queue.rs
Line
Count
Source
1
//! Michael-Scott lock-free queue.
2
//!
3
//! Usable with any number of producers and consumers.
4
//!
5
//! Michael and Scott.  Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue
6
//! Algorithms.  PODC 1996.  <http://dl.acm.org/citation.cfm?id=248106>
7
//!
8
//! Simon Doherty, Lindsay Groves, Victor Luchangco, and Mark Moir. 2004b. Formal Verification of a
9
//! Practical Lock-Free Queue Algorithm. <https://doi.org/10.1007/978-3-540-30232-2_7>
10
11
use core::mem::MaybeUninit;
12
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release};
13
14
use crossbeam_utils::CachePadded;
15
16
use crate::{unprotected, Atomic, Guard, Owned, Shared};
17
18
// The representation here is a singly-linked list, with a sentinel node at the front. In general
19
// the `tail` pointer may lag behind the actual tail. Non-sentinel nodes are either all `Data` or
20
// all `Blocked` (requests for data from blocked threads).
21
#[derive(Debug)]
22
pub(crate) struct Queue<T> {
23
    head: CachePadded<Atomic<Node<T>>>,
24
    tail: CachePadded<Atomic<Node<T>>>,
25
}
26
27
struct Node<T> {
28
    /// The slot in which a value of type `T` can be stored.
29
    ///
30
    /// The type of `data` is `MaybeUninit<T>` because a `Node<T>` doesn't always contain a `T`.
31
    /// For example, the sentinel node in a queue never contains a value: its slot is always empty.
32
    /// Other nodes start their life with a push operation and contain a value until it gets popped
33
    /// out. After that such empty nodes get added to the collector for destruction.
34
    data: MaybeUninit<T>,
35
36
    next: Atomic<Node<T>>,
37
}
38
39
// Any particular `T` should never be accessed concurrently, so no need for `Sync`.
40
unsafe impl<T: Send> Sync for Queue<T> {}
41
unsafe impl<T: Send> Send for Queue<T> {}
42
43
impl<T> Queue<T> {
44
    /// Create a new, empty queue.
45
2
    pub(crate) fn new() -> Queue<T> {
46
2
        let q = Queue {
47
2
            head: CachePadded::new(Atomic::null()),
48
2
            tail: CachePadded::new(Atomic::null()),
49
2
        };
50
2
        let sentinel = Owned::new(Node {
51
2
            data: MaybeUninit::uninit(),
52
2
            next: Atomic::null(),
53
2
        });
54
        unsafe {
55
2
            let guard = unprotected();
56
2
            let sentinel = sentinel.into_shared(guard);
57
2
            q.head.store(sentinel, Relaxed);
58
2
            q.tail.store(sentinel, Relaxed);
59
2
            q
60
        }
61
2
    }
62
63
    /// Attempts to atomically place `n` into the `next` pointer of `onto`, and returns `true` on
64
    /// success. The queue's `tail` pointer may be updated.
65
    #[inline(always)]
66
100k
    fn push_internal(
67
100k
        &self,
68
100k
        onto: Shared<'_, Node<T>>,
69
100k
        new: Shared<'_, Node<T>>,
70
100k
        guard: &Guard,
71
100k
    ) -> bool {
72
        // is `onto` the actual tail?
73
100k
        let o = unsafe { onto.deref() };
74
100k
        let next = o.next.load(Acquire, guard);
75
100k
        if unsafe { next.as_ref().is_some() } {
76
            // if not, try to "help" by moving the tail pointer forward
77
23.5k
            let _ = self
78
23.5k
                .tail
79
23.5k
                .compare_exchange(onto, next, Release, Relaxed, guard);
80
23.5k
            false
81
        } else {
82
            // looks like the actual tail; attempt to link in `n`
83
77.4k
            let result = o
84
77.4k
                .next
85
77.4k
                .compare_exchange(Shared::null(), new, Release, Relaxed, guard)
86
77.4k
                .is_ok();
87
77.4k
            if result {
88
64.1k
                // try to move the tail pointer forward
89
64.1k
                let _ = self
90
64.1k
                    .tail
91
64.1k
                    .compare_exchange(onto, new, Release, Relaxed, guard);
92
64.1k
            }
93
77.4k
            result
94
        }
95
100k
    }
96
97
    /// Adds `t` to the back of the queue, possibly waking up threads blocked on `pop`.
98
64.1k
    pub(crate) fn push(&self, t: T, guard: &Guard) {
99
64.1k
        let new = Owned::new(Node {
100
64.1k
            data: MaybeUninit::new(t),
101
64.1k
            next: Atomic::null(),
102
64.1k
        });
103
64.1k
        let new = Owned::into_shared(new, guard);
104
105
        loop {
106
            // We push onto the tail, so we'll start optimistically by looking there first.
107
100k
            let tail = self.tail.load(Acquire, guard);
108
109
            // Attempt to push onto the `tail` snapshot; fails if `tail.next` has changed.
110
100k
            if self.push_internal(tail, new, guard) {
111
64.1k
                break;
112
36.8k
            }
113
        }
114
64.1k
    }
115
116
    /// Attempts to pop a data node. `Ok(None)` if queue is empty; `Err(())` if lost race to pop.
117
    #[inline(always)]
118
0
    fn pop_internal(&self, guard: &Guard) -> Result<Option<T>, ()> {
119
0
        let head = self.head.load(Acquire, guard);
120
0
        let h = unsafe { head.deref() };
121
0
        let next = h.next.load(Acquire, guard);
122
0
        match unsafe { next.as_ref() } {
123
0
            Some(n) => unsafe {
124
0
                self.head
125
0
                    .compare_exchange(head, next, Release, Relaxed, guard)
126
0
                    .map(|_| {
127
0
                        let tail = self.tail.load(Relaxed, guard);
128
                        // Advance the tail so that we don't retire a pointer to a reachable node.
129
0
                        if head == tail {
130
0
                            let _ = self
131
0
                                .tail
132
0
                                .compare_exchange(tail, next, Release, Relaxed, guard);
133
0
                        }
134
0
                        guard.defer_destroy(head);
135
0
                        Some(n.data.assume_init_read())
136
0
                    })
137
0
                    .map_err(|_| ())
138
            },
139
0
            None => Ok(None),
140
        }
141
0
    }
142
143
    /// Attempts to pop a data node, if the data satisfies the given condition. `Ok(None)` if queue
144
    /// is empty or the data does not satisfy the condition; `Err(())` if lost race to pop.
145
    #[inline(always)]
146
1.71M
    fn pop_if_internal<F>(&self, condition: F, guard: &Guard) -> Result<Option<T>, ()>
147
1.71M
    where
148
1.71M
        T: Sync,
149
1.71M
        F: Fn(&T) -> bool,
150
    {
151
1.71M
        let head = self.head.load(Acquire, guard);
152
1.71M
        let h = unsafe { head.deref() };
153
1.71M
        let next = h.next.load(Acquire, guard);
154
1.71M
        match unsafe { next.as_ref() } {
155
103k
            Some(n) if condition(unsafe { &*n.data.as_ptr() }) => unsafe {
156
86.8k
                self.head
157
86.8k
                    .compare_exchange(head, next, Release, Relaxed, guard)
158
86.8k
                    .map(|_| {
159
64.0k
                        let tail = self.tail.load(Relaxed, guard);
160
                        // Advance the tail so that we don't retire a pointer to a reachable node.
161
64.0k
                        if head == tail {
162
0
                            let _ = self
163
0
                                .tail
164
0
                                .compare_exchange(tail, next, Release, Relaxed, guard);
165
64.0k
                        }
166
64.0k
                        guard.defer_destroy(head);
167
64.0k
                        Some(n.data.assume_init_read())
168
64.0k
                    })
169
86.8k
                    .map_err(|_| ())
170
            },
171
1.63M
            None | Some(_) => Ok(None),
172
        }
173
1.71M
    }
174
175
    /// Attempts to dequeue from the front.
176
    ///
177
    /// Returns `None` if the queue is observed to be empty.
178
0
    pub(crate) fn try_pop(&self, guard: &Guard) -> Option<T> {
179
        loop {
180
0
            if let Ok(head) = self.pop_internal(guard) {
181
0
                return head;
182
0
            }
183
        }
184
0
    }
185
186
    /// Attempts to dequeue from the front, if the item satisfies the given condition.
187
    ///
188
    /// Returns `None` if the queue is observed to be empty, or the head does not satisfy the given
189
    /// condition.
190
1.69M
    pub(crate) fn try_pop_if<F>(&self, condition: F, guard: &Guard) -> Option<T>
191
1.69M
    where
192
1.69M
        T: Sync,
193
1.69M
        F: Fn(&T) -> bool,
194
    {
195
        loop {
196
1.71M
            if let Ok(head) = self.pop_if_internal(&condition, guard) {
197
1.69M
                return head;
198
22.8k
            }
199
        }
200
1.69M
    }
201
}
202
203
impl<T> Drop for Queue<T> {
204
0
    fn drop(&mut self) {
205
        unsafe {
206
0
            let guard = unprotected();
207
208
0
            while self.try_pop(guard).is_some() {}
209
210
            // Destroy the remaining sentinel node.
211
0
            let sentinel = self.head.load(Relaxed, guard);
212
0
            drop(sentinel.into_owned());
213
        }
214
0
    }
215
}
216
217
#[cfg(all(test, not(crossbeam_loom)))]
218
mod test {
219
    use super::*;
220
    use crate::pin;
221
    use crossbeam_utils::thread;
222
223
    struct Queue<T> {
224
        queue: super::Queue<T>,
225
    }
226
227
    impl<T> Queue<T> {
228
        pub(crate) fn new() -> Queue<T> {
229
            Queue {
230
                queue: super::Queue::new(),
231
            }
232
        }
233
234
        pub(crate) fn push(&self, t: T) {
235
            let guard = &pin();
236
            self.queue.push(t, guard);
237
        }
238
239
        pub(crate) fn is_empty(&self) -> bool {
240
            let guard = &pin();
241
            let head = self.queue.head.load(Acquire, guard);
242
            let h = unsafe { head.deref() };
243
            h.next.load(Acquire, guard).is_null()
244
        }
245
246
        pub(crate) fn try_pop(&self) -> Option<T> {
247
            let guard = &pin();
248
            self.queue.try_pop(guard)
249
        }
250
251
        pub(crate) fn pop(&self) -> T {
252
            loop {
253
                match self.try_pop() {
254
                    None => continue,
255
                    Some(t) => return t,
256
                }
257
            }
258
        }
259
    }
260
261
    #[cfg(miri)]
262
    const CONC_COUNT: i64 = 1000;
263
    #[cfg(not(miri))]
264
    const CONC_COUNT: i64 = 1000000;
265
266
    #[test]
267
    fn push_try_pop_1() {
268
        let q: Queue<i64> = Queue::new();
269
        assert!(q.is_empty());
270
        q.push(37);
271
        assert!(!q.is_empty());
272
        assert_eq!(q.try_pop(), Some(37));
273
        assert!(q.is_empty());
274
    }
275
276
    #[test]
277
    fn push_try_pop_2() {
278
        let q: Queue<i64> = Queue::new();
279
        assert!(q.is_empty());
280
        q.push(37);
281
        q.push(48);
282
        assert_eq!(q.try_pop(), Some(37));
283
        assert!(!q.is_empty());
284
        assert_eq!(q.try_pop(), Some(48));
285
        assert!(q.is_empty());
286
    }
287
288
    #[test]
289
    fn push_try_pop_many_seq() {
290
        let q: Queue<i64> = Queue::new();
291
        assert!(q.is_empty());
292
        for i in 0..200 {
293
            q.push(i)
294
        }
295
        assert!(!q.is_empty());
296
        for i in 0..200 {
297
            assert_eq!(q.try_pop(), Some(i));
298
        }
299
        assert!(q.is_empty());
300
    }
301
302
    #[test]
303
    fn push_pop_1() {
304
        let q: Queue<i64> = Queue::new();
305
        assert!(q.is_empty());
306
        q.push(37);
307
        assert!(!q.is_empty());
308
        assert_eq!(q.pop(), 37);
309
        assert!(q.is_empty());
310
    }
311
312
    #[test]
313
    fn push_pop_2() {
314
        let q: Queue<i64> = Queue::new();
315
        q.push(37);
316
        q.push(48);
317
        assert_eq!(q.pop(), 37);
318
        assert_eq!(q.pop(), 48);
319
    }
320
321
    #[test]
322
    fn push_pop_many_seq() {
323
        let q: Queue<i64> = Queue::new();
324
        assert!(q.is_empty());
325
        for i in 0..200 {
326
            q.push(i)
327
        }
328
        assert!(!q.is_empty());
329
        for i in 0..200 {
330
            assert_eq!(q.pop(), i);
331
        }
332
        assert!(q.is_empty());
333
    }
334
335
    #[test]
336
    fn push_try_pop_many_spsc() {
337
        let q: Queue<i64> = Queue::new();
338
        assert!(q.is_empty());
339
340
        thread::scope(|scope| {
341
            scope.spawn(|_| {
342
                let mut next = 0;
343
344
                while next < CONC_COUNT {
345
                    if let Some(elem) = q.try_pop() {
346
                        assert_eq!(elem, next);
347
                        next += 1;
348
                    }
349
                }
350
            });
351
352
            for i in 0..CONC_COUNT {
353
                q.push(i)
354
            }
355
        })
356
        .unwrap();
357
    }
358
359
    #[test]
360
    fn push_try_pop_many_spmc() {
361
        fn recv(_t: i32, q: &Queue<i64>) {
362
            let mut cur = -1;
363
            for _i in 0..CONC_COUNT {
364
                if let Some(elem) = q.try_pop() {
365
                    assert!(elem > cur);
366
                    cur = elem;
367
368
                    if cur == CONC_COUNT - 1 {
369
                        break;
370
                    }
371
                }
372
            }
373
        }
374
375
        let q: Queue<i64> = Queue::new();
376
        assert!(q.is_empty());
377
        thread::scope(|scope| {
378
            for i in 0..3 {
379
                let q = &q;
380
                scope.spawn(move |_| recv(i, q));
381
            }
382
383
            scope.spawn(|_| {
384
                for i in 0..CONC_COUNT {
385
                    q.push(i);
386
                }
387
            });
388
        })
389
        .unwrap();
390
    }
391
392
    #[test]
393
    fn push_try_pop_many_mpmc() {
394
        enum LR {
395
            Left(i64),
396
            Right(i64),
397
        }
398
399
        let q: Queue<LR> = Queue::new();
400
        assert!(q.is_empty());
401
402
        thread::scope(|scope| {
403
            for _t in 0..2 {
404
                scope.spawn(|_| {
405
                    for i in CONC_COUNT - 1..CONC_COUNT {
406
                        q.push(LR::Left(i))
407
                    }
408
                });
409
                scope.spawn(|_| {
410
                    for i in CONC_COUNT - 1..CONC_COUNT {
411
                        q.push(LR::Right(i))
412
                    }
413
                });
414
                scope.spawn(|_| {
415
                    let mut vl = vec![];
416
                    let mut vr = vec![];
417
                    for _i in 0..CONC_COUNT {
418
                        match q.try_pop() {
419
                            Some(LR::Left(x)) => vl.push(x),
420
                            Some(LR::Right(x)) => vr.push(x),
421
                            _ => {}
422
                        }
423
                    }
424
425
                    let mut vl2 = vl.clone();
426
                    let mut vr2 = vr.clone();
427
                    vl2.sort_unstable();
428
                    vr2.sort_unstable();
429
430
                    assert_eq!(vl, vl2);
431
                    assert_eq!(vr, vr2);
432
                });
433
            }
434
        })
435
        .unwrap();
436
    }
437
438
    #[test]
439
    fn push_pop_many_spsc() {
440
        let q: Queue<i64> = Queue::new();
441
442
        thread::scope(|scope| {
443
            scope.spawn(|_| {
444
                let mut next = 0;
445
                while next < CONC_COUNT {
446
                    assert_eq!(q.pop(), next);
447
                    next += 1;
448
                }
449
            });
450
451
            for i in 0..CONC_COUNT {
452
                q.push(i)
453
            }
454
        })
455
        .unwrap();
456
        assert!(q.is_empty());
457
    }
458
459
    #[test]
460
    fn is_empty_dont_pop() {
461
        let q: Queue<i64> = Queue::new();
462
        q.push(20);
463
        q.push(20);
464
        assert!(!q.is_empty());
465
        assert!(!q.is_empty());
466
        assert!(q.try_pop().is_some());
467
    }
468
}