Skip to main content

crossbeam_channel/flavors/
array.rs

1//! Bounded channel based on a preallocated array.
2//!
3//! This flavor has a fixed, positive capacity.
4//!
5//! The implementation is based on Dmitry Vyukov's bounded MPMC queue.
6//!
7//! Source:
8//!   - <http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue>
9//!   - <https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub>
10
11use std::boxed::Box;
12use std::cell::UnsafeCell;
13use std::mem::{self, MaybeUninit};
14use std::ptr;
15use std::sync::atomic::{self, Ordering};
16use std::time::Instant;
17
18use crossbeam_utils::{Backoff, CachePadded};
19
20use crate::context::Context;
21use crate::err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError};
22use crate::select::{Operation, SelectHandle, Selected, Token};
23use crate::waker::SyncWaker;
24
25// Ideally, we want to always use AtomicU64, but since it is not available on all platforms,
26// we only use it when it is available for now.
27// TODO: On platforms where AtomicU64 is unavailable, we may want to use AtomicCell instead of
28// AtomicUsize. (https://github.com/crossbeam-rs/crossbeam/issues/433)
29#[cfg(target_has_atomic = "64")]
30type AtomicIndex = core::sync::atomic::AtomicU64;
31#[cfg(target_has_atomic = "64")]
32type Index = u64;
33#[cfg(not(target_has_atomic = "64"))]
34type AtomicIndex = core::sync::atomic::AtomicUsize;
35#[cfg(not(target_has_atomic = "64"))]
36type Index = usize;
37
38/// A slot in a channel.
39struct Slot<T> {
40    /// The current stamp.
41    stamp: AtomicIndex,
42
43    /// The message in this slot.
44    msg: UnsafeCell<MaybeUninit<T>>,
45}
46
47/// The token type for the array flavor.
48#[derive(Debug)]
49pub(crate) struct ArrayToken {
50    /// Slot to read from or write to.
51    slot: *const u8,
52
53    /// Stamp to store into the slot after reading or writing.
54    stamp: Index,
55}
56
57impl Default for ArrayToken {
58    #[inline]
59    fn default() -> Self {
60        ArrayToken {
61            slot: ptr::null(),
62            stamp: 0,
63        }
64    }
65}
66
67/// Bounded channel based on a preallocated array.
68pub(crate) struct Channel<T> {
69    /// The head of the channel.
70    ///
71    /// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but
72    /// packed into a single `Index`. The lower bits represent the index, while the upper bits
73    /// represent the lap. The mark bit in the head is always zero.
74    ///
75    /// Messages are popped from the head of the channel.
76    head: CachePadded<AtomicIndex>,
77
78    /// The tail of the channel.
79    ///
80    /// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but
81    /// packed into a single `Index`. The lower bits represent the index, while the upper bits
82    /// represent the lap. The mark bit indicates that the channel is disconnected.
83    ///
84    /// Messages are pushed into the tail of the channel.
85    tail: CachePadded<AtomicIndex>,
86
87    /// The buffer holding slots.
88    buffer: Box<[Slot<T>]>,
89
90    /// The channel capacity.
91    cap: usize,
92
93    /// A stamp with the value of `{ lap: 1, mark: 0, index: 0 }`.
94    one_lap: Index,
95
96    /// If this bit is set in the tail, that means the channel is disconnected.
97    mark_bit: Index,
98
99    /// Senders waiting while the channel is full.
100    senders: SyncWaker,
101
102    /// Receivers waiting while the channel is empty and not disconnected.
103    receivers: SyncWaker,
104}
105
106impl<T> Channel<T> {
107    /// Creates a bounded channel of capacity `cap`.
108    pub(crate) fn with_capacity(cap: usize) -> Self {
109        assert!(cap > 0, "capacity must be positive");
110
111        // Use checked arithmetic before computing `mark_bit` and `one_lap`.
112        let mark_bit = (cap as Index)
113            .checked_add(1)
114            .and_then(Index::checked_next_power_of_two)
115            .expect("bounded channel capacity is too large");
116        let one_lap = mark_bit
117            .checked_mul(2)
118            .expect("bounded channel capacity is too large");
119
120        // Head is initialized to `{ lap: 0, mark: 0, index: 0 }`.
121        let head = 0;
122        // Tail is initialized to `{ lap: 0, mark: 0, index: 0 }`.
123        let tail = 0;
124
125        // Allocate a buffer of `cap` slots initialized
126        // with stamps.
127        let buffer: Box<[Slot<T>]> = (0..cap)
128            .map(|i| {
129                // Set the stamp to `{ lap: 0, mark: 0, index: i }`.
130                Slot {
131                    stamp: AtomicIndex::new(i as Index),
132                    msg: UnsafeCell::new(MaybeUninit::uninit()),
133                }
134            })
135            .collect();
136
137        Channel {
138            buffer,
139            cap,
140            one_lap,
141            mark_bit,
142            head: CachePadded::new(AtomicIndex::new(head)),
143            tail: CachePadded::new(AtomicIndex::new(tail)),
144            senders: SyncWaker::new(),
145            receivers: SyncWaker::new(),
146        }
147    }
148
149    /// Returns a receiver handle to the channel.
150    pub(crate) fn receiver(&self) -> Receiver<'_, T> {
151        Receiver(self)
152    }
153
154    /// Returns a sender handle to the channel.
155    pub(crate) fn sender(&self) -> Sender<'_, T> {
156        Sender(self)
157    }
158
159    /// Attempts to reserve a slot for sending a message.
160    fn start_send(&self, token: &mut Token) -> bool {
161        let backoff = Backoff::new();
162        let mut tail = self.tail.load(Ordering::Relaxed);
163
164        loop {
165            // Check if the channel is disconnected.
166            if tail & self.mark_bit != 0 {
167                token.array.slot = ptr::null();
168                token.array.stamp = 0;
169                return true;
170            }
171
172            // Deconstruct the tail.
173            let index = (tail & (self.mark_bit - 1)) as usize;
174            let lap = tail & !(self.one_lap - 1);
175
176            // Inspect the corresponding slot.
177            debug_assert!(index < self.buffer.len());
178            let slot = unsafe { self.buffer.get_unchecked(index) };
179            let stamp = slot.stamp.load(Ordering::Acquire);
180
181            // If the tail and the stamp match, we may attempt to push.
182            if tail == stamp {
183                let new_tail = if index + 1 < self.cap {
184                    // Same lap, incremented index.
185                    // Set to `{ lap: lap, mark: 0, index: index + 1 }`.
186                    tail + 1
187                } else {
188                    // One lap forward, index wraps around to zero.
189                    // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`.
190                    lap.wrapping_add(self.one_lap)
191                };
192
193                // Try moving the tail.
194                match self.tail.compare_exchange_weak(
195                    tail,
196                    new_tail,
197                    Ordering::SeqCst,
198                    Ordering::Relaxed,
199                ) {
200                    Ok(_) => {
201                        // Prepare the token for the follow-up call to `write`.
202                        token.array.slot = slot as *const Slot<T> as *const u8;
203                        token.array.stamp = tail + 1;
204                        return true;
205                    }
206                    Err(t) => {
207                        tail = t;
208                        backoff.spin();
209                    }
210                }
211            } else if stamp.wrapping_add(self.one_lap) == tail + 1 {
212                atomic::fence(Ordering::SeqCst);
213                let head = self.head.load(Ordering::Relaxed);
214
215                // If the head lags one lap behind the tail as well...
216                if head.wrapping_add(self.one_lap) == tail {
217                    // ...then the channel is full.
218                    return false;
219                }
220
221                backoff.spin();
222                tail = self.tail.load(Ordering::Relaxed);
223            } else {
224                // Snooze because we need to wait for the stamp to get updated.
225                backoff.snooze();
226                tail = self.tail.load(Ordering::Relaxed);
227            }
228        }
229    }
230
231    /// Writes a message into the channel.
232    pub(crate) unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> {
233        // If there is no slot, the channel is disconnected.
234        if token.array.slot.is_null() {
235            return Err(msg);
236        }
237
238        let slot: &Slot<T> = &*token.array.slot.cast::<Slot<T>>();
239
240        // Write the message into the slot and update the stamp.
241        slot.msg.get().write(MaybeUninit::new(msg));
242        slot.stamp.store(token.array.stamp, Ordering::Release);
243
244        // Wake a sleeping receiver.
245        self.receivers.notify();
246        Ok(())
247    }
248
249    /// Attempts to reserve a slot for receiving a message.
250    fn start_recv(&self, token: &mut Token) -> bool {
251        let backoff = Backoff::new();
252        let mut head = self.head.load(Ordering::Relaxed);
253
254        loop {
255            // Deconstruct the head.
256            let index = (head & (self.mark_bit - 1)) as usize;
257            let lap = head & !(self.one_lap - 1);
258
259            // Inspect the corresponding slot.
260            debug_assert!(index < self.buffer.len());
261            let slot = unsafe { self.buffer.get_unchecked(index) };
262            let stamp = slot.stamp.load(Ordering::Acquire);
263
264            // If the stamp is ahead of the head by 1, we may attempt to pop.
265            if head + 1 == stamp {
266                let new = if index + 1 < self.cap {
267                    // Same lap, incremented index.
268                    // Set to `{ lap: lap, mark: 0, index: index + 1 }`.
269                    head + 1
270                } else {
271                    // One lap forward, index wraps around to zero.
272                    // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`.
273                    lap.wrapping_add(self.one_lap)
274                };
275
276                // Try moving the head.
277                match self.head.compare_exchange_weak(
278                    head,
279                    new,
280                    Ordering::SeqCst,
281                    Ordering::Relaxed,
282                ) {
283                    Ok(_) => {
284                        // Prepare the token for the follow-up call to `read`.
285                        token.array.slot = slot as *const Slot<T> as *const u8;
286                        token.array.stamp = head.wrapping_add(self.one_lap);
287                        return true;
288                    }
289                    Err(h) => {
290                        head = h;
291                        backoff.spin();
292                    }
293                }
294            } else if stamp == head {
295                atomic::fence(Ordering::SeqCst);
296                let tail = self.tail.load(Ordering::Relaxed);
297
298                // If the tail equals the head, that means the channel is empty.
299                if (tail & !self.mark_bit) == head {
300                    // If the channel is disconnected...
301                    if tail & self.mark_bit != 0 {
302                        // ...then receive an error.
303                        token.array.slot = ptr::null();
304                        token.array.stamp = 0;
305                        return true;
306                    } else {
307                        // Otherwise, the receive operation is not ready.
308                        return false;
309                    }
310                }
311
312                backoff.spin();
313                head = self.head.load(Ordering::Relaxed);
314            } else {
315                // Snooze because we need to wait for the stamp to get updated.
316                backoff.snooze();
317                head = self.head.load(Ordering::Relaxed);
318            }
319        }
320    }
321
322    /// Reads a message from the channel.
323    pub(crate) unsafe fn read(&self, token: &mut Token) -> Result<T, ()> {
324        if token.array.slot.is_null() {
325            // The channel is disconnected.
326            return Err(());
327        }
328
329        let slot: &Slot<T> = &*token.array.slot.cast::<Slot<T>>();
330
331        // Read the message from the slot and update the stamp.
332        let msg = slot.msg.get().read().assume_init();
333        slot.stamp.store(token.array.stamp, Ordering::Release);
334
335        // Wake a sleeping sender.
336        self.senders.notify();
337        Ok(msg)
338    }
339
340    /// Attempts to send a message into the channel.
341    pub(crate) fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
342        let token = &mut Token::default();
343        if self.start_send(token) {
344            unsafe { self.write(token, msg).map_err(TrySendError::Disconnected) }
345        } else {
346            Err(TrySendError::Full(msg))
347        }
348    }
349
350    /// Sends a message into the channel.
351    pub(crate) fn send(
352        &self,
353        msg: T,
354        deadline: Option<Instant>,
355    ) -> Result<(), SendTimeoutError<T>> {
356        let token = &mut Token::default();
357        loop {
358            // Try sending a message several times.
359            let backoff = Backoff::new();
360            loop {
361                if self.start_send(token) {
362                    let res = unsafe { self.write(token, msg) };
363                    return res.map_err(SendTimeoutError::Disconnected);
364                }
365
366                if backoff.is_completed() {
367                    break;
368                } else {
369                    backoff.snooze();
370                }
371            }
372
373            if let Some(d) = deadline {
374                if Instant::now() >= d {
375                    return Err(SendTimeoutError::Timeout(msg));
376                }
377            }
378
379            Context::with(|cx| {
380                // Prepare for blocking until a receiver wakes us up.
381                let oper = Operation::hook(token);
382                self.senders.register(oper, cx);
383
384                // Has the channel become ready just now?
385                if !self.is_full() || self.is_disconnected() {
386                    let _ = cx.try_select(Selected::Aborted);
387                }
388
389                // Block the current thread.
390                let sel = cx.wait_until(deadline);
391
392                match sel {
393                    Selected::Waiting => unreachable!(),
394                    Selected::Aborted | Selected::Disconnected => {
395                        self.senders.unregister(oper).unwrap();
396                    }
397                    Selected::Operation(_) => {}
398                }
399            });
400        }
401    }
402
403    /// Attempts to receive a message without blocking.
404    pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
405        let token = &mut Token::default();
406
407        if self.start_recv(token) {
408            unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) }
409        } else {
410            Err(TryRecvError::Empty)
411        }
412    }
413
414    /// Receives a message from the channel.
415    pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
416        let token = &mut Token::default();
417        loop {
418            // Try receiving a message several times.
419            let backoff = Backoff::new();
420            loop {
421                if self.start_recv(token) {
422                    let res = unsafe { self.read(token) };
423                    return res.map_err(|_| RecvTimeoutError::Disconnected);
424                }
425
426                if backoff.is_completed() {
427                    break;
428                } else {
429                    backoff.snooze();
430                }
431            }
432
433            if let Some(d) = deadline {
434                if Instant::now() >= d {
435                    return Err(RecvTimeoutError::Timeout);
436                }
437            }
438
439            Context::with(|cx| {
440                // Prepare for blocking until a sender wakes us up.
441                let oper = Operation::hook(token);
442                self.receivers.register(oper, cx);
443
444                // Has the channel become ready just now?
445                if !self.is_empty() || self.is_disconnected() {
446                    let _ = cx.try_select(Selected::Aborted);
447                }
448
449                // Block the current thread.
450                let sel = cx.wait_until(deadline);
451
452                match sel {
453                    Selected::Waiting => unreachable!(),
454                    Selected::Aborted | Selected::Disconnected => {
455                        self.receivers.unregister(oper).unwrap();
456                        // If the channel was disconnected, we still have to check for remaining
457                        // messages.
458                    }
459                    Selected::Operation(_) => {}
460                }
461            });
462        }
463    }
464
465    /// Returns the current number of messages inside the channel.
466    pub(crate) fn len(&self) -> usize {
467        loop {
468            // Load the tail, then load the head.
469            let tail = self.tail.load(Ordering::SeqCst);
470            let head = self.head.load(Ordering::SeqCst);
471
472            // If the tail didn't change, we've got consistent values to work with.
473            if self.tail.load(Ordering::SeqCst) == tail {
474                let hix = (head & (self.mark_bit - 1)) as usize;
475                let tix = (tail & (self.mark_bit - 1)) as usize;
476
477                return if hix < tix {
478                    tix - hix
479                } else if hix > tix {
480                    self.cap - hix + tix
481                } else if (tail & !self.mark_bit) == head {
482                    0
483                } else {
484                    self.cap
485                };
486            }
487        }
488    }
489
490    /// Returns the capacity of the channel.
491    pub(crate) fn capacity(&self) -> Option<usize> {
492        Some(self.cap)
493    }
494
495    /// Disconnects the channel and wakes up all blocked senders and receivers.
496    ///
497    /// Returns `true` if this call disconnected the channel.
498    pub(crate) fn disconnect(&self) -> bool {
499        let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst);
500
501        if tail & self.mark_bit == 0 {
502            self.senders.disconnect();
503            self.receivers.disconnect();
504            true
505        } else {
506            false
507        }
508    }
509
510    /// Returns `true` if the channel is disconnected.
511    pub(crate) fn is_disconnected(&self) -> bool {
512        self.tail.load(Ordering::SeqCst) & self.mark_bit != 0
513    }
514
515    /// Returns `true` if the channel is empty.
516    pub(crate) fn is_empty(&self) -> bool {
517        let head = self.head.load(Ordering::SeqCst);
518        let tail = self.tail.load(Ordering::SeqCst);
519
520        // Is the tail equal to the head?
521        //
522        // Note: If the head changes just before we load the tail, that means there was a moment
523        // when the channel was not empty, so it is safe to just return `false`.
524        (tail & !self.mark_bit) == head
525    }
526
527    /// Returns `true` if the channel is full.
528    pub(crate) fn is_full(&self) -> bool {
529        let tail = self.tail.load(Ordering::SeqCst);
530        let head = self.head.load(Ordering::SeqCst);
531
532        // Is the head lagging one lap behind tail?
533        //
534        // Note: If the tail changes just before we load the head, that means there was a moment
535        // when the channel was not full, so it is safe to just return `false`.
536        head.wrapping_add(self.one_lap) == tail & !self.mark_bit
537    }
538}
539
540impl<T> Drop for Channel<T> {
541    fn drop(&mut self) {
542        if mem::needs_drop::<T>() {
543            // Get the index of the head.
544            let head = *self.head.get_mut();
545            let tail = *self.tail.get_mut();
546
547            let hix = (head & (self.mark_bit - 1)) as usize;
548            let tix = (tail & (self.mark_bit - 1)) as usize;
549
550            let len = if hix < tix {
551                tix - hix
552            } else if hix > tix {
553                self.cap - hix + tix
554            } else if (tail & !self.mark_bit) == head {
555                0
556            } else {
557                self.cap
558            };
559
560            // Loop over all slots that hold a message and drop them.
561            for i in 0..len {
562                // Compute the index of the next slot holding a message.
563                let index = if hix + i < self.cap {
564                    hix + i
565                } else {
566                    hix + i - self.cap
567                };
568
569                unsafe {
570                    debug_assert!(index < self.buffer.len());
571                    let slot = self.buffer.get_unchecked_mut(index);
572                    (*slot.msg.get()).assume_init_drop();
573                }
574            }
575        }
576    }
577}
578
579/// Receiver handle to a channel.
580pub(crate) struct Receiver<'a, T>(&'a Channel<T>);
581
582/// Sender handle to a channel.
583pub(crate) struct Sender<'a, T>(&'a Channel<T>);
584
585impl<T> SelectHandle for Receiver<'_, T> {
586    fn try_select(&self, token: &mut Token) -> bool {
587        self.0.start_recv(token)
588    }
589
590    fn deadline(&self) -> Option<Instant> {
591        None
592    }
593
594    fn register(&self, oper: Operation, cx: &Context) -> bool {
595        self.0.receivers.register(oper, cx);
596        self.is_ready()
597    }
598
599    fn unregister(&self, oper: Operation) {
600        self.0.receivers.unregister(oper);
601    }
602
603    fn accept(&self, token: &mut Token, _cx: &Context) -> bool {
604        self.try_select(token)
605    }
606
607    fn is_ready(&self) -> bool {
608        !self.0.is_empty() || self.0.is_disconnected()
609    }
610
611    fn watch(&self, oper: Operation, cx: &Context) -> bool {
612        self.0.receivers.watch(oper, cx);
613        self.is_ready()
614    }
615
616    fn unwatch(&self, oper: Operation) {
617        self.0.receivers.unwatch(oper);
618    }
619}
620
621impl<T> SelectHandle for Sender<'_, T> {
622    fn try_select(&self, token: &mut Token) -> bool {
623        self.0.start_send(token)
624    }
625
626    fn deadline(&self) -> Option<Instant> {
627        None
628    }
629
630    fn register(&self, oper: Operation, cx: &Context) -> bool {
631        self.0.senders.register(oper, cx);
632        self.is_ready()
633    }
634
635    fn unregister(&self, oper: Operation) {
636        self.0.senders.unregister(oper);
637    }
638
639    fn accept(&self, token: &mut Token, _cx: &Context) -> bool {
640        self.try_select(token)
641    }
642
643    fn is_ready(&self) -> bool {
644        !self.0.is_full() || self.0.is_disconnected()
645    }
646
647    fn watch(&self, oper: Operation, cx: &Context) -> bool {
648        self.0.senders.watch(oper, cx);
649        self.is_ready()
650    }
651
652    fn unwatch(&self, oper: Operation) {
653        self.0.senders.unwatch(oper);
654    }
655}