Skip to main content

crossbeam_queue/
seg_queue.rs

1use alloc::alloc::{alloc_zeroed, handle_alloc_error, Layout};
2use alloc::boxed::Box;
3use core::cell::UnsafeCell;
4use core::fmt;
5use core::marker::PhantomData;
6use core::mem::MaybeUninit;
7use core::panic::{RefUnwindSafe, UnwindSafe};
8use core::ptr;
9use core::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering};
10
11use crossbeam_utils::{Backoff, CachePadded};
12
13// Ideally, we want to always use AtomicU64, but since it is not available on all platforms,
14// we only use it when it is available for now.
15// TODO: On platforms where AtomicU64 is unavailable, we may want to use AtomicCell instead of
16// AtomicUsize. (https://github.com/crossbeam-rs/crossbeam/issues/433)
17#[cfg(target_has_atomic = "64")]
18type AtomicIndex = core::sync::atomic::AtomicU64;
19#[cfg(target_has_atomic = "64")]
20type Index = u64;
21#[cfg(not(target_has_atomic = "64"))]
22type AtomicIndex = core::sync::atomic::AtomicUsize;
23#[cfg(not(target_has_atomic = "64"))]
24type Index = usize;
25
26// Bits indicating the state of a slot:
27// * If a value has been written into the slot, `WRITE` is set.
28// * If a value has been read from the slot, `READ` is set.
29// * If the block is being destroyed, `DESTROY` is set.
30const WRITE: usize = 1;
31const READ: usize = 2;
32const DESTROY: usize = 4;
33
34// Each block covers one "lap" of indices.
35const LAP: Index = 32;
36// The maximum number of values a block can hold.
37const BLOCK_CAP: usize = LAP as usize - 1;
38// How many lower bits are reserved for metadata.
39const SHIFT: usize = 1;
40// Indicates that the block is not the last one.
41const HAS_NEXT: Index = 1;
42
43/// A slot in a block.
44struct Slot<T> {
45    /// The value.
46    value: UnsafeCell<MaybeUninit<T>>,
47
48    /// The state of the slot.
49    state: AtomicUsize,
50}
51
52impl<T> Slot<T> {
53    /// Waits until a value is written into the slot.
54    fn wait_write(&self) {
55        let backoff = Backoff::new();
56        while self.state.load(Ordering::Acquire) & WRITE == 0 {
57            backoff.snooze();
58        }
59    }
60}
61
62/// A block in a linked list.
63///
64/// Each block in the list can hold up to `BLOCK_CAP` values.
65struct Block<T> {
66    /// The next block in the linked list.
67    next: AtomicPtr<Block<T>>,
68
69    /// Slots for values.
70    slots: [Slot<T>; BLOCK_CAP],
71}
72
73impl<T> Block<T> {
74    const LAYOUT: Layout = {
75        let layout = Layout::new::<Self>();
76        assert!(
77            layout.size() != 0,
78            "Block should never be zero-sized, as it has an AtomicPtr field"
79        );
80        layout
81    };
82
83    /// Creates an empty block.
84    fn new() -> Box<Self> {
85        // SAFETY: layout is not zero-sized
86        let ptr = unsafe { alloc_zeroed(Self::LAYOUT) };
87        // Handle allocation failure
88        if ptr.is_null() {
89            handle_alloc_error(Self::LAYOUT)
90        }
91        // SAFETY: This is safe because:
92        //  [1] `Block::next` (AtomicPtr) may be safely zero initialized.
93        //  [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4].
94        //  [3] `Slot::value` (UnsafeCell) may be safely zero initialized because it
95        //       holds a MaybeUninit.
96        //  [4] `Slot::state` (AtomicUsize) may be safely zero initialized.
97        // TODO: unsafe { Box::new_zeroed().assume_init() }
98        unsafe { Box::from_raw(ptr.cast()) }
99    }
100
101    /// Waits until the next pointer is set.
102    fn wait_next(&self) -> *mut Block<T> {
103        let backoff = Backoff::new();
104        loop {
105            let next = self.next.load(Ordering::Acquire);
106            if !next.is_null() {
107                return next;
108            }
109            backoff.snooze();
110        }
111    }
112
113    /// Sets the `DESTROY` bit in slots starting from `start` and destroys the block.
114    unsafe fn destroy(this: *mut Block<T>, start: usize) {
115        // It is not necessary to set the `DESTROY` bit in the last slot because that slot has
116        // begun destruction of the block.
117        for i in start..BLOCK_CAP - 1 {
118            let slot = (*this).slots.get_unchecked(i);
119
120            // Mark the `DESTROY` bit if a thread is still using the slot.
121            if slot.state.load(Ordering::Acquire) & READ == 0
122                && slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0
123            {
124                // If a thread is still using the slot, it will continue destruction of the block.
125                return;
126            }
127        }
128        // No thread is using the block, now it is safe to destroy it.
129        drop(Box::from_raw(this));
130    }
131
132    /// Destroys the block. Only safe to call with exclusive access, when no other thread is using it.
133    unsafe fn destroy_mut(this: *mut Self) {
134        drop(unsafe { Box::from_raw(this) });
135    }
136}
137
138/// A position in a queue.
139struct Position<T> {
140    /// The index in the queue.
141    index: AtomicIndex,
142
143    /// The block in the linked list.
144    block: AtomicPtr<Block<T>>,
145}
146
147/// An unbounded multi-producer multi-consumer queue.
148///
149/// This queue is implemented as a linked list of segments, where each segment is a small buffer
150/// that can hold a handful of elements. There is no limit to how many elements can be in the queue
151/// at a time. However, since segments need to be dynamically allocated as elements get pushed,
152/// this queue is somewhat slower than [`ArrayQueue`].
153///
154/// [`ArrayQueue`]: super::ArrayQueue
155///
156/// # Examples
157///
158/// ```
159/// use crossbeam_queue::SegQueue;
160///
161/// let q = SegQueue::new();
162///
163/// q.push('a');
164/// q.push('b');
165///
166/// assert_eq!(q.pop(), Some('a'));
167/// assert_eq!(q.pop(), Some('b'));
168/// assert!(q.pop().is_none());
169/// ```
170pub struct SegQueue<T> {
171    /// The head of the queue.
172    head: CachePadded<Position<T>>,
173
174    /// The tail of the queue.
175    tail: CachePadded<Position<T>>,
176
177    /// Indicates that dropping a `SegQueue<T>` may drop values of type `T`.
178    _marker: PhantomData<T>,
179}
180
181unsafe impl<T: Send> Send for SegQueue<T> {}
182unsafe impl<T: Send> Sync for SegQueue<T> {}
183
184impl<T> UnwindSafe for SegQueue<T> {}
185impl<T> RefUnwindSafe for SegQueue<T> {}
186
187impl<T> SegQueue<T> {
188    /// Creates a new unbounded queue.
189    ///
190    /// # Examples
191    ///
192    /// ```
193    /// use crossbeam_queue::SegQueue;
194    ///
195    /// let q = SegQueue::<i32>::new();
196    /// ```
197    pub const fn new() -> SegQueue<T> {
198        SegQueue {
199            head: CachePadded::new(Position {
200                block: AtomicPtr::new(ptr::null_mut()),
201                index: AtomicIndex::new(0),
202            }),
203            tail: CachePadded::new(Position {
204                block: AtomicPtr::new(ptr::null_mut()),
205                index: AtomicIndex::new(0),
206            }),
207            _marker: PhantomData,
208        }
209    }
210
211    /// Pushes back an element to the tail.
212    ///
213    /// # Examples
214    ///
215    /// ```
216    /// use crossbeam_queue::SegQueue;
217    ///
218    /// let q = SegQueue::new();
219    ///
220    /// q.push(10);
221    /// q.push(20);
222    /// ```
223    pub fn push(&self, value: T) {
224        let backoff = Backoff::new();
225        let mut tail = self.tail.index.load(Ordering::Acquire);
226        let mut block = self.tail.block.load(Ordering::Acquire);
227        let mut next_block = None;
228
229        loop {
230            // Calculate the offset of the index into the block.
231            let offset = ((tail >> SHIFT) % LAP) as usize;
232
233            // If we reached the end of the block, wait until the next one is installed.
234            if offset == BLOCK_CAP {
235                backoff.snooze();
236                tail = self.tail.index.load(Ordering::Acquire);
237                block = self.tail.block.load(Ordering::Acquire);
238                continue;
239            }
240
241            // If we're going to have to install the next block, allocate it in advance in order to
242            // make the wait for other threads as short as possible.
243            if offset + 1 == BLOCK_CAP && next_block.is_none() {
244                next_block = Some(Block::<T>::new());
245            }
246
247            // If this is the first push operation, we need to allocate the first block.
248            if block.is_null() {
249                let new = Box::into_raw(Block::<T>::new());
250
251                if self
252                    .tail
253                    .block
254                    .compare_exchange(block, new, Ordering::Release, Ordering::Relaxed)
255                    .is_ok()
256                {
257                    self.head.block.store(new, Ordering::Release);
258                    block = new;
259                } else {
260                    next_block = unsafe { Some(Box::from_raw(new)) };
261                    tail = self.tail.index.load(Ordering::Acquire);
262                    block = self.tail.block.load(Ordering::Acquire);
263                    continue;
264                }
265            }
266
267            let new_tail = tail + (1 << SHIFT);
268
269            // Try advancing the tail forward.
270            match self.tail.index.compare_exchange_weak(
271                tail,
272                new_tail,
273                Ordering::SeqCst,
274                Ordering::Acquire,
275            ) {
276                Ok(_) => unsafe {
277                    // If we've reached the end of the block, install the next one.
278                    if offset + 1 == BLOCK_CAP {
279                        let next_block = Box::into_raw(next_block.unwrap());
280                        let next_index = new_tail.wrapping_add(1 << SHIFT);
281
282                        self.tail.block.store(next_block, Ordering::Release);
283                        self.tail.index.store(next_index, Ordering::Release);
284                        (*block).next.store(next_block, Ordering::Release);
285                    }
286
287                    // Write the value into the slot.
288                    let slot = (*block).slots.get_unchecked(offset);
289                    slot.value.get().write(MaybeUninit::new(value));
290                    slot.state.fetch_or(WRITE, Ordering::Release);
291
292                    return;
293                },
294                Err(t) => {
295                    tail = t;
296                    block = self.tail.block.load(Ordering::Acquire);
297                    backoff.spin();
298                }
299            }
300        }
301    }
302
303    /// Pushes an element to the queue with exclusive mutable access.
304    ///
305    /// Avoids atomic operations and synchronization, assuming
306    /// no other threads access the queue concurrently.
307    ///
308    /// # Examples
309    ///
310    /// ```
311    /// use crossbeam_queue::SegQueue;
312    ///
313    /// let mut q = SegQueue::new();
314    ///
315    /// q.push_mut(10);
316    /// q.push_mut(20);
317    /// ```
318    pub fn push_mut(&mut self, value: T) {
319        let tail = *self.tail.index.get_mut();
320        let mut block = *self.tail.block.get_mut();
321
322        // Calculate the offset of the index into the block.
323        let offset = ((tail >> SHIFT) % LAP) as usize;
324
325        // If this is the first push operation, we need to allocate the first block.
326        if block.is_null() {
327            let new = Box::into_raw(Block::<T>::new());
328            *self.head.block.get_mut() = new;
329            *self.tail.block.get_mut() = new;
330
331            block = new;
332        }
333
334        let new_tail = tail + (1 << SHIFT);
335
336        *self.tail.index.get_mut() = new_tail;
337
338        unsafe {
339            // If we've reached the end of the block, install the next one.
340            if offset + 1 == BLOCK_CAP {
341                let next_block = Box::into_raw(Block::<T>::new());
342                let next_index = new_tail.wrapping_add(1 << SHIFT);
343
344                *self.tail.block.get_mut() = next_block;
345                *self.tail.index.get_mut() = next_index;
346                *(*block).next.get_mut() = next_block;
347            }
348
349            // Write the value into the slot.
350            let slot = (*block).slots.get_unchecked(offset);
351            slot.value.get().write(MaybeUninit::new(value));
352            *(*block).slots.get_unchecked_mut(offset).state.get_mut() |= WRITE;
353        }
354    }
355
356    /// Pops the head element from the queue.
357    ///
358    /// If the queue is empty, `None` is returned.
359    ///
360    /// # Examples
361    ///
362    /// ```
363    /// use crossbeam_queue::SegQueue;
364    ///
365    /// let q = SegQueue::new();
366    ///
367    /// q.push(10);
368    /// q.push(20);
369    /// assert_eq!(q.pop(), Some(10));
370    /// assert_eq!(q.pop(), Some(20));
371    /// assert!(q.pop().is_none());
372    /// ```
373    pub fn pop(&self) -> Option<T> {
374        let backoff = Backoff::new();
375        let mut head = self.head.index.load(Ordering::Acquire);
376        let mut block = self.head.block.load(Ordering::Acquire);
377
378        loop {
379            // Calculate the offset of the index into the block.
380            let offset = ((head >> SHIFT) % LAP) as usize;
381
382            // If we reached the end of the block, wait until the next one is installed.
383            if offset == BLOCK_CAP {
384                backoff.snooze();
385                head = self.head.index.load(Ordering::Acquire);
386                block = self.head.block.load(Ordering::Acquire);
387                continue;
388            }
389
390            let mut new_head = head + (1 << SHIFT);
391
392            if new_head & HAS_NEXT == 0 {
393                atomic::fence(Ordering::SeqCst);
394                let tail = self.tail.index.load(Ordering::Relaxed);
395
396                // If the tail equals the head, that means the queue is empty.
397                if head >> SHIFT == tail >> SHIFT {
398                    return None;
399                }
400
401                // If head and tail are not in the same block, set `HAS_NEXT` in head.
402                if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP {
403                    new_head |= HAS_NEXT;
404                }
405            }
406
407            // The block can be null here only if the first push operation is in progress. In that
408            // case, just wait until it gets initialized.
409            if block.is_null() {
410                backoff.snooze();
411                head = self.head.index.load(Ordering::Acquire);
412                block = self.head.block.load(Ordering::Acquire);
413                continue;
414            }
415
416            // Try moving the head index forward.
417            match self.head.index.compare_exchange_weak(
418                head,
419                new_head,
420                Ordering::SeqCst,
421                Ordering::Acquire,
422            ) {
423                Ok(_) => unsafe {
424                    // If we've reached the end of the block, move to the next one.
425                    if offset + 1 == BLOCK_CAP {
426                        let next = (*block).wait_next();
427                        let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT);
428                        if !(*next).next.load(Ordering::Relaxed).is_null() {
429                            next_index |= HAS_NEXT;
430                        }
431
432                        self.head.block.store(next, Ordering::Release);
433                        self.head.index.store(next_index, Ordering::Release);
434                    }
435
436                    // Read the value.
437                    let slot = (*block).slots.get_unchecked(offset);
438                    slot.wait_write();
439                    let value = slot.value.get().read().assume_init();
440
441                    // Destroy the block if we've reached the end, or if another thread wanted to
442                    // destroy but couldn't because we were busy reading from the slot.
443                    if offset + 1 == BLOCK_CAP {
444                        Block::destroy(block, 0);
445                    } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 {
446                        Block::destroy(block, offset + 1);
447                    }
448
449                    return Some(value);
450                },
451                Err(h) => {
452                    head = h;
453                    block = self.head.block.load(Ordering::Acquire);
454                    backoff.spin();
455                }
456            }
457        }
458    }
459
460    /// Pops the head element from the queue using an exclusive reference.
461    ///
462    /// Avoids atomic operations and synchronization, assuming
463    /// no other threads access the queue concurrently.
464    ///
465    /// If the queue is empty, `None` is returned.
466    ///
467    /// # Examples
468    ///
469    /// ```
470    /// use crossbeam_queue::SegQueue;
471    ///
472    /// let mut q = SegQueue::new();
473    ///
474    /// q.push(10);
475    /// q.push(20);
476    /// assert_eq!(q.pop_mut(), Some(10));
477    /// assert_eq!(q.pop_mut(), Some(20));
478    /// assert!(q.pop_mut().is_none());
479    /// ```
480    pub fn pop_mut(&mut self) -> Option<T> {
481        let head = *self.head.index.get_mut();
482        let block = *self.head.block.get_mut();
483
484        // Calculate the offset of the index into the block.
485        let offset = ((head >> SHIFT) % LAP) as usize;
486
487        let mut new_head = head + (1 << SHIFT);
488
489        if new_head & HAS_NEXT == 0 {
490            let tail = *self.tail.index.get_mut();
491
492            // If the tail equals the head, that means the queue is empty.
493            if head >> SHIFT == tail >> SHIFT {
494                return None;
495            }
496
497            // If head and tail are not in the same block, set `HAS_NEXT` in head.
498            if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP {
499                new_head |= HAS_NEXT;
500            }
501        }
502
503        *self.head.index.get_mut() = new_head;
504
505        unsafe {
506            // If we've reached the end of the block, move to the next one.
507            if offset + 1 == BLOCK_CAP {
508                let next = *(*block).next.get_mut();
509                let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT);
510                if !(*next).next.get_mut().is_null() {
511                    next_index |= HAS_NEXT;
512                }
513
514                *self.head.block.get_mut() = next;
515                *self.head.index.get_mut() = next_index;
516            }
517
518            // Read the value.
519            let slot = (*block).slots.get_unchecked(offset);
520            let value = slot.value.get().read().assume_init();
521
522            // Destroy the block if we've reached the end
523            if offset + 1 == BLOCK_CAP {
524                Block::destroy_mut(block);
525            } else {
526                let state = *(*block).slots.get_unchecked_mut(offset).state.get_mut();
527                *(*block).slots.get_unchecked_mut(offset).state.get_mut() = state | READ;
528                if state & DESTROY != 0 {
529                    Block::destroy(block, offset + 1);
530                }
531            }
532
533            Some(value)
534        }
535    }
536
537    /// Returns `true` if the queue is empty.
538    ///
539    /// # Examples
540    ///
541    /// ```
542    /// use crossbeam_queue::SegQueue;
543    ///
544    /// let q = SegQueue::new();
545    ///
546    /// assert!(q.is_empty());
547    /// q.push(1);
548    /// assert!(!q.is_empty());
549    /// ```
550    pub fn is_empty(&self) -> bool {
551        let head = self.head.index.load(Ordering::SeqCst);
552        let tail = self.tail.index.load(Ordering::SeqCst);
553        head >> SHIFT == tail >> SHIFT
554    }
555
556    /// Returns the number of elements in the queue.
557    ///
558    /// # Examples
559    ///
560    /// ```
561    /// use crossbeam_queue::SegQueue;
562    ///
563    /// let q = SegQueue::new();
564    /// assert_eq!(q.len(), 0);
565    ///
566    /// q.push(10);
567    /// assert_eq!(q.len(), 1);
568    ///
569    /// q.push(20);
570    /// assert_eq!(q.len(), 2);
571    /// ```
572    pub fn len(&self) -> usize {
573        loop {
574            // Load the tail index, then load the head index.
575            let mut tail = self.tail.index.load(Ordering::SeqCst);
576            let mut head = self.head.index.load(Ordering::SeqCst);
577
578            // If the tail index didn't change, we've got consistent indices to work with.
579            if self.tail.index.load(Ordering::SeqCst) == tail {
580                // Erase the lower bits.
581                tail &= !((1 << SHIFT) - 1);
582                head &= !((1 << SHIFT) - 1);
583
584                // Fix up indices if they fall onto block ends.
585                if (tail >> SHIFT) & (LAP - 1) == LAP - 1 {
586                    tail = tail.wrapping_add(1 << SHIFT);
587                }
588                if (head >> SHIFT) & (LAP - 1) == LAP - 1 {
589                    head = head.wrapping_add(1 << SHIFT);
590                }
591
592                // Rotate indices so that head falls into the first block.
593                let lap = (head >> SHIFT) / LAP;
594                tail = tail.wrapping_sub((lap * LAP) << SHIFT);
595                head = head.wrapping_sub((lap * LAP) << SHIFT);
596
597                // Remove the lower bits.
598                tail >>= SHIFT;
599                head >>= SHIFT;
600
601                // Return the difference minus the number of blocks between tail and head.
602                return (tail - head - tail / LAP) as usize;
603            }
604        }
605    }
606}
607
608impl<T> Drop for SegQueue<T> {
609    fn drop(&mut self) {
610        let mut head = *self.head.index.get_mut();
611        let mut tail = *self.tail.index.get_mut();
612        let mut block = *self.head.block.get_mut();
613
614        // Erase the lower bits.
615        head &= !((1 << SHIFT) - 1);
616        tail &= !((1 << SHIFT) - 1);
617
618        unsafe {
619            // Drop all values between `head` and `tail` and deallocate the heap-allocated blocks.
620            while head != tail {
621                let offset = ((head >> SHIFT) % LAP) as usize;
622
623                if offset < BLOCK_CAP {
624                    // Drop the value in the slot.
625                    let slot = (*block).slots.get_unchecked(offset);
626                    (*slot.value.get()).assume_init_drop();
627                } else {
628                    // Deallocate the block and move to the next one.
629                    let next = *(*block).next.get_mut();
630                    drop(Box::from_raw(block));
631                    block = next;
632                }
633
634                head = head.wrapping_add(1 << SHIFT);
635            }
636
637            // Deallocate the last remaining block.
638            if !block.is_null() {
639                drop(Box::from_raw(block));
640            }
641        }
642    }
643}
644
645impl<T> fmt::Debug for SegQueue<T> {
646    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
647        f.pad("SegQueue { .. }")
648    }
649}
650
651impl<T> Default for SegQueue<T> {
652    fn default() -> SegQueue<T> {
653        SegQueue::new()
654    }
655}
656
657impl<T> IntoIterator for SegQueue<T> {
658    type Item = T;
659
660    type IntoIter = IntoIter<T>;
661
662    fn into_iter(self) -> Self::IntoIter {
663        IntoIter { value: self }
664    }
665}
666
667#[derive(Debug)]
668pub struct IntoIter<T> {
669    value: SegQueue<T>,
670}
671
672impl<T> Iterator for IntoIter<T> {
673    type Item = T;
674
675    fn next(&mut self) -> Option<Self::Item> {
676        let value = &mut self.value;
677        let head = *value.head.index.get_mut();
678        let tail = *value.tail.index.get_mut();
679        if head >> SHIFT == tail >> SHIFT {
680            None
681        } else {
682            let block = *value.head.block.get_mut();
683            let offset = ((head >> SHIFT) % LAP) as usize;
684
685            // SAFETY: We have mutable access to this, so we can read without
686            // worrying about concurrency. Furthermore, we know this is
687            // initialized because it is the value pointed at by `value.head`
688            // and this is a non-empty queue.
689            let item = unsafe {
690                let slot = (*block).slots.get_unchecked(offset);
691                slot.value.get().read().assume_init()
692            };
693            if offset + 1 == BLOCK_CAP {
694                // Deallocate the block and move to the next one.
695                // SAFETY: The block is initialized because we've been reading
696                // from it this entire time. We can drop it b/c everything has
697                // been read out of it, so nothing is pointing to it anymore.
698                unsafe {
699                    let next = *(*block).next.get_mut();
700                    drop(Box::from_raw(block));
701                    *value.head.block.get_mut() = next;
702                }
703                // The last value in a block is empty, so skip it
704                *value.head.index.get_mut() = head.wrapping_add(2 << SHIFT);
705                // Double-check that we're pointing to the first item in a block.
706                debug_assert_eq!((*value.head.index.get_mut() >> SHIFT) % LAP, 0);
707            } else {
708                *value.head.index.get_mut() = head.wrapping_add(1 << SHIFT);
709            }
710            Some(item)
711        }
712    }
713}