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}