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