crossbeam_deque/deque.rs
1use std::alloc::{alloc_zeroed, handle_alloc_error, Layout};
2use std::boxed::Box;
3use std::cell::{Cell, UnsafeCell};
4use std::cmp;
5use std::fmt;
6use std::marker::PhantomData;
7use std::mem::{self, MaybeUninit};
8use std::ptr;
9use std::sync::atomic::{self, AtomicIsize, AtomicPtr, AtomicUsize, Ordering};
10use std::sync::Arc;
11
12use crossbeam_epoch::{self as epoch, Atomic, Owned};
13use crossbeam_utils::{Backoff, CachePadded};
14
15// Minimum buffer capacity.
16const MIN_CAP: usize = 64;
17// Maximum number of tasks that can be stolen in `steal_batch()` and `steal_batch_and_pop()`.
18const MAX_BATCH: usize = 32;
19// If a buffer of at least this size is retired, thread-local garbage is flushed so that it gets
20// deallocated as soon as possible.
21const FLUSH_THRESHOLD_BYTES: usize = 1 << 10;
22
23/// A buffer that holds tasks in a worker queue.
24///
25/// This is just a pointer to the buffer and its length - dropping an instance of this struct will
26/// *not* deallocate the buffer.
27struct Buffer<T> {
28 /// Pointer to the allocated memory.
29 ptr: *mut T,
30
31 /// Capacity of the buffer. Always a power of two.
32 cap: usize,
33}
34
35unsafe impl<T> Send for Buffer<T> {}
36
37impl<T> Buffer<T> {
38 /// Allocates a new buffer with the specified capacity.
39 fn alloc(cap: usize) -> Buffer<T> {
40 debug_assert_eq!(cap, cap.next_power_of_two());
41
42 let ptr = Box::into_raw(
43 (0..cap)
44 .map(|_| MaybeUninit::<T>::uninit())
45 .collect::<Box<[_]>>(),
46 )
47 .cast::<T>();
48
49 Buffer { ptr, cap }
50 }
51
52 /// Deallocates the buffer.
53 unsafe fn dealloc(self) {
54 drop(Box::from_raw(ptr::slice_from_raw_parts_mut(
55 self.ptr.cast::<MaybeUninit<T>>(),
56 self.cap,
57 )));
58 }
59
60 /// Returns a pointer to the task at the specified `index`.
61 unsafe fn at(&self, index: isize) -> *mut T {
62 // `self.cap` is always a power of two.
63 // We do all the loads at `MaybeUninit` because we might realize, after loading, that we
64 // don't actually have the right to access this memory.
65 self.ptr.offset(index & (self.cap - 1) as isize)
66 }
67
68 /// Writes `task` into the specified `index`.
69 ///
70 /// This method might be concurrently called with another `read` at the same index, which is
71 /// technically speaking a data race and therefore UB. We should use an atomic store here, but
72 /// that would be more expensive and difficult to implement generically for all types `T`.
73 /// Hence, as a hack, we use a volatile write instead.
74 unsafe fn write(&self, index: isize, task: MaybeUninit<T>) {
75 ptr::write_volatile(self.at(index).cast::<MaybeUninit<T>>(), task)
76 }
77
78 /// Reads a task from the specified `index`.
79 ///
80 /// This method might be concurrently called with another `write` at the same index, which is
81 /// technically speaking a data race and therefore UB. We should use an atomic load here, but
82 /// that would be more expensive and difficult to implement generically for all types `T`.
83 /// Hence, as a hack, we use a volatile load instead.
84 unsafe fn read(&self, index: isize) -> MaybeUninit<T> {
85 ptr::read_volatile(self.at(index).cast::<MaybeUninit<T>>())
86 }
87}
88
89impl<T> Clone for Buffer<T> {
90 fn clone(&self) -> Buffer<T> {
91 *self
92 }
93}
94
95impl<T> Copy for Buffer<T> {}
96
97/// Internal queue data shared between the worker and stealers.
98///
99/// The implementation is based on the following work:
100///
101/// 1. [Chase and Lev. Dynamic circular work-stealing deque. SPAA 2005.][chase-lev]
102/// 2. [Le, Pop, Cohen, and Nardelli. Correct and efficient work-stealing for weak memory models.
103/// PPoPP 2013.][weak-mem]
104/// 3. [Norris and Demsky. CDSchecker: checking concurrent data structures written with C/C++
105/// atomics. OOPSLA 2013.][checker]
106///
107/// [chase-lev]: https://dl.acm.org/citation.cfm?id=1073974
108/// [weak-mem]: https://dl.acm.org/citation.cfm?id=2442524
109/// [checker]: https://dl.acm.org/citation.cfm?id=2509514
110struct Inner<T> {
111 /// The front index.
112 front: AtomicIsize,
113
114 /// The back index.
115 back: AtomicIsize,
116
117 /// The underlying buffer.
118 buffer: CachePadded<Atomic<Buffer<T>>>,
119}
120
121impl<T> Drop for Inner<T> {
122 fn drop(&mut self) {
123 // Load the back index, front index, and buffer.
124 let b = *self.back.get_mut();
125 let f = *self.front.get_mut();
126
127 unsafe {
128 let buffer = self.buffer.load(Ordering::Relaxed, epoch::unprotected());
129
130 // Go through the buffer from front to back and drop all tasks in the queue.
131 let mut i = f;
132 while i != b {
133 buffer.deref().at(i).drop_in_place();
134 i = i.wrapping_add(1);
135 }
136
137 // Free the memory allocated by the buffer.
138 buffer.into_owned().into_box().dealloc();
139 }
140 }
141}
142
143/// Worker queue flavor: FIFO or LIFO.
144#[derive(Clone, Copy, Debug, Eq, PartialEq)]
145enum Flavor {
146 /// The first-in first-out flavor.
147 Fifo,
148
149 /// The last-in first-out flavor.
150 Lifo,
151}
152
153/// A worker queue.
154///
155/// This is a FIFO or LIFO queue that is owned by a single thread, but other threads may steal
156/// tasks from it. Task schedulers typically create a single worker queue per thread.
157///
158/// # Examples
159///
160/// A FIFO worker:
161///
162/// ```
163/// use crossbeam_deque::{Steal, Worker};
164///
165/// let w = Worker::new_fifo();
166/// let s = w.stealer();
167///
168/// w.push(1);
169/// w.push(2);
170/// w.push(3);
171///
172/// assert_eq!(s.steal(), Steal::Success(1));
173/// assert_eq!(w.pop(), Some(2));
174/// assert_eq!(w.pop(), Some(3));
175/// ```
176///
177/// A LIFO worker:
178///
179/// ```
180/// use crossbeam_deque::{Steal, Worker};
181///
182/// let w = Worker::new_lifo();
183/// let s = w.stealer();
184///
185/// w.push(1);
186/// w.push(2);
187/// w.push(3);
188///
189/// assert_eq!(s.steal(), Steal::Success(1));
190/// assert_eq!(w.pop(), Some(3));
191/// assert_eq!(w.pop(), Some(2));
192/// ```
193pub struct Worker<T> {
194 /// A reference to the inner representation of the queue.
195 inner: Arc<CachePadded<Inner<T>>>,
196
197 /// A copy of `inner.buffer` for quick access.
198 buffer: Cell<Buffer<T>>,
199
200 /// The flavor of the queue.
201 flavor: Flavor,
202
203 /// Indicates that the worker cannot be shared among threads.
204 _marker: PhantomData<*mut ()>, // !Send + !Sync
205}
206
207unsafe impl<T: Send> Send for Worker<T> {}
208
209impl<T> Worker<T> {
210 /// Creates a FIFO worker queue.
211 ///
212 /// Tasks are pushed and popped from opposite ends.
213 ///
214 /// # Examples
215 ///
216 /// ```
217 /// use crossbeam_deque::Worker;
218 ///
219 /// let w = Worker::<i32>::new_fifo();
220 /// ```
221 pub fn new_fifo() -> Worker<T> {
222 let buffer = Buffer::alloc(MIN_CAP);
223
224 let inner = Arc::new(CachePadded::new(Inner {
225 front: AtomicIsize::new(0),
226 back: AtomicIsize::new(0),
227 buffer: CachePadded::new(Atomic::new(buffer)),
228 }));
229
230 Worker {
231 inner,
232 buffer: Cell::new(buffer),
233 flavor: Flavor::Fifo,
234 _marker: PhantomData,
235 }
236 }
237
238 /// Creates a LIFO worker queue.
239 ///
240 /// Tasks are pushed and popped from the same end.
241 ///
242 /// # Examples
243 ///
244 /// ```
245 /// use crossbeam_deque::Worker;
246 ///
247 /// let w = Worker::<i32>::new_lifo();
248 /// ```
249 pub fn new_lifo() -> Worker<T> {
250 let buffer = Buffer::alloc(MIN_CAP);
251
252 let inner = Arc::new(CachePadded::new(Inner {
253 front: AtomicIsize::new(0),
254 back: AtomicIsize::new(0),
255 buffer: CachePadded::new(Atomic::new(buffer)),
256 }));
257
258 Worker {
259 inner,
260 buffer: Cell::new(buffer),
261 flavor: Flavor::Lifo,
262 _marker: PhantomData,
263 }
264 }
265
266 /// Creates a stealer for this queue.
267 ///
268 /// The returned stealer can be shared among threads and cloned.
269 ///
270 /// # Examples
271 ///
272 /// ```
273 /// use crossbeam_deque::Worker;
274 ///
275 /// let w = Worker::<i32>::new_lifo();
276 /// let s = w.stealer();
277 /// ```
278 pub fn stealer(&self) -> Stealer<T> {
279 Stealer {
280 inner: self.inner.clone(),
281 flavor: self.flavor,
282 }
283 }
284
285 /// Resizes the internal buffer to the new capacity of `new_cap`.
286 #[cold]
287 unsafe fn resize(&self, new_cap: usize) {
288 // Load the back index, front index, and buffer.
289 let b = self.inner.back.load(Ordering::Relaxed);
290 let f = self.inner.front.load(Ordering::Relaxed);
291 let buffer = self.buffer.get();
292
293 // Allocate a new buffer and copy data from the old buffer to the new one.
294 let new = Buffer::alloc(new_cap);
295 let mut i = f;
296 while i != b {
297 ptr::copy_nonoverlapping(buffer.at(i), new.at(i), 1);
298 i = i.wrapping_add(1);
299 }
300
301 let guard = &epoch::pin();
302
303 // Replace the old buffer with the new one.
304 self.buffer.replace(new);
305 let old =
306 self.inner
307 .buffer
308 .swap(Owned::new(new).into_shared(guard), Ordering::Release, guard);
309
310 // Destroy the old buffer later.
311 guard.defer_unchecked(move || old.into_owned().into_box().dealloc());
312
313 // If the buffer is very large, then flush the thread-local garbage in order to deallocate
314 // it as soon as possible.
315 if mem::size_of::<T>() * new_cap >= FLUSH_THRESHOLD_BYTES {
316 guard.flush();
317 }
318 }
319
320 /// Reserves enough capacity so that `reserve_cap` tasks can be pushed without growing the
321 /// buffer.
322 fn reserve(&self, reserve_cap: usize) {
323 if reserve_cap > 0 {
324 // Compute the current length.
325 let b = self.inner.back.load(Ordering::Relaxed);
326 let f = self.inner.front.load(Ordering::SeqCst);
327 let len = b.wrapping_sub(f) as usize;
328
329 // The current capacity.
330 let cap = self.buffer.get().cap;
331
332 // Is there enough capacity to push `reserve_cap` tasks?
333 if cap - len < reserve_cap {
334 // Keep doubling the capacity as much as is needed.
335 let mut new_cap = cap * 2;
336 while new_cap - len < reserve_cap {
337 new_cap *= 2;
338 }
339
340 // Resize the buffer.
341 unsafe {
342 self.resize(new_cap);
343 }
344 }
345 }
346 }
347
348 /// Returns `true` if the queue is empty.
349 ///
350 /// ```
351 /// use crossbeam_deque::Worker;
352 ///
353 /// let w = Worker::new_lifo();
354 ///
355 /// assert!(w.is_empty());
356 /// w.push(1);
357 /// assert!(!w.is_empty());
358 /// ```
359 pub fn is_empty(&self) -> bool {
360 let b = self.inner.back.load(Ordering::Relaxed);
361 let f = self.inner.front.load(Ordering::SeqCst);
362 b.wrapping_sub(f) <= 0
363 }
364
365 /// Returns the number of tasks in the deque.
366 ///
367 /// ```
368 /// use crossbeam_deque::Worker;
369 ///
370 /// let w = Worker::new_lifo();
371 ///
372 /// assert_eq!(w.len(), 0);
373 /// w.push(1);
374 /// assert_eq!(w.len(), 1);
375 /// w.push(1);
376 /// assert_eq!(w.len(), 2);
377 /// ```
378 pub fn len(&self) -> usize {
379 let b = self.inner.back.load(Ordering::Relaxed);
380 let f = self.inner.front.load(Ordering::SeqCst);
381 b.wrapping_sub(f).max(0) as usize
382 }
383
384 /// Pushes a task into the queue.
385 ///
386 /// # Examples
387 ///
388 /// ```
389 /// use crossbeam_deque::Worker;
390 ///
391 /// let w = Worker::new_lifo();
392 /// w.push(1);
393 /// w.push(2);
394 /// ```
395 pub fn push(&self, task: T) {
396 // Load the back index, front index, and buffer.
397 let b = self.inner.back.load(Ordering::Relaxed);
398 let f = self.inner.front.load(Ordering::Acquire);
399 let mut buffer = self.buffer.get();
400
401 // Calculate the length of the queue.
402 let len = b.wrapping_sub(f);
403
404 // Is the queue full?
405 if len >= buffer.cap as isize {
406 // Yes. Grow the underlying buffer.
407 unsafe {
408 self.resize(2 * buffer.cap);
409 }
410 buffer = self.buffer.get();
411 }
412
413 // Write `task` into the slot.
414 unsafe {
415 buffer.write(b, MaybeUninit::new(task));
416 }
417
418 // ThreadSanitizer does not understand fences, so we omit fence and do store with Release ordering.
419 #[cfg(not(crossbeam_sanitize_thread))]
420 atomic::fence(Ordering::Release);
421 let store_order = if cfg!(crossbeam_sanitize_thread) {
422 Ordering::Release
423 } else {
424 Ordering::Relaxed
425 };
426
427 // Increment the back index.
428 self.inner.back.store(b.wrapping_add(1), store_order);
429 }
430
431 /// Pops a task from the queue.
432 ///
433 /// # Examples
434 ///
435 /// ```
436 /// use crossbeam_deque::Worker;
437 ///
438 /// let w = Worker::new_fifo();
439 /// w.push(1);
440 /// w.push(2);
441 ///
442 /// assert_eq!(w.pop(), Some(1));
443 /// assert_eq!(w.pop(), Some(2));
444 /// assert_eq!(w.pop(), None);
445 /// ```
446 pub fn pop(&self) -> Option<T> {
447 // Load the back and front index.
448 let b = self.inner.back.load(Ordering::Relaxed);
449 let f = self.inner.front.load(Ordering::Relaxed);
450
451 // Calculate the length of the queue.
452 let len = b.wrapping_sub(f);
453
454 // Is the queue empty?
455 if len <= 0 {
456 return None;
457 }
458
459 match self.flavor {
460 // Pop from the front of the queue.
461 Flavor::Fifo => {
462 // Try incrementing the front index to pop the task.
463 let f = self.inner.front.fetch_add(1, Ordering::SeqCst);
464 let new_f = f.wrapping_add(1);
465
466 if b.wrapping_sub(new_f) < 0 {
467 self.inner.front.store(f, Ordering::Relaxed);
468 return None;
469 }
470
471 unsafe {
472 // Read the popped task.
473 let buffer = self.buffer.get();
474 let task = buffer.read(f).assume_init();
475
476 // Shrink the buffer if `len - 1` is less than one fourth of the capacity.
477 if buffer.cap > MIN_CAP && len <= buffer.cap as isize / 4 {
478 self.resize(buffer.cap / 2);
479 }
480
481 Some(task)
482 }
483 }
484
485 // Pop from the back of the queue.
486 Flavor::Lifo => {
487 // Decrement the back index.
488 let b = b.wrapping_sub(1);
489 self.inner.back.store(b, Ordering::Relaxed);
490
491 atomic::fence(Ordering::SeqCst);
492
493 // Load the front index.
494 let f = self.inner.front.load(Ordering::Relaxed);
495
496 // Compute the length after the back index was decremented.
497 let len = b.wrapping_sub(f);
498
499 if len < 0 {
500 // The queue is empty. Restore the back index to the original task.
501 self.inner.back.store(b.wrapping_add(1), Ordering::Relaxed);
502 None
503 } else {
504 // Read the task to be popped.
505 let buffer = self.buffer.get();
506 let mut task = unsafe { Some(buffer.read(b)) };
507
508 // Are we popping the last task from the queue?
509 if len == 0 {
510 // Try incrementing the front index.
511 if self
512 .inner
513 .front
514 .compare_exchange(
515 f,
516 f.wrapping_add(1),
517 Ordering::SeqCst,
518 Ordering::Relaxed,
519 )
520 .is_err()
521 {
522 // Failed. We didn't pop anything. Reset to `None`.
523 task.take();
524 }
525
526 // Restore the back index to the original task.
527 self.inner.back.store(b.wrapping_add(1), Ordering::Relaxed);
528 } else {
529 // Shrink the buffer if `len` is less than one fourth of the capacity.
530 if buffer.cap > MIN_CAP && len < buffer.cap as isize / 4 {
531 unsafe {
532 self.resize(buffer.cap / 2);
533 }
534 }
535 }
536
537 task.map(|t| unsafe { t.assume_init() })
538 }
539 }
540 }
541 }
542}
543
544impl<T> fmt::Debug for Worker<T> {
545 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
546 f.pad("Worker { .. }")
547 }
548}
549
550/// A stealer handle of a worker queue.
551///
552/// Stealers can be shared among threads.
553///
554/// Task schedulers typically have a single worker queue per worker thread.
555///
556/// # Examples
557///
558/// ```
559/// use crossbeam_deque::{Steal, Worker};
560///
561/// let w = Worker::new_lifo();
562/// w.push(1);
563/// w.push(2);
564///
565/// let s = w.stealer();
566/// assert_eq!(s.steal(), Steal::Success(1));
567/// assert_eq!(s.steal(), Steal::Success(2));
568/// assert_eq!(s.steal(), Steal::Empty);
569/// ```
570pub struct Stealer<T> {
571 /// A reference to the inner representation of the queue.
572 inner: Arc<CachePadded<Inner<T>>>,
573
574 /// The flavor of the queue.
575 flavor: Flavor,
576}
577
578unsafe impl<T: Send> Send for Stealer<T> {}
579unsafe impl<T: Send> Sync for Stealer<T> {}
580
581impl<T> Stealer<T> {
582 /// Returns `true` if the queue is empty.
583 ///
584 /// ```
585 /// use crossbeam_deque::Worker;
586 ///
587 /// let w = Worker::new_lifo();
588 /// let s = w.stealer();
589 ///
590 /// assert!(s.is_empty());
591 /// w.push(1);
592 /// assert!(!s.is_empty());
593 /// ```
594 pub fn is_empty(&self) -> bool {
595 let f = self.inner.front.load(Ordering::Acquire);
596 atomic::fence(Ordering::SeqCst);
597 let b = self.inner.back.load(Ordering::Acquire);
598 b.wrapping_sub(f) <= 0
599 }
600
601 /// Returns the number of tasks in the deque.
602 ///
603 /// ```
604 /// use crossbeam_deque::Worker;
605 ///
606 /// let w = Worker::new_lifo();
607 /// let s = w.stealer();
608 ///
609 /// assert_eq!(s.len(), 0);
610 /// w.push(1);
611 /// assert_eq!(s.len(), 1);
612 /// w.push(2);
613 /// assert_eq!(s.len(), 2);
614 /// ```
615 pub fn len(&self) -> usize {
616 let f = self.inner.front.load(Ordering::Acquire);
617 atomic::fence(Ordering::SeqCst);
618 let b = self.inner.back.load(Ordering::Acquire);
619 b.wrapping_sub(f).max(0) as usize
620 }
621
622 /// Steals a task from the queue.
623 ///
624 /// # Examples
625 ///
626 /// ```
627 /// use crossbeam_deque::{Steal, Worker};
628 ///
629 /// let w = Worker::new_lifo();
630 /// w.push(1);
631 /// w.push(2);
632 ///
633 /// let s = w.stealer();
634 /// assert_eq!(s.steal(), Steal::Success(1));
635 /// assert_eq!(s.steal(), Steal::Success(2));
636 /// ```
637 pub fn steal(&self) -> Steal<T> {
638 // Load the front index.
639 let f = self.inner.front.load(Ordering::Acquire);
640
641 // A SeqCst fence is needed here.
642 //
643 // If the current thread is already pinned (reentrantly), we must manually issue the
644 // fence. Otherwise, the following pinning will issue the fence anyway, so we don't
645 // have to.
646 if epoch::is_pinned() {
647 atomic::fence(Ordering::SeqCst);
648 }
649
650 let guard = &epoch::pin();
651
652 // Load the back index.
653 let b = self.inner.back.load(Ordering::Acquire);
654
655 // Is the queue empty?
656 if b.wrapping_sub(f) <= 0 {
657 return Steal::Empty;
658 }
659
660 // Load the buffer and read the task at the front.
661 let buffer = self.inner.buffer.load(Ordering::Acquire, guard);
662 let task = unsafe { buffer.deref().read(f) };
663
664 // Try incrementing the front index to steal the task.
665 // If the buffer has been swapped or the increment fails, we retry.
666 if self.inner.buffer.load(Ordering::Acquire, guard) != buffer
667 || self
668 .inner
669 .front
670 .compare_exchange(f, f.wrapping_add(1), Ordering::SeqCst, Ordering::Relaxed)
671 .is_err()
672 {
673 // We didn't steal this task, forget it.
674 return Steal::Retry;
675 }
676
677 // Return the stolen task.
678 Steal::Success(unsafe { task.assume_init() })
679 }
680
681 /// Steals a batch of tasks and pushes them into another worker.
682 ///
683 /// How many tasks exactly will be stolen is not specified. That said, this method will try to
684 /// steal around half of the tasks in the queue, but also not more than some constant limit.
685 ///
686 /// # Examples
687 ///
688 /// ```
689 /// use crossbeam_deque::Worker;
690 ///
691 /// let w1 = Worker::new_fifo();
692 /// w1.push(1);
693 /// w1.push(2);
694 /// w1.push(3);
695 /// w1.push(4);
696 ///
697 /// let s = w1.stealer();
698 /// let w2 = Worker::new_fifo();
699 ///
700 /// let _ = s.steal_batch(&w2);
701 /// assert_eq!(w2.pop(), Some(1));
702 /// assert_eq!(w2.pop(), Some(2));
703 /// ```
704 pub fn steal_batch(&self, dest: &Worker<T>) -> Steal<()> {
705 self.steal_batch_with_limit(dest, MAX_BATCH)
706 }
707
708 /// Steals no more than `limit` of tasks and pushes them into another worker.
709 ///
710 /// How many tasks exactly will be stolen is not specified. That said, this method will try to
711 /// steal around half of the tasks in the queue, but also not more than the given limit.
712 ///
713 /// # Examples
714 ///
715 /// ```
716 /// use crossbeam_deque::Worker;
717 ///
718 /// let w1 = Worker::new_fifo();
719 /// w1.push(1);
720 /// w1.push(2);
721 /// w1.push(3);
722 /// w1.push(4);
723 /// w1.push(5);
724 /// w1.push(6);
725 ///
726 /// let s = w1.stealer();
727 /// let w2 = Worker::new_fifo();
728 ///
729 /// let _ = s.steal_batch_with_limit(&w2, 2);
730 /// assert_eq!(w2.pop(), Some(1));
731 /// assert_eq!(w2.pop(), Some(2));
732 /// assert_eq!(w2.pop(), None);
733 ///
734 /// w1.push(7);
735 /// w1.push(8);
736 /// // Setting a large limit does not guarantee that all elements will be popped. In this case,
737 /// // half of the elements are currently popped, but the number of popped elements is considered
738 /// // an implementation detail that may be changed in the future.
739 /// let _ = s.steal_batch_with_limit(&w2, std::usize::MAX);
740 /// assert_eq!(w2.len(), 3);
741 /// ```
742 pub fn steal_batch_with_limit(&self, dest: &Worker<T>, limit: usize) -> Steal<()> {
743 assert!(limit > 0);
744 if Arc::ptr_eq(&self.inner, &dest.inner) {
745 if dest.is_empty() {
746 return Steal::Empty;
747 } else {
748 return Steal::Success(());
749 }
750 }
751
752 // Load the front index.
753 let mut f = self.inner.front.load(Ordering::Acquire);
754
755 // A SeqCst fence is needed here.
756 //
757 // If the current thread is already pinned (reentrantly), we must manually issue the
758 // fence. Otherwise, the following pinning will issue the fence anyway, so we don't
759 // have to.
760 if epoch::is_pinned() {
761 atomic::fence(Ordering::SeqCst);
762 }
763
764 let guard = &epoch::pin();
765
766 // Load the back index.
767 let b = self.inner.back.load(Ordering::Acquire);
768
769 // Is the queue empty?
770 let len = b.wrapping_sub(f);
771 if len <= 0 {
772 return Steal::Empty;
773 }
774
775 // Reserve capacity for the stolen batch.
776 let batch_size = cmp::min((len as usize + 1) / 2, limit);
777 dest.reserve(batch_size);
778 let mut batch_size = batch_size as isize;
779
780 // Get the destination buffer and back index.
781 let dest_buffer = dest.buffer.get();
782 let mut dest_b = dest.inner.back.load(Ordering::Relaxed);
783
784 // Load the buffer.
785 let buffer = self.inner.buffer.load(Ordering::Acquire, guard);
786
787 match self.flavor {
788 // Steal a batch of tasks from the front at once.
789 Flavor::Fifo => {
790 // Copy the batch from the source to the destination buffer.
791 match dest.flavor {
792 Flavor::Fifo => {
793 for i in 0..batch_size {
794 unsafe {
795 let task = buffer.deref().read(f.wrapping_add(i));
796 dest_buffer.write(dest_b.wrapping_add(i), task);
797 }
798 }
799 }
800 Flavor::Lifo => {
801 for i in 0..batch_size {
802 unsafe {
803 let task = buffer.deref().read(f.wrapping_add(i));
804 dest_buffer.write(dest_b.wrapping_add(batch_size - 1 - i), task);
805 }
806 }
807 }
808 }
809
810 // Try incrementing the front index to steal the batch.
811 // If the buffer has been swapped or the increment fails, we retry.
812 if self.inner.buffer.load(Ordering::Acquire, guard) != buffer
813 || self
814 .inner
815 .front
816 .compare_exchange(
817 f,
818 f.wrapping_add(batch_size),
819 Ordering::SeqCst,
820 Ordering::Relaxed,
821 )
822 .is_err()
823 {
824 return Steal::Retry;
825 }
826
827 dest_b = dest_b.wrapping_add(batch_size);
828 }
829
830 // Steal a batch of tasks from the front one by one.
831 Flavor::Lifo => {
832 // This loop may modify the batch_size, which triggers a clippy lint warning.
833 // Use a new variable to avoid the warning, and to make it clear we aren't
834 // modifying the loop exit condition during iteration.
835 let original_batch_size = batch_size;
836
837 for i in 0..original_batch_size {
838 // If this is not the first steal, check whether the queue is empty.
839 if i > 0 {
840 // We've already got the current front index. Now execute the fence to
841 // synchronize with other threads.
842 atomic::fence(Ordering::SeqCst);
843
844 // Load the back index.
845 let b = self.inner.back.load(Ordering::Acquire);
846
847 // Is the queue empty?
848 if b.wrapping_sub(f) <= 0 {
849 batch_size = i;
850 break;
851 }
852 }
853
854 // Read the task at the front.
855 let task = unsafe { buffer.deref().read(f) };
856
857 // Try incrementing the front index to steal the task.
858 // If the buffer has been swapped or the increment fails, we retry.
859 if self.inner.buffer.load(Ordering::Acquire, guard) != buffer
860 || self
861 .inner
862 .front
863 .compare_exchange(
864 f,
865 f.wrapping_add(1),
866 Ordering::SeqCst,
867 Ordering::Relaxed,
868 )
869 .is_err()
870 {
871 // We didn't steal this task, forget it and break from the loop.
872 batch_size = i;
873 break;
874 }
875
876 // Write the stolen task into the destination buffer.
877 unsafe {
878 dest_buffer.write(dest_b, task);
879 }
880
881 // Move the source front index and the destination back index one step forward.
882 f = f.wrapping_add(1);
883 dest_b = dest_b.wrapping_add(1);
884 }
885
886 // If we didn't steal anything, the operation needs to be retried.
887 if batch_size == 0 {
888 return Steal::Retry;
889 }
890
891 // If stealing into a FIFO queue, stolen tasks need to be reversed.
892 if dest.flavor == Flavor::Fifo {
893 for i in 0..batch_size / 2 {
894 unsafe {
895 let i1 = dest_b.wrapping_sub(batch_size - i);
896 let i2 = dest_b.wrapping_sub(i + 1);
897 let t1 = dest_buffer.read(i1);
898 let t2 = dest_buffer.read(i2);
899 dest_buffer.write(i1, t2);
900 dest_buffer.write(i2, t1);
901 }
902 }
903 }
904 }
905 }
906
907 // ThreadSanitizer does not understand fences, so we omit fence and do store with Release ordering.
908 #[cfg(not(crossbeam_sanitize_thread))]
909 atomic::fence(Ordering::Release);
910 let store_order = if cfg!(crossbeam_sanitize_thread) {
911 Ordering::Release
912 } else {
913 Ordering::Relaxed
914 };
915
916 // Update the back index in the destination queue.
917 dest.inner.back.store(dest_b, store_order);
918
919 // Return with success.
920 Steal::Success(())
921 }
922
923 /// Steals a batch of tasks, pushes them into another worker, and pops a task from that worker.
924 ///
925 /// How many tasks exactly will be stolen is not specified. That said, this method will try to
926 /// steal around half of the tasks in the queue, but also not more than some constant limit.
927 ///
928 /// # Examples
929 ///
930 /// ```
931 /// use crossbeam_deque::{Steal, Worker};
932 ///
933 /// let w1 = Worker::new_fifo();
934 /// w1.push(1);
935 /// w1.push(2);
936 /// w1.push(3);
937 /// w1.push(4);
938 ///
939 /// let s = w1.stealer();
940 /// let w2 = Worker::new_fifo();
941 ///
942 /// assert_eq!(s.steal_batch_and_pop(&w2), Steal::Success(1));
943 /// assert_eq!(w2.pop(), Some(2));
944 /// ```
945 pub fn steal_batch_and_pop(&self, dest: &Worker<T>) -> Steal<T> {
946 self.steal_batch_with_limit_and_pop(dest, MAX_BATCH)
947 }
948
949 /// Steals no more than `limit` of tasks, pushes them into another worker, and pops a task from
950 /// that worker.
951 ///
952 /// How many tasks exactly will be stolen is not specified. That said, this method will try to
953 /// steal around half of the tasks in the queue, but also not more than the given limit.
954 ///
955 /// # Examples
956 ///
957 /// ```
958 /// use crossbeam_deque::{Steal, Worker};
959 ///
960 /// let w1 = Worker::new_fifo();
961 /// w1.push(1);
962 /// w1.push(2);
963 /// w1.push(3);
964 /// w1.push(4);
965 /// w1.push(5);
966 /// w1.push(6);
967 ///
968 /// let s = w1.stealer();
969 /// let w2 = Worker::new_fifo();
970 ///
971 /// assert_eq!(s.steal_batch_with_limit_and_pop(&w2, 2), Steal::Success(1));
972 /// assert_eq!(w2.pop(), Some(2));
973 /// assert_eq!(w2.pop(), None);
974 ///
975 /// w1.push(7);
976 /// w1.push(8);
977 /// // Setting a large limit does not guarantee that all elements will be popped. In this case,
978 /// // half of the elements are currently popped, but the number of popped elements is considered
979 /// // an implementation detail that may be changed in the future.
980 /// assert_eq!(s.steal_batch_with_limit_and_pop(&w2, std::usize::MAX), Steal::Success(3));
981 /// assert_eq!(w2.pop(), Some(4));
982 /// assert_eq!(w2.pop(), Some(5));
983 /// assert_eq!(w2.pop(), None);
984 /// ```
985 pub fn steal_batch_with_limit_and_pop(&self, dest: &Worker<T>, limit: usize) -> Steal<T> {
986 assert!(limit > 0);
987 if Arc::ptr_eq(&self.inner, &dest.inner) {
988 match dest.pop() {
989 None => return Steal::Empty,
990 Some(task) => return Steal::Success(task),
991 }
992 }
993
994 // Load the front index.
995 let mut f = self.inner.front.load(Ordering::Acquire);
996
997 // A SeqCst fence is needed here.
998 //
999 // If the current thread is already pinned (reentrantly), we must manually issue the
1000 // fence. Otherwise, the following pinning will issue the fence anyway, so we don't
1001 // have to.
1002 if epoch::is_pinned() {
1003 atomic::fence(Ordering::SeqCst);
1004 }
1005
1006 let guard = &epoch::pin();
1007
1008 // Load the back index.
1009 let b = self.inner.back.load(Ordering::Acquire);
1010
1011 // Is the queue empty?
1012 let len = b.wrapping_sub(f);
1013 if len <= 0 {
1014 return Steal::Empty;
1015 }
1016
1017 // Reserve capacity for the stolen batch.
1018 let batch_size = cmp::min((len as usize - 1) / 2, limit - 1);
1019 dest.reserve(batch_size);
1020 let mut batch_size = batch_size as isize;
1021
1022 // Get the destination buffer and back index.
1023 let dest_buffer = dest.buffer.get();
1024 let mut dest_b = dest.inner.back.load(Ordering::Relaxed);
1025
1026 // Load the buffer
1027 let buffer = self.inner.buffer.load(Ordering::Acquire, guard);
1028
1029 // Read the task at the front.
1030 let mut task = unsafe { buffer.deref().read(f) };
1031
1032 match self.flavor {
1033 // Steal a batch of tasks from the front at once.
1034 Flavor::Fifo => {
1035 // Copy the batch from the source to the destination buffer.
1036 match dest.flavor {
1037 Flavor::Fifo => {
1038 for i in 0..batch_size {
1039 unsafe {
1040 let task = buffer.deref().read(f.wrapping_add(i + 1));
1041 dest_buffer.write(dest_b.wrapping_add(i), task);
1042 }
1043 }
1044 }
1045 Flavor::Lifo => {
1046 for i in 0..batch_size {
1047 unsafe {
1048 let task = buffer.deref().read(f.wrapping_add(i + 1));
1049 dest_buffer.write(dest_b.wrapping_add(batch_size - 1 - i), task);
1050 }
1051 }
1052 }
1053 }
1054
1055 // Try incrementing the front index to steal the task.
1056 // If the buffer has been swapped or the increment fails, we retry.
1057 if self.inner.buffer.load(Ordering::Acquire, guard) != buffer
1058 || self
1059 .inner
1060 .front
1061 .compare_exchange(
1062 f,
1063 f.wrapping_add(batch_size + 1),
1064 Ordering::SeqCst,
1065 Ordering::Relaxed,
1066 )
1067 .is_err()
1068 {
1069 // We didn't steal this task, forget it.
1070 return Steal::Retry;
1071 }
1072
1073 dest_b = dest_b.wrapping_add(batch_size);
1074 }
1075
1076 // Steal a batch of tasks from the front one by one.
1077 Flavor::Lifo => {
1078 // Try incrementing the front index to steal the task.
1079 if self
1080 .inner
1081 .front
1082 .compare_exchange(f, f.wrapping_add(1), Ordering::SeqCst, Ordering::Relaxed)
1083 .is_err()
1084 {
1085 // We didn't steal this task, forget it.
1086 return Steal::Retry;
1087 }
1088
1089 // Move the front index one step forward.
1090 f = f.wrapping_add(1);
1091
1092 // Repeat the same procedure for the batch steals.
1093 //
1094 // This loop may modify the batch_size, which triggers a clippy lint warning.
1095 // Use a new variable to avoid the warning, and to make it clear we aren't
1096 // modifying the loop exit condition during iteration.
1097 let original_batch_size = batch_size;
1098 for i in 0..original_batch_size {
1099 // We've already got the current front index. Now execute the fence to
1100 // synchronize with other threads.
1101 atomic::fence(Ordering::SeqCst);
1102
1103 // Load the back index.
1104 let b = self.inner.back.load(Ordering::Acquire);
1105
1106 // Is the queue empty?
1107 if b.wrapping_sub(f) <= 0 {
1108 batch_size = i;
1109 break;
1110 }
1111
1112 // Read the task at the front.
1113 let tmp = unsafe { buffer.deref().read(f) };
1114
1115 // Try incrementing the front index to steal the task.
1116 // If the buffer has been swapped or the increment fails, we retry.
1117 if self.inner.buffer.load(Ordering::Acquire, guard) != buffer
1118 || self
1119 .inner
1120 .front
1121 .compare_exchange(
1122 f,
1123 f.wrapping_add(1),
1124 Ordering::SeqCst,
1125 Ordering::Relaxed,
1126 )
1127 .is_err()
1128 {
1129 // We didn't steal this task, forget it and break from the loop.
1130 batch_size = i;
1131 break;
1132 }
1133
1134 // Write the previously stolen task into the destination buffer.
1135 unsafe {
1136 dest_buffer.write(dest_b, mem::replace(&mut task, tmp));
1137 }
1138
1139 // Move the source front index and the destination back index one step forward.
1140 f = f.wrapping_add(1);
1141 dest_b = dest_b.wrapping_add(1);
1142 }
1143
1144 // If stealing into a FIFO queue, stolen tasks need to be reversed.
1145 if dest.flavor == Flavor::Fifo {
1146 for i in 0..batch_size / 2 {
1147 unsafe {
1148 let i1 = dest_b.wrapping_sub(batch_size - i);
1149 let i2 = dest_b.wrapping_sub(i + 1);
1150 let t1 = dest_buffer.read(i1);
1151 let t2 = dest_buffer.read(i2);
1152 dest_buffer.write(i1, t2);
1153 dest_buffer.write(i2, t1);
1154 }
1155 }
1156 }
1157 }
1158 }
1159
1160 // ThreadSanitizer does not understand fences, so we omit fence and do store with Release ordering.
1161 #[cfg(not(crossbeam_sanitize_thread))]
1162 atomic::fence(Ordering::Release);
1163 let store_order = if cfg!(crossbeam_sanitize_thread) {
1164 Ordering::Release
1165 } else {
1166 Ordering::Relaxed
1167 };
1168
1169 // Update the back index in the destination queue.
1170 dest.inner.back.store(dest_b, store_order);
1171
1172 // Return with success.
1173 Steal::Success(unsafe { task.assume_init() })
1174 }
1175}
1176
1177impl<T> Clone for Stealer<T> {
1178 fn clone(&self) -> Stealer<T> {
1179 Stealer {
1180 inner: self.inner.clone(),
1181 flavor: self.flavor,
1182 }
1183 }
1184}
1185
1186impl<T> fmt::Debug for Stealer<T> {
1187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1188 f.pad("Stealer { .. }")
1189 }
1190}
1191
1192// Bits indicating the state of a slot:
1193// * If a task has been written into the slot, `WRITE` is set.
1194// * If a task has been read from the slot, `READ` is set.
1195// * If the block is being destroyed, `DESTROY` is set.
1196const WRITE: usize = 1;
1197const READ: usize = 2;
1198const DESTROY: usize = 4;
1199
1200// Each block covers one "lap" of indices.
1201const LAP: usize = 64;
1202// The maximum number of values a block can hold.
1203const BLOCK_CAP: usize = LAP - 1;
1204// How many lower bits are reserved for metadata.
1205const SHIFT: usize = 1;
1206// Indicates that the block is not the last one.
1207const HAS_NEXT: usize = 1;
1208
1209/// A slot in a block.
1210struct Slot<T> {
1211 /// The task.
1212 task: UnsafeCell<MaybeUninit<T>>,
1213
1214 /// The state of the slot.
1215 state: AtomicUsize,
1216}
1217
1218impl<T> Slot<T> {
1219 /// Waits until a task is written into the slot.
1220 fn wait_write(&self) {
1221 let backoff = Backoff::new();
1222 while self.state.load(Ordering::Acquire) & WRITE == 0 {
1223 backoff.snooze();
1224 }
1225 }
1226}
1227
1228/// A block in a linked list.
1229///
1230/// Each block in the list can hold up to `BLOCK_CAP` values.
1231struct Block<T> {
1232 /// The next block in the linked list.
1233 next: AtomicPtr<Block<T>>,
1234
1235 /// Slots for values.
1236 slots: [Slot<T>; BLOCK_CAP],
1237}
1238
1239impl<T> Block<T> {
1240 const LAYOUT: Layout = {
1241 let layout = Layout::new::<Self>();
1242 assert!(
1243 layout.size() != 0,
1244 "Block should never be zero-sized, as it has an AtomicPtr field"
1245 );
1246 layout
1247 };
1248
1249 /// Creates an empty block.
1250 fn new() -> Box<Self> {
1251 // SAFETY: layout is not zero-sized
1252 let ptr = unsafe { alloc_zeroed(Self::LAYOUT) };
1253 // Handle allocation failure
1254 if ptr.is_null() {
1255 handle_alloc_error(Self::LAYOUT)
1256 }
1257 // SAFETY: This is safe because:
1258 // [1] `Block::next` (AtomicPtr) may be safely zero initialized.
1259 // [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4].
1260 // [3] `Slot::task` (UnsafeCell) may be safely zero initialized because it
1261 // holds a MaybeUninit.
1262 // [4] `Slot::state` (AtomicUsize) may be safely zero initialized.
1263 // TODO: unsafe { Box::new_zeroed().assume_init() }
1264 unsafe { Box::from_raw(ptr.cast()) }
1265 }
1266
1267 /// Waits until the next pointer is set.
1268 fn wait_next(&self) -> *mut Block<T> {
1269 let backoff = Backoff::new();
1270 loop {
1271 let next = self.next.load(Ordering::Acquire);
1272 if !next.is_null() {
1273 return next;
1274 }
1275 backoff.snooze();
1276 }
1277 }
1278
1279 /// Sets the `DESTROY` bit in slots starting from `start` and destroys the block.
1280 unsafe fn destroy(this: *mut Block<T>, count: usize) {
1281 // It is not necessary to set the `DESTROY` bit in the last slot because that slot has
1282 // begun destruction of the block.
1283 for i in (0..count).rev() {
1284 let slot = (*this).slots.get_unchecked(i);
1285
1286 // Mark the `DESTROY` bit if a thread is still using the slot.
1287 if slot.state.load(Ordering::Acquire) & READ == 0
1288 && slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0
1289 {
1290 // If a thread is still using the slot, it will continue destruction of the block.
1291 return;
1292 }
1293 }
1294
1295 // No thread is using the block, now it is safe to destroy it.
1296 drop(Box::from_raw(this));
1297 }
1298}
1299
1300/// A position in a queue.
1301struct Position<T> {
1302 /// The index in the queue.
1303 index: AtomicUsize,
1304
1305 /// The block in the linked list.
1306 block: AtomicPtr<Block<T>>,
1307}
1308
1309/// An injector queue.
1310///
1311/// This is a FIFO queue that can be shared among multiple threads. Task schedulers typically have
1312/// a single injector queue, which is the entry point for new tasks.
1313///
1314/// # Examples
1315///
1316/// ```
1317/// use crossbeam_deque::{Injector, Steal};
1318///
1319/// let q = Injector::new();
1320/// q.push(1);
1321/// q.push(2);
1322///
1323/// assert_eq!(q.steal(), Steal::Success(1));
1324/// assert_eq!(q.steal(), Steal::Success(2));
1325/// assert_eq!(q.steal(), Steal::Empty);
1326/// ```
1327pub struct Injector<T> {
1328 /// The head of the queue.
1329 head: CachePadded<Position<T>>,
1330
1331 /// The tail of the queue.
1332 tail: CachePadded<Position<T>>,
1333
1334 /// Indicates that dropping a `Injector<T>` may drop values of type `T`.
1335 _marker: PhantomData<T>,
1336}
1337
1338unsafe impl<T: Send> Send for Injector<T> {}
1339unsafe impl<T: Send> Sync for Injector<T> {}
1340
1341impl<T> Default for Injector<T> {
1342 fn default() -> Self {
1343 let block = Box::into_raw(Block::<T>::new());
1344 Self {
1345 head: CachePadded::new(Position {
1346 block: AtomicPtr::new(block),
1347 index: AtomicUsize::new(0),
1348 }),
1349 tail: CachePadded::new(Position {
1350 block: AtomicPtr::new(block),
1351 index: AtomicUsize::new(0),
1352 }),
1353 _marker: PhantomData,
1354 }
1355 }
1356}
1357
1358impl<T> Injector<T> {
1359 /// Creates a new injector queue.
1360 ///
1361 /// # Examples
1362 ///
1363 /// ```
1364 /// use crossbeam_deque::Injector;
1365 ///
1366 /// let q = Injector::<i32>::new();
1367 /// ```
1368 pub fn new() -> Injector<T> {
1369 Self::default()
1370 }
1371
1372 /// Pushes a task into the queue.
1373 ///
1374 /// # Examples
1375 ///
1376 /// ```
1377 /// use crossbeam_deque::Injector;
1378 ///
1379 /// let w = Injector::new();
1380 /// w.push(1);
1381 /// w.push(2);
1382 /// ```
1383 pub fn push(&self, task: T) {
1384 let backoff = Backoff::new();
1385 let mut tail = self.tail.index.load(Ordering::Acquire);
1386 let mut block = self.tail.block.load(Ordering::Acquire);
1387 let mut next_block = None;
1388
1389 loop {
1390 // Calculate the offset of the index into the block.
1391 let offset = (tail >> SHIFT) % LAP;
1392
1393 // If we reached the end of the block, wait until the next one is installed.
1394 if offset == BLOCK_CAP {
1395 backoff.snooze();
1396 tail = self.tail.index.load(Ordering::Acquire);
1397 block = self.tail.block.load(Ordering::Acquire);
1398 continue;
1399 }
1400
1401 // If we're going to have to install the next block, allocate it in advance in order to
1402 // make the wait for other threads as short as possible.
1403 if offset + 1 == BLOCK_CAP && next_block.is_none() {
1404 next_block = Some(Block::<T>::new());
1405 }
1406
1407 let new_tail = tail + (1 << SHIFT);
1408
1409 // Try advancing the tail forward.
1410 match self.tail.index.compare_exchange_weak(
1411 tail,
1412 new_tail,
1413 Ordering::SeqCst,
1414 Ordering::Acquire,
1415 ) {
1416 Ok(_) => unsafe {
1417 // If we've reached the end of the block, install the next one.
1418 if offset + 1 == BLOCK_CAP {
1419 let next_block = Box::into_raw(next_block.unwrap());
1420 let next_index = new_tail.wrapping_add(1 << SHIFT);
1421
1422 self.tail.block.store(next_block, Ordering::Release);
1423 self.tail.index.store(next_index, Ordering::Release);
1424 (*block).next.store(next_block, Ordering::Release);
1425 }
1426
1427 // Write the task into the slot.
1428 let slot = (*block).slots.get_unchecked(offset);
1429 slot.task.get().write(MaybeUninit::new(task));
1430 slot.state.fetch_or(WRITE, Ordering::Release);
1431
1432 return;
1433 },
1434 Err(t) => {
1435 tail = t;
1436 block = self.tail.block.load(Ordering::Acquire);
1437 backoff.spin();
1438 }
1439 }
1440 }
1441 }
1442
1443 /// Steals a task from the queue.
1444 ///
1445 /// # Examples
1446 ///
1447 /// ```
1448 /// use crossbeam_deque::{Injector, Steal};
1449 ///
1450 /// let q = Injector::new();
1451 /// q.push(1);
1452 /// q.push(2);
1453 ///
1454 /// assert_eq!(q.steal(), Steal::Success(1));
1455 /// assert_eq!(q.steal(), Steal::Success(2));
1456 /// assert_eq!(q.steal(), Steal::Empty);
1457 /// ```
1458 pub fn steal(&self) -> Steal<T> {
1459 let mut head;
1460 let mut block;
1461 let mut offset;
1462
1463 let backoff = Backoff::new();
1464 loop {
1465 head = self.head.index.load(Ordering::Acquire);
1466 block = self.head.block.load(Ordering::Acquire);
1467
1468 // Calculate the offset of the index into the block.
1469 offset = (head >> SHIFT) % LAP;
1470
1471 // If we reached the end of the block, wait until the next one is installed.
1472 if offset == BLOCK_CAP {
1473 backoff.snooze();
1474 } else {
1475 break;
1476 }
1477 }
1478
1479 let mut new_head = head + (1 << SHIFT);
1480
1481 if new_head & HAS_NEXT == 0 {
1482 atomic::fence(Ordering::SeqCst);
1483 let tail = self.tail.index.load(Ordering::Relaxed);
1484
1485 // If the tail equals the head, that means the queue is empty.
1486 if head >> SHIFT == tail >> SHIFT {
1487 return Steal::Empty;
1488 }
1489
1490 // If head and tail are not in the same block, set `HAS_NEXT` in head.
1491 if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP {
1492 new_head |= HAS_NEXT;
1493 }
1494 }
1495
1496 // Try moving the head index forward.
1497 if self
1498 .head
1499 .index
1500 .compare_exchange_weak(head, new_head, Ordering::SeqCst, Ordering::Acquire)
1501 .is_err()
1502 {
1503 return Steal::Retry;
1504 }
1505
1506 unsafe {
1507 // If we've reached the end of the block, move to the next one.
1508 if offset + 1 == BLOCK_CAP {
1509 let next = (*block).wait_next();
1510 let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT);
1511 if !(*next).next.load(Ordering::Relaxed).is_null() {
1512 next_index |= HAS_NEXT;
1513 }
1514
1515 self.head.block.store(next, Ordering::Release);
1516 self.head.index.store(next_index, Ordering::Release);
1517 }
1518
1519 // Read the task.
1520 let slot = (*block).slots.get_unchecked(offset);
1521 slot.wait_write();
1522 let task = slot.task.get().read().assume_init();
1523
1524 // Destroy the block if we've reached the end, or if another thread wanted to destroy
1525 // but couldn't because we were busy reading from the slot.
1526 if (offset + 1 == BLOCK_CAP)
1527 || (slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0)
1528 {
1529 Block::destroy(block, offset);
1530 }
1531
1532 Steal::Success(task)
1533 }
1534 }
1535
1536 /// Steals a batch of tasks and pushes them into a worker.
1537 ///
1538 /// How many tasks exactly will be stolen is not specified. That said, this method will try to
1539 /// steal around half of the tasks in the queue, but also not more than some constant limit.
1540 ///
1541 /// # Examples
1542 ///
1543 /// ```
1544 /// use crossbeam_deque::{Injector, Worker};
1545 ///
1546 /// let q = Injector::new();
1547 /// q.push(1);
1548 /// q.push(2);
1549 /// q.push(3);
1550 /// q.push(4);
1551 ///
1552 /// let w = Worker::new_fifo();
1553 /// let _ = q.steal_batch(&w);
1554 /// assert_eq!(w.pop(), Some(1));
1555 /// assert_eq!(w.pop(), Some(2));
1556 /// ```
1557 pub fn steal_batch(&self, dest: &Worker<T>) -> Steal<()> {
1558 self.steal_batch_with_limit(dest, MAX_BATCH)
1559 }
1560
1561 /// Steals no more than `limit` of tasks and pushes them into a worker.
1562 ///
1563 /// How many tasks exactly will be stolen is not specified. That said, this method will try to
1564 /// steal around half of the tasks in the queue, but also not more than some constant limit.
1565 ///
1566 /// # Examples
1567 ///
1568 /// ```
1569 /// use crossbeam_deque::{Injector, Worker};
1570 ///
1571 /// let q = Injector::new();
1572 /// q.push(1);
1573 /// q.push(2);
1574 /// q.push(3);
1575 /// q.push(4);
1576 /// q.push(5);
1577 /// q.push(6);
1578 ///
1579 /// let w = Worker::new_fifo();
1580 /// let _ = q.steal_batch_with_limit(&w, 2);
1581 /// assert_eq!(w.pop(), Some(1));
1582 /// assert_eq!(w.pop(), Some(2));
1583 /// assert_eq!(w.pop(), None);
1584 ///
1585 /// q.push(7);
1586 /// q.push(8);
1587 /// // Setting a large limit does not guarantee that all elements will be popped. In this case,
1588 /// // half of the elements are currently popped, but the number of popped elements is considered
1589 /// // an implementation detail that may be changed in the future.
1590 /// let _ = q.steal_batch_with_limit(&w, std::usize::MAX);
1591 /// assert_eq!(w.len(), 3);
1592 /// ```
1593 pub fn steal_batch_with_limit(&self, dest: &Worker<T>, limit: usize) -> Steal<()> {
1594 assert!(limit > 0);
1595 let mut head;
1596 let mut block;
1597 let mut offset;
1598
1599 let backoff = Backoff::new();
1600 loop {
1601 head = self.head.index.load(Ordering::Acquire);
1602 block = self.head.block.load(Ordering::Acquire);
1603
1604 // Calculate the offset of the index into the block.
1605 offset = (head >> SHIFT) % LAP;
1606
1607 // If we reached the end of the block, wait until the next one is installed.
1608 if offset == BLOCK_CAP {
1609 backoff.snooze();
1610 } else {
1611 break;
1612 }
1613 }
1614
1615 let mut new_head = head;
1616 let advance;
1617
1618 if new_head & HAS_NEXT == 0 {
1619 atomic::fence(Ordering::SeqCst);
1620 let tail = self.tail.index.load(Ordering::Relaxed);
1621
1622 // If the tail equals the head, that means the queue is empty.
1623 if head >> SHIFT == tail >> SHIFT {
1624 return Steal::Empty;
1625 }
1626
1627 // If head and tail are not in the same block, set `HAS_NEXT` in head. Also, calculate
1628 // the right batch size to steal.
1629 if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP {
1630 new_head |= HAS_NEXT;
1631 // We can steal all tasks till the end of the block.
1632 advance = (BLOCK_CAP - offset).min(limit);
1633 } else {
1634 let len = (tail - head) >> SHIFT;
1635 // Steal half of the available tasks.
1636 advance = ((len + 1) / 2).min(limit);
1637 }
1638 } else {
1639 // We can steal all tasks till the end of the block.
1640 advance = (BLOCK_CAP - offset).min(limit);
1641 }
1642
1643 new_head += advance << SHIFT;
1644 let new_offset = offset + advance;
1645
1646 // Try moving the head index forward.
1647 if self
1648 .head
1649 .index
1650 .compare_exchange_weak(head, new_head, Ordering::SeqCst, Ordering::Acquire)
1651 .is_err()
1652 {
1653 return Steal::Retry;
1654 }
1655
1656 // Reserve capacity for the stolen batch.
1657 let batch_size = new_offset - offset;
1658 dest.reserve(batch_size);
1659
1660 // Get the destination buffer and back index.
1661 let dest_buffer = dest.buffer.get();
1662 let dest_b = dest.inner.back.load(Ordering::Relaxed);
1663
1664 unsafe {
1665 // If we've reached the end of the block, move to the next one.
1666 if new_offset == BLOCK_CAP {
1667 let next = (*block).wait_next();
1668 let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT);
1669 if !(*next).next.load(Ordering::Relaxed).is_null() {
1670 next_index |= HAS_NEXT;
1671 }
1672
1673 self.head.block.store(next, Ordering::Release);
1674 self.head.index.store(next_index, Ordering::Release);
1675 }
1676
1677 // Copy values from the injector into the destination queue.
1678 match dest.flavor {
1679 Flavor::Fifo => {
1680 for i in 0..batch_size {
1681 // Read the task.
1682 let slot = (*block).slots.get_unchecked(offset + i);
1683 slot.wait_write();
1684 let task = slot.task.get().read();
1685
1686 // Write it into the destination queue.
1687 dest_buffer.write(dest_b.wrapping_add(i as isize), task);
1688 }
1689 }
1690
1691 Flavor::Lifo => {
1692 for i in 0..batch_size {
1693 // Read the task.
1694 let slot = (*block).slots.get_unchecked(offset + i);
1695 slot.wait_write();
1696 let task = slot.task.get().read();
1697
1698 // Write it into the destination queue.
1699 dest_buffer.write(dest_b.wrapping_add((batch_size - 1 - i) as isize), task);
1700 }
1701 }
1702 }
1703
1704 // ThreadSanitizer does not understand fences, so we omit fence and do store with Release ordering.
1705 #[cfg(not(crossbeam_sanitize_thread))]
1706 atomic::fence(Ordering::Release);
1707 let store_order = if cfg!(crossbeam_sanitize_thread) {
1708 Ordering::Release
1709 } else {
1710 Ordering::Relaxed
1711 };
1712
1713 // Update the back index in the destination queue.
1714 dest.inner
1715 .back
1716 .store(dest_b.wrapping_add(batch_size as isize), store_order);
1717
1718 // Destroy the block if we've reached the end, or if another thread wanted to destroy
1719 // but couldn't because we were busy reading from the slot.
1720 if new_offset == BLOCK_CAP {
1721 Block::destroy(block, offset);
1722 } else {
1723 for i in offset..new_offset {
1724 let slot = (*block).slots.get_unchecked(i);
1725
1726 if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 {
1727 Block::destroy(block, offset);
1728 break;
1729 }
1730 }
1731 }
1732
1733 Steal::Success(())
1734 }
1735 }
1736
1737 /// Steals a batch of tasks, pushes them into a worker, and pops a task from that worker.
1738 ///
1739 /// How many tasks exactly will be stolen is not specified. That said, this method will try to
1740 /// steal around half of the tasks in the queue, but also not more than some constant limit.
1741 ///
1742 /// # Examples
1743 ///
1744 /// ```
1745 /// use crossbeam_deque::{Injector, Steal, Worker};
1746 ///
1747 /// let q = Injector::new();
1748 /// q.push(1);
1749 /// q.push(2);
1750 /// q.push(3);
1751 /// q.push(4);
1752 ///
1753 /// let w = Worker::new_fifo();
1754 /// assert_eq!(q.steal_batch_and_pop(&w), Steal::Success(1));
1755 /// assert_eq!(w.pop(), Some(2));
1756 /// ```
1757 pub fn steal_batch_and_pop(&self, dest: &Worker<T>) -> Steal<T> {
1758 // TODO: we use `MAX_BATCH + 1` as the hard limit for Injecter as the performance is slightly
1759 // better, but we may change it in the future to be compatible with the same method in Stealer.
1760 self.steal_batch_with_limit_and_pop(dest, MAX_BATCH + 1)
1761 }
1762
1763 /// Steals no more than `limit` of tasks, pushes them into a worker, and pops a task from that worker.
1764 ///
1765 /// How many tasks exactly will be stolen is not specified. That said, this method will try to
1766 /// steal around half of the tasks in the queue, but also not more than the given limit.
1767 ///
1768 /// # Examples
1769 ///
1770 /// ```
1771 /// use crossbeam_deque::{Injector, Steal, Worker};
1772 ///
1773 /// let q = Injector::new();
1774 /// q.push(1);
1775 /// q.push(2);
1776 /// q.push(3);
1777 /// q.push(4);
1778 /// q.push(5);
1779 /// q.push(6);
1780 ///
1781 /// let w = Worker::new_fifo();
1782 /// assert_eq!(q.steal_batch_with_limit_and_pop(&w, 2), Steal::Success(1));
1783 /// assert_eq!(w.pop(), Some(2));
1784 /// assert_eq!(w.pop(), None);
1785 ///
1786 /// q.push(7);
1787 /// // Setting a large limit does not guarantee that all elements will be popped. In this case,
1788 /// // half of the elements are currently popped, but the number of popped elements is considered
1789 /// // an implementation detail that may be changed in the future.
1790 /// assert_eq!(q.steal_batch_with_limit_and_pop(&w, std::usize::MAX), Steal::Success(3));
1791 /// assert_eq!(w.pop(), Some(4));
1792 /// assert_eq!(w.pop(), Some(5));
1793 /// assert_eq!(w.pop(), None);
1794 /// ```
1795 pub fn steal_batch_with_limit_and_pop(&self, dest: &Worker<T>, limit: usize) -> Steal<T> {
1796 assert!(limit > 0);
1797 let mut head;
1798 let mut block;
1799 let mut offset;
1800
1801 let backoff = Backoff::new();
1802 loop {
1803 head = self.head.index.load(Ordering::Acquire);
1804 block = self.head.block.load(Ordering::Acquire);
1805
1806 // Calculate the offset of the index into the block.
1807 offset = (head >> SHIFT) % LAP;
1808
1809 // If we reached the end of the block, wait until the next one is installed.
1810 if offset == BLOCK_CAP {
1811 backoff.snooze();
1812 } else {
1813 break;
1814 }
1815 }
1816
1817 let mut new_head = head;
1818 let advance;
1819
1820 if new_head & HAS_NEXT == 0 {
1821 atomic::fence(Ordering::SeqCst);
1822 let tail = self.tail.index.load(Ordering::Relaxed);
1823
1824 // If the tail equals the head, that means the queue is empty.
1825 if head >> SHIFT == tail >> SHIFT {
1826 return Steal::Empty;
1827 }
1828
1829 // If head and tail are not in the same block, set `HAS_NEXT` in head.
1830 if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP {
1831 new_head |= HAS_NEXT;
1832 // We can steal all tasks till the end of the block.
1833 advance = (BLOCK_CAP - offset).min(limit);
1834 } else {
1835 let len = (tail - head) >> SHIFT;
1836 // Steal half of the available tasks.
1837 advance = ((len + 1) / 2).min(limit);
1838 }
1839 } else {
1840 // We can steal all tasks till the end of the block.
1841 advance = (BLOCK_CAP - offset).min(limit);
1842 }
1843
1844 new_head += advance << SHIFT;
1845 let new_offset = offset + advance;
1846
1847 // Try moving the head index forward.
1848 if self
1849 .head
1850 .index
1851 .compare_exchange_weak(head, new_head, Ordering::SeqCst, Ordering::Acquire)
1852 .is_err()
1853 {
1854 return Steal::Retry;
1855 }
1856
1857 // Reserve capacity for the stolen batch.
1858 let batch_size = new_offset - offset - 1;
1859 dest.reserve(batch_size);
1860
1861 // Get the destination buffer and back index.
1862 let dest_buffer = dest.buffer.get();
1863 let dest_b = dest.inner.back.load(Ordering::Relaxed);
1864
1865 unsafe {
1866 // If we've reached the end of the block, move to the next one.
1867 if new_offset == BLOCK_CAP {
1868 let next = (*block).wait_next();
1869 let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT);
1870 if !(*next).next.load(Ordering::Relaxed).is_null() {
1871 next_index |= HAS_NEXT;
1872 }
1873
1874 self.head.block.store(next, Ordering::Release);
1875 self.head.index.store(next_index, Ordering::Release);
1876 }
1877
1878 // Read the task.
1879 let slot = (*block).slots.get_unchecked(offset);
1880 slot.wait_write();
1881 let task = slot.task.get().read();
1882
1883 match dest.flavor {
1884 Flavor::Fifo => {
1885 // Copy values from the injector into the destination queue.
1886 for i in 0..batch_size {
1887 // Read the task.
1888 let slot = (*block).slots.get_unchecked(offset + i + 1);
1889 slot.wait_write();
1890 let task = slot.task.get().read();
1891
1892 // Write it into the destination queue.
1893 dest_buffer.write(dest_b.wrapping_add(i as isize), task);
1894 }
1895 }
1896
1897 Flavor::Lifo => {
1898 // Copy values from the injector into the destination queue.
1899 for i in 0..batch_size {
1900 // Read the task.
1901 let slot = (*block).slots.get_unchecked(offset + i + 1);
1902 slot.wait_write();
1903 let task = slot.task.get().read();
1904
1905 // Write it into the destination queue.
1906 dest_buffer.write(dest_b.wrapping_add((batch_size - 1 - i) as isize), task);
1907 }
1908 }
1909 }
1910
1911 // ThreadSanitizer does not understand fences, so we omit fence and do store with Release ordering.
1912 #[cfg(not(crossbeam_sanitize_thread))]
1913 atomic::fence(Ordering::Release);
1914 let store_order = if cfg!(crossbeam_sanitize_thread) {
1915 Ordering::Release
1916 } else {
1917 Ordering::Relaxed
1918 };
1919
1920 // Update the back index in the destination queue.
1921 dest.inner
1922 .back
1923 .store(dest_b.wrapping_add(batch_size as isize), store_order);
1924
1925 // Destroy the block if we've reached the end, or if another thread wanted to destroy
1926 // but couldn't because we were busy reading from the slot.
1927 if new_offset == BLOCK_CAP {
1928 Block::destroy(block, offset);
1929 } else {
1930 for i in offset..new_offset {
1931 let slot = (*block).slots.get_unchecked(i);
1932
1933 if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 {
1934 Block::destroy(block, offset);
1935 break;
1936 }
1937 }
1938 }
1939
1940 Steal::Success(task.assume_init())
1941 }
1942 }
1943
1944 /// Returns `true` if the queue is empty.
1945 ///
1946 /// # Examples
1947 ///
1948 /// ```
1949 /// use crossbeam_deque::Injector;
1950 ///
1951 /// let q = Injector::new();
1952 ///
1953 /// assert!(q.is_empty());
1954 /// q.push(1);
1955 /// assert!(!q.is_empty());
1956 /// ```
1957 pub fn is_empty(&self) -> bool {
1958 let head = self.head.index.load(Ordering::SeqCst);
1959 let tail = self.tail.index.load(Ordering::SeqCst);
1960 head >> SHIFT == tail >> SHIFT
1961 }
1962
1963 /// Returns the number of tasks in the queue.
1964 ///
1965 /// # Examples
1966 ///
1967 /// ```
1968 /// use crossbeam_deque::Injector;
1969 ///
1970 /// let q = Injector::new();
1971 ///
1972 /// assert_eq!(q.len(), 0);
1973 /// q.push(1);
1974 /// assert_eq!(q.len(), 1);
1975 /// q.push(1);
1976 /// assert_eq!(q.len(), 2);
1977 /// ```
1978 pub fn len(&self) -> usize {
1979 loop {
1980 // Load the tail index, then load the head index.
1981 let mut tail = self.tail.index.load(Ordering::SeqCst);
1982 let mut head = self.head.index.load(Ordering::SeqCst);
1983
1984 // If the tail index didn't change, we've got consistent indices to work with.
1985 if self.tail.index.load(Ordering::SeqCst) == tail {
1986 // Erase the lower bits.
1987 tail &= !((1 << SHIFT) - 1);
1988 head &= !((1 << SHIFT) - 1);
1989
1990 // Fix up indices if they fall onto block ends.
1991 if (tail >> SHIFT) & (LAP - 1) == LAP - 1 {
1992 tail = tail.wrapping_add(1 << SHIFT);
1993 }
1994 if (head >> SHIFT) & (LAP - 1) == LAP - 1 {
1995 head = head.wrapping_add(1 << SHIFT);
1996 }
1997
1998 // Rotate indices so that head falls into the first block.
1999 let lap = (head >> SHIFT) / LAP;
2000 tail = tail.wrapping_sub((lap * LAP) << SHIFT);
2001 head = head.wrapping_sub((lap * LAP) << SHIFT);
2002
2003 // Remove the lower bits.
2004 tail >>= SHIFT;
2005 head >>= SHIFT;
2006
2007 // Return the difference minus the number of blocks between tail and head.
2008 return tail - head - tail / LAP;
2009 }
2010 }
2011 }
2012}
2013
2014impl<T> Drop for Injector<T> {
2015 fn drop(&mut self) {
2016 let mut head = *self.head.index.get_mut();
2017 let mut tail = *self.tail.index.get_mut();
2018 let mut block = *self.head.block.get_mut();
2019
2020 // Erase the lower bits.
2021 head &= !((1 << SHIFT) - 1);
2022 tail &= !((1 << SHIFT) - 1);
2023
2024 unsafe {
2025 // Drop all values between `head` and `tail` and deallocate the heap-allocated blocks.
2026 while head != tail {
2027 let offset = (head >> SHIFT) % LAP;
2028
2029 if offset < BLOCK_CAP {
2030 // Drop the task in the slot.
2031 let slot = (*block).slots.get_unchecked(offset);
2032 (*slot.task.get()).assume_init_drop();
2033 } else {
2034 // Deallocate the block and move to the next one.
2035 let next = *(*block).next.get_mut();
2036 drop(Box::from_raw(block));
2037 block = next;
2038 }
2039
2040 head = head.wrapping_add(1 << SHIFT);
2041 }
2042
2043 // Deallocate the last remaining block.
2044 drop(Box::from_raw(block));
2045 }
2046 }
2047}
2048
2049impl<T> fmt::Debug for Injector<T> {
2050 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2051 f.pad("Injector { .. }")
2052 }
2053}
2054
2055/// Possible outcomes of a steal operation.
2056///
2057/// # Examples
2058///
2059/// There are lots of ways to chain results of steal operations together:
2060///
2061/// ```
2062/// use crossbeam_deque::Steal::{self, Empty, Retry, Success};
2063///
2064/// let collect = |v: Vec<Steal<i32>>| v.into_iter().collect::<Steal<i32>>();
2065///
2066/// assert_eq!(collect(vec![Empty, Empty, Empty]), Empty);
2067/// assert_eq!(collect(vec![Empty, Retry, Empty]), Retry);
2068/// assert_eq!(collect(vec![Retry, Success(1), Empty]), Success(1));
2069///
2070/// assert_eq!(collect(vec![Empty, Empty]).or_else(|| Retry), Retry);
2071/// assert_eq!(collect(vec![Retry, Empty]).or_else(|| Success(1)), Success(1));
2072/// ```
2073#[must_use]
2074#[derive(PartialEq, Eq, Copy, Clone)]
2075pub enum Steal<T> {
2076 /// The queue was empty at the time of stealing.
2077 Empty,
2078
2079 /// At least one task was successfully stolen.
2080 Success(T),
2081
2082 /// The steal operation needs to be retried.
2083 Retry,
2084}
2085
2086impl<T> Steal<T> {
2087 /// Returns `true` if the queue was empty at the time of stealing.
2088 ///
2089 /// # Examples
2090 ///
2091 /// ```
2092 /// use crossbeam_deque::Steal::{Empty, Retry, Success};
2093 ///
2094 /// assert!(!Success(7).is_empty());
2095 /// assert!(!Retry::<i32>.is_empty());
2096 ///
2097 /// assert!(Empty::<i32>.is_empty());
2098 /// ```
2099 pub fn is_empty(&self) -> bool {
2100 match self {
2101 Steal::Empty => true,
2102 _ => false,
2103 }
2104 }
2105
2106 /// Returns `true` if at least one task was stolen.
2107 ///
2108 /// # Examples
2109 ///
2110 /// ```
2111 /// use crossbeam_deque::Steal::{Empty, Retry, Success};
2112 ///
2113 /// assert!(!Empty::<i32>.is_success());
2114 /// assert!(!Retry::<i32>.is_success());
2115 ///
2116 /// assert!(Success(7).is_success());
2117 /// ```
2118 pub fn is_success(&self) -> bool {
2119 match self {
2120 Steal::Success(_) => true,
2121 _ => false,
2122 }
2123 }
2124
2125 /// Returns `true` if the steal operation needs to be retried.
2126 ///
2127 /// # Examples
2128 ///
2129 /// ```
2130 /// use crossbeam_deque::Steal::{Empty, Retry, Success};
2131 ///
2132 /// assert!(!Empty::<i32>.is_retry());
2133 /// assert!(!Success(7).is_retry());
2134 ///
2135 /// assert!(Retry::<i32>.is_retry());
2136 /// ```
2137 pub fn is_retry(&self) -> bool {
2138 match self {
2139 Steal::Retry => true,
2140 _ => false,
2141 }
2142 }
2143
2144 /// Returns the result of the operation, if successful.
2145 ///
2146 /// # Examples
2147 ///
2148 /// ```
2149 /// use crossbeam_deque::Steal::{Empty, Retry, Success};
2150 ///
2151 /// assert_eq!(Empty::<i32>.success(), None);
2152 /// assert_eq!(Retry::<i32>.success(), None);
2153 ///
2154 /// assert_eq!(Success(7).success(), Some(7));
2155 /// ```
2156 pub fn success(self) -> Option<T> {
2157 match self {
2158 Steal::Success(res) => Some(res),
2159 _ => None,
2160 }
2161 }
2162
2163 /// If no task was stolen, attempts another steal operation.
2164 ///
2165 /// Returns this steal result if it is `Success`. Otherwise, closure `f` is invoked and then:
2166 ///
2167 /// * If the second steal resulted in `Success`, it is returned.
2168 /// * If both steals were unsuccessful but any resulted in `Retry`, then `Retry` is returned.
2169 /// * If both resulted in `None`, then `None` is returned.
2170 ///
2171 /// # Examples
2172 ///
2173 /// ```
2174 /// use crossbeam_deque::Steal::{Empty, Retry, Success};
2175 ///
2176 /// assert_eq!(Success(1).or_else(|| Success(2)), Success(1));
2177 /// assert_eq!(Retry.or_else(|| Success(2)), Success(2));
2178 ///
2179 /// assert_eq!(Retry.or_else(|| Empty), Retry::<i32>);
2180 /// assert_eq!(Empty.or_else(|| Retry), Retry::<i32>);
2181 ///
2182 /// assert_eq!(Empty.or_else(|| Empty), Empty::<i32>);
2183 /// ```
2184 pub fn or_else<F>(self, f: F) -> Steal<T>
2185 where
2186 F: FnOnce() -> Steal<T>,
2187 {
2188 match self {
2189 Steal::Empty => f(),
2190 Steal::Success(_) => self,
2191 Steal::Retry => {
2192 if let Steal::Success(res) = f() {
2193 Steal::Success(res)
2194 } else {
2195 Steal::Retry
2196 }
2197 }
2198 }
2199 }
2200}
2201
2202impl<T> fmt::Debug for Steal<T> {
2203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2204 match self {
2205 Steal::Empty => f.pad("Empty"),
2206 Steal::Success(_) => f.pad("Success(..)"),
2207 Steal::Retry => f.pad("Retry"),
2208 }
2209 }
2210}
2211
2212impl<T> FromIterator<Steal<T>> for Steal<T> {
2213 /// Consumes items until a `Success` is found and returns it.
2214 ///
2215 /// If no `Success` was found, but there was at least one `Retry`, then returns `Retry`.
2216 /// Otherwise, `Empty` is returned.
2217 fn from_iter<I>(iter: I) -> Steal<T>
2218 where
2219 I: IntoIterator<Item = Steal<T>>,
2220 {
2221 let mut retry = false;
2222 for s in iter {
2223 match &s {
2224 Steal::Empty => {}
2225 Steal::Success(_) => return s,
2226 Steal::Retry => retry = true,
2227 }
2228 }
2229
2230 if retry {
2231 Steal::Retry
2232 } else {
2233 Steal::Empty
2234 }
2235 }
2236}