Skip to main content

crossbeam_queue/
array_queue.rs

1//! The implementation is based on Dmitry Vyukov's bounded MPMC queue.
2//!
3//! Source:
4//!   - <http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue>
5
6use alloc::boxed::Box;
7use core::cell::UnsafeCell;
8use core::fmt;
9use core::mem::{self, MaybeUninit};
10use core::panic::{RefUnwindSafe, UnwindSafe};
11use core::sync::atomic::{self, Ordering};
12
13use crossbeam_utils::{Backoff, CachePadded};
14
15// Ideally, we want to always use AtomicU64, but since it is not available on all platforms,
16// we only use it when it is available for now.
17// TODO: On platforms where AtomicU64 is unavailable, we may want to use AtomicCell instead of
18// AtomicUsize. (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 Index = u64;
23#[cfg(not(target_has_atomic = "64"))]
24type AtomicIndex = core::sync::atomic::AtomicUsize;
25#[cfg(not(target_has_atomic = "64"))]
26type Index = usize;
27
28/// A slot in a queue.
29struct Slot<T> {
30    /// The current stamp.
31    ///
32    /// If the stamp equals the tail, this node will be next written to. If it equals head + 1,
33    /// this node will be next read from.
34    stamp: AtomicIndex,
35
36    /// The value in this slot.
37    value: UnsafeCell<MaybeUninit<T>>,
38}
39
40/// A bounded multi-producer multi-consumer queue.
41///
42/// This queue allocates a fixed-capacity buffer on construction, which is used to store pushed
43/// elements. The queue cannot hold more elements than the buffer allows. Attempting to push an
44/// element into a full queue will fail. Alternatively, [`force_push`] makes it possible for
45/// this queue to be used as a ring-buffer. Having a buffer allocated upfront makes this queue
46/// a bit faster than [`SegQueue`].
47///
48/// [`force_push`]: ArrayQueue::force_push
49/// [`SegQueue`]: super::SegQueue
50///
51/// # Examples
52///
53/// ```
54/// use crossbeam_queue::ArrayQueue;
55///
56/// let q = ArrayQueue::new(2);
57///
58/// assert_eq!(q.push('a'), Ok(()));
59/// assert_eq!(q.push('b'), Ok(()));
60/// assert_eq!(q.push('c'), Err('c'));
61/// assert_eq!(q.pop(), Some('a'));
62/// ```
63pub struct ArrayQueue<T> {
64    /// The head of the queue.
65    ///
66    /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a
67    /// single `Index`. The lower bits represent the index, while the upper bits represent the lap.
68    ///
69    /// Elements are popped from the head of the queue.
70    head: CachePadded<AtomicIndex>,
71
72    /// The tail of the queue.
73    ///
74    /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a
75    /// single `Index`. The lower bits represent the index, while the upper bits represent the lap.
76    ///
77    /// Elements are pushed into the tail of the queue.
78    tail: CachePadded<AtomicIndex>,
79
80    /// The buffer holding slots.
81    buffer: Box<[Slot<T>]>,
82
83    /// The queue capacity.
84    cap: usize,
85
86    /// A stamp with the value of `{ lap: 1, index: 0 }`.
87    one_lap: Index,
88}
89
90unsafe impl<T: Send> Sync for ArrayQueue<T> {}
91unsafe impl<T: Send> Send for ArrayQueue<T> {}
92
93impl<T> UnwindSafe for ArrayQueue<T> {}
94impl<T> RefUnwindSafe for ArrayQueue<T> {}
95
96impl<T> ArrayQueue<T> {
97    /// Creates a new bounded queue with the given capacity.
98    ///
99    /// # Panics
100    ///
101    /// Panics if the capacity is zero or too large.
102    ///
103    /// # Examples
104    ///
105    /// ```
106    /// use crossbeam_queue::ArrayQueue;
107    ///
108    /// let q = ArrayQueue::<i32>::new(100);
109    /// ```
110    pub fn new(cap: usize) -> ArrayQueue<T> {
111        assert!(cap > 0, "capacity must be non-zero");
112
113        // Head is initialized to `{ lap: 0, index: 0 }`.
114        // Tail is initialized to `{ lap: 0, index: 0 }`.
115        let head = 0;
116        let tail = 0;
117
118        // Allocate a buffer of `cap` slots initialized
119        // with stamps.
120        let buffer: Box<[Slot<T>]> = (0..cap)
121            .map(|i| {
122                // Set the stamp to `{ lap: 0, index: i }`.
123                Slot {
124                    stamp: AtomicIndex::new(i as Index),
125                    value: UnsafeCell::new(MaybeUninit::uninit()),
126                }
127            })
128            .collect();
129
130        // One lap is the smallest power of two greater than `cap`.
131        let one_lap = (cap as Index)
132            .checked_add(1)
133            .and_then(Index::checked_next_power_of_two)
134            .expect("queue capacity is too large");
135
136        ArrayQueue {
137            buffer,
138            cap,
139            one_lap,
140            head: CachePadded::new(AtomicIndex::new(head)),
141            tail: CachePadded::new(AtomicIndex::new(tail)),
142        }
143    }
144
145    fn push_or_else<F>(&self, mut value: T, f: F) -> Result<(), T>
146    where
147        F: Fn(T, Index, Index, &Slot<T>) -> Result<T, T>,
148    {
149        let backoff = Backoff::new();
150        let mut tail = self.tail.load(Ordering::Relaxed);
151
152        loop {
153            // Deconstruct the tail.
154            let index = (tail & (self.one_lap - 1)) as usize;
155            let lap = tail & !(self.one_lap - 1);
156
157            let new_tail = if index + 1 < self.cap {
158                // Same lap, incremented index.
159                // Set to `{ lap: lap, index: index + 1 }`.
160                tail + 1
161            } else {
162                // One lap forward, index wraps around to zero.
163                // Set to `{ lap: lap.wrapping_add(1), index: 0 }`.
164                lap.wrapping_add(self.one_lap)
165            };
166
167            // Inspect the corresponding slot.
168            debug_assert!(index < self.buffer.len());
169            let slot = unsafe { self.buffer.get_unchecked(index) };
170            let stamp = slot.stamp.load(Ordering::Acquire);
171
172            // If the tail and the stamp match, we may attempt to push.
173            if tail == stamp {
174                // Try moving the tail.
175                match self.tail.compare_exchange_weak(
176                    tail,
177                    new_tail,
178                    Ordering::SeqCst,
179                    Ordering::Relaxed,
180                ) {
181                    Ok(_) => {
182                        // Write the value into the slot and update the stamp.
183                        unsafe {
184                            slot.value.get().write(MaybeUninit::new(value));
185                        }
186                        slot.stamp.store(tail + 1, Ordering::Release);
187                        return Ok(());
188                    }
189                    Err(t) => {
190                        tail = t;
191                        backoff.spin();
192                    }
193                }
194            } else if stamp.wrapping_add(self.one_lap) == tail + 1 {
195                atomic::fence(Ordering::SeqCst);
196                value = f(value, tail, new_tail, slot)?;
197                backoff.spin();
198                tail = self.tail.load(Ordering::Relaxed);
199            } else {
200                // Snooze because we need to wait for the stamp to get updated.
201                backoff.snooze();
202                tail = self.tail.load(Ordering::Relaxed);
203            }
204        }
205    }
206
207    /// Attempts to push an element into the queue.
208    ///
209    /// If the queue is full, the element is returned back as an error.
210    ///
211    /// # Examples
212    ///
213    /// ```
214    /// use crossbeam_queue::ArrayQueue;
215    ///
216    /// let q = ArrayQueue::new(1);
217    ///
218    /// assert_eq!(q.push(10), Ok(()));
219    /// assert_eq!(q.push(20), Err(20));
220    /// ```
221    pub fn push(&self, value: T) -> Result<(), T> {
222        self.push_or_else(value, |v, tail, _, _| {
223            let head = self.head.load(Ordering::Relaxed);
224
225            // If the head lags one lap behind the tail as well...
226            if head.wrapping_add(self.one_lap) == tail {
227                // ...then the queue is full.
228                Err(v)
229            } else {
230                Ok(v)
231            }
232        })
233    }
234
235    /// Attempts to push an element using an exclusive reference of the queue.
236    ///
237    /// Atomic operations and checks are omitted
238    ///
239    /// # Examples
240    ///
241    /// ```
242    /// use crossbeam_queue::ArrayQueue;
243    ///
244    /// let mut q = ArrayQueue::new(1);
245    ///
246    /// assert_eq!(q.push_mut(10), Ok(()));
247    /// assert_eq!(q.push_mut(20), Err(20));
248    /// ```
249    pub fn push_mut(&mut self, value: T) -> Result<(), T> {
250        let tail = *self.tail.get_mut();
251        let head = *self.head.get_mut();
252
253        if head.wrapping_add(self.one_lap) == tail {
254            return Err(value);
255        }
256
257        let index = (tail & (self.one_lap - 1)) as usize;
258        let lap = tail & !(self.one_lap - 1);
259        let new_tail = if index + 1 < self.capacity() {
260            tail + 1
261        } else {
262            lap.wrapping_add(self.one_lap)
263        };
264
265        *self.tail.get_mut() = new_tail;
266
267        let slot = unsafe { self.buffer.get_unchecked_mut(index) };
268        unsafe {
269            slot.value.get().write(MaybeUninit::new(value));
270        }
271        *slot.stamp.get_mut() = tail + 1;
272
273        Ok(())
274    }
275
276    /// Pushes an element into the queue, replacing the oldest element if necessary.
277    ///
278    /// If the queue is full, the oldest element is replaced and returned,
279    /// otherwise `None` is returned.
280    ///
281    /// # Examples
282    ///
283    /// ```
284    /// use crossbeam_queue::ArrayQueue;
285    ///
286    /// let q = ArrayQueue::new(2);
287    ///
288    /// assert_eq!(q.force_push(10), None);
289    /// assert_eq!(q.force_push(20), None);
290    /// assert_eq!(q.force_push(30), Some(10));
291    /// assert_eq!(q.pop(), Some(20));
292    /// ```
293    pub fn force_push(&self, value: T) -> Option<T> {
294        self.push_or_else(value, |v, tail, new_tail, slot| {
295            let head = tail.wrapping_sub(self.one_lap);
296            let new_head = new_tail.wrapping_sub(self.one_lap);
297
298            // Try moving the head.
299            if self
300                .head
301                .compare_exchange_weak(head, new_head, Ordering::SeqCst, Ordering::Relaxed)
302                .is_ok()
303            {
304                // Move the tail.
305                self.tail.store(new_tail, Ordering::SeqCst);
306
307                // Swap the previous value.
308                let old = unsafe { slot.value.get().replace(MaybeUninit::new(v)).assume_init() };
309
310                // Update the stamp.
311                slot.stamp.store(tail + 1, Ordering::Release);
312
313                Err(old)
314            } else {
315                Ok(v)
316            }
317        })
318        .err()
319    }
320
321    /// Attempts to pop an element from the queue.
322    ///
323    /// If the queue is empty, `None` is returned.
324    ///
325    /// # Examples
326    ///
327    /// ```
328    /// use crossbeam_queue::ArrayQueue;
329    ///
330    /// let q = ArrayQueue::new(1);
331    /// assert_eq!(q.push(10), Ok(()));
332    ///
333    /// assert_eq!(q.pop(), Some(10));
334    /// assert!(q.pop().is_none());
335    /// ```
336    pub fn pop(&self) -> Option<T> {
337        let backoff = Backoff::new();
338        let mut head = self.head.load(Ordering::Relaxed);
339
340        loop {
341            // Deconstruct the head.
342            let index = (head & (self.one_lap - 1)) as usize;
343            let lap = head & !(self.one_lap - 1);
344
345            // Inspect the corresponding slot.
346            debug_assert!(index < self.buffer.len());
347            let slot = unsafe { self.buffer.get_unchecked(index) };
348            let stamp = slot.stamp.load(Ordering::Acquire);
349
350            // If the stamp is ahead of the head by 1, we may attempt to pop.
351            if head + 1 == stamp {
352                let new = if index + 1 < self.cap {
353                    // Same lap, incremented index.
354                    // Set to `{ lap: lap, index: index + 1 }`.
355                    head + 1
356                } else {
357                    // One lap forward, index wraps around to zero.
358                    // Set to `{ lap: lap.wrapping_add(1), index: 0 }`.
359                    lap.wrapping_add(self.one_lap)
360                };
361
362                // Try moving the head.
363                match self.head.compare_exchange_weak(
364                    head,
365                    new,
366                    Ordering::SeqCst,
367                    Ordering::Relaxed,
368                ) {
369                    Ok(_) => {
370                        // Read the value from the slot and update the stamp.
371                        let msg = unsafe { slot.value.get().read().assume_init() };
372                        slot.stamp
373                            .store(head.wrapping_add(self.one_lap), Ordering::Release);
374                        return Some(msg);
375                    }
376                    Err(h) => {
377                        head = h;
378                        backoff.spin();
379                    }
380                }
381            } else if stamp == head {
382                atomic::fence(Ordering::SeqCst);
383                let tail = self.tail.load(Ordering::Relaxed);
384
385                // If the tail equals the head, that means the channel is empty.
386                if tail == head {
387                    return None;
388                }
389
390                backoff.spin();
391                head = self.head.load(Ordering::Relaxed);
392            } else {
393                // Snooze because we need to wait for the stamp to get updated.
394                backoff.snooze();
395                head = self.head.load(Ordering::Relaxed);
396            }
397        }
398    }
399
400    /// Attempts to pop an element using an exclusive reference of the queue.
401    ///
402    /// Due to having an exclusive reference, atomic operations and checks are omitted
403    ///
404    /// # Examples
405    ///
406    /// ```
407    /// use crossbeam_queue::ArrayQueue;
408    ///
409    /// let mut q = ArrayQueue::new(1);
410    /// assert_eq!(q.push(10), Ok(()));
411    ///
412    /// assert_eq!(q.pop_mut(), Some(10));
413    /// assert!(q.pop_mut().is_none());
414    /// ```
415    pub fn pop_mut(&mut self) -> Option<T> {
416        let head = *self.head.get_mut();
417        let tail = *self.tail.get_mut();
418
419        // If the tail equals the head, that means the channel is empty.
420        if tail == head {
421            return None;
422        }
423        let index = (head & (self.one_lap - 1)) as usize;
424        let lap = head & !(self.one_lap - 1);
425
426        // Inspect the corresponding slot.
427        debug_assert!(index < self.buffer.len());
428
429        let new = if index + 1 < self.capacity() {
430            // Same lap, incremented index.
431            // Set to `{ lap: lap, index: index + 1 }`.
432            head + 1
433        } else {
434            // One lap forward, index wraps around to zero.
435            // Set to `{ lap: lap.wrapping_add(1), index: 0 }`.
436            lap.wrapping_add(self.one_lap)
437        };
438
439        let slot = unsafe { self.buffer.get_unchecked_mut(index) };
440
441        let msg = unsafe { slot.value.get().read().assume_init() };
442        *slot.stamp.get_mut() = head.wrapping_add(self.one_lap);
443        *self.head.get_mut() = new;
444        Some(msg)
445    }
446
447    /// Returns the capacity of the queue.
448    ///
449    /// # Examples
450    ///
451    /// ```
452    /// use crossbeam_queue::ArrayQueue;
453    ///
454    /// let q = ArrayQueue::<i32>::new(100);
455    ///
456    /// assert_eq!(q.capacity(), 100);
457    /// ```
458    pub fn capacity(&self) -> usize {
459        self.cap
460    }
461
462    /// Returns `true` if the queue is empty.
463    ///
464    /// # Examples
465    ///
466    /// ```
467    /// use crossbeam_queue::ArrayQueue;
468    ///
469    /// let q = ArrayQueue::new(100);
470    ///
471    /// assert!(q.is_empty());
472    /// q.push(1).unwrap();
473    /// assert!(!q.is_empty());
474    /// ```
475    pub fn is_empty(&self) -> bool {
476        let head = self.head.load(Ordering::SeqCst);
477        let tail = self.tail.load(Ordering::SeqCst);
478
479        // Is the tail lagging one lap behind head?
480        // Is the tail equal to the head?
481        //
482        // Note: If the head changes just before we load the tail, that means there was a moment
483        // when the channel was not empty, so it is safe to just return `false`.
484        tail == head
485    }
486
487    /// Returns `true` if the queue is full.
488    ///
489    /// # Examples
490    ///
491    /// ```
492    /// use crossbeam_queue::ArrayQueue;
493    ///
494    /// let q = ArrayQueue::new(1);
495    ///
496    /// assert!(!q.is_full());
497    /// q.push(1).unwrap();
498    /// assert!(q.is_full());
499    /// ```
500    pub fn is_full(&self) -> bool {
501        let tail = self.tail.load(Ordering::SeqCst);
502        let head = self.head.load(Ordering::SeqCst);
503
504        // Is the head lagging one lap behind tail?
505        //
506        // Note: If the tail changes just before we load the head, that means there was a moment
507        // when the queue was not full, so it is safe to just return `false`.
508        head.wrapping_add(self.one_lap) == tail
509    }
510
511    /// Returns the number of elements in the queue.
512    ///
513    /// # Examples
514    ///
515    /// ```
516    /// use crossbeam_queue::ArrayQueue;
517    ///
518    /// let q = ArrayQueue::new(100);
519    /// assert_eq!(q.len(), 0);
520    ///
521    /// q.push(10).unwrap();
522    /// assert_eq!(q.len(), 1);
523    ///
524    /// q.push(20).unwrap();
525    /// assert_eq!(q.len(), 2);
526    /// ```
527    pub fn len(&self) -> usize {
528        loop {
529            // Load the tail, then load the head.
530            let tail = self.tail.load(Ordering::SeqCst);
531            let head = self.head.load(Ordering::SeqCst);
532
533            // If the tail didn't change, we've got consistent values to work with.
534            if self.tail.load(Ordering::SeqCst) == tail {
535                let hix = (head & (self.one_lap - 1)) as usize;
536                let tix = (tail & (self.one_lap - 1)) as usize;
537
538                return if hix < tix {
539                    tix - hix
540                } else if hix > tix {
541                    self.cap - hix + tix
542                } else if tail == head {
543                    0
544                } else {
545                    self.cap
546                };
547            }
548        }
549    }
550}
551
552impl<T> Drop for ArrayQueue<T> {
553    fn drop(&mut self) {
554        if mem::needs_drop::<T>() {
555            // Get the index of the head.
556            let head = *self.head.get_mut();
557            let tail = *self.tail.get_mut();
558
559            let hix = (head & (self.one_lap - 1)) as usize;
560            let tix = (tail & (self.one_lap - 1)) as usize;
561
562            let len = if hix < tix {
563                tix - hix
564            } else if hix > tix {
565                self.cap - hix + tix
566            } else if tail == head {
567                0
568            } else {
569                self.cap
570            };
571
572            // Loop over all slots that hold a message and drop them.
573            for i in 0..len {
574                // Compute the index of the next slot holding a message.
575                let index = if hix + i < self.cap {
576                    hix + i
577                } else {
578                    hix + i - self.cap
579                };
580
581                unsafe {
582                    debug_assert!(index < self.buffer.len());
583                    let slot = self.buffer.get_unchecked_mut(index);
584                    (*slot.value.get()).assume_init_drop();
585                }
586            }
587        }
588    }
589}
590
591impl<T> fmt::Debug for ArrayQueue<T> {
592    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
593        f.pad("ArrayQueue { .. }")
594    }
595}
596
597impl<T> IntoIterator for ArrayQueue<T> {
598    type Item = T;
599
600    type IntoIter = IntoIter<T>;
601
602    fn into_iter(self) -> Self::IntoIter {
603        IntoIter { value: self }
604    }
605}
606
607#[derive(Debug)]
608pub struct IntoIter<T> {
609    value: ArrayQueue<T>,
610}
611
612impl<T> Iterator for IntoIter<T> {
613    type Item = T;
614
615    fn next(&mut self) -> Option<Self::Item> {
616        let value = &mut self.value;
617        let head = *value.head.get_mut();
618        if value.head.get_mut() != value.tail.get_mut() {
619            let index = (head & (value.one_lap - 1)) as usize;
620            let lap = head & !(value.one_lap - 1);
621            // SAFETY: We have mutable access to this, so we can read without
622            // worrying about concurrency. Furthermore, we know this is
623            // initialized because it is the value pointed at by `value.head`
624            // and this is a non-empty queue.
625            let val = unsafe {
626                debug_assert!(index < value.buffer.len());
627                let slot = value.buffer.get_unchecked_mut(index);
628                slot.value.get().read().assume_init()
629            };
630            let new = if index + 1 < value.cap {
631                // Same lap, incremented index.
632                // Set to `{ lap: lap, index: index + 1 }`.
633                head + 1
634            } else {
635                // One lap forward, index wraps around to zero.
636                // Set to `{ lap: lap.wrapping_add(1), index: 0 }`.
637                lap.wrapping_add(value.one_lap)
638            };
639            *value.head.get_mut() = new;
640            Option::Some(val)
641        } else {
642            Option::None
643        }
644    }
645}