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}