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}