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}