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