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