Skip to main content

crossbeam_channel/flavors/
list.rs

1//! Unbounded channel implemented as a linked list.
2
3use std::alloc::{alloc_zeroed, handle_alloc_error, Layout};
4use std::boxed::Box;
5use std::cell::UnsafeCell;
6use std::marker::PhantomData;
7use std::mem::MaybeUninit;
8use std::ptr;
9use std::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering};
10use std::time::Instant;
11
12use crossbeam_utils::{Backoff, CachePadded};
13
14use crate::context::Context;
15use crate::err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError};
16use crate::select::{Operation, SelectHandle, Selected, Token};
17use crate::waker::SyncWaker;
18
19// Ideally, we want to always use AtomicU64, but since it is not available on all platforms,
20// we only use it when it is available for now.
21// TODO: On platforms where AtomicU64 is unavailable, we may want to use AtomicCell instead of
22// AtomicUsize. (https://github.com/crossbeam-rs/crossbeam/issues/433)
23#[cfg(target_has_atomic = "64")]
24type AtomicIndex = core::sync::atomic::AtomicU64;
25#[cfg(target_has_atomic = "64")]
26type Index = u64;
27#[cfg(not(target_has_atomic = "64"))]
28type AtomicIndex = core::sync::atomic::AtomicUsize;
29#[cfg(not(target_has_atomic = "64"))]
30type Index = usize;
31
32// TODO(stjepang): Once we bump the minimum required Rust version to 1.28 or newer, re-apply the
33// following changes by @kleimkuhler:
34//
35// 1. https://github.com/crossbeam-rs/crossbeam-channel/pull/100
36// 2. https://github.com/crossbeam-rs/crossbeam-channel/pull/101
37
38// Bits indicating the state of a slot:
39// * If a message has been written into the slot, `WRITE` is set.
40// * If a message has been read from the slot, `READ` is set.
41// * If the block is being destroyed, `DESTROY` is set.
42const WRITE: usize = 1;
43const READ: usize = 2;
44const DESTROY: usize = 4;
45
46// Each block covers one "lap" of indices.
47const LAP: Index = 32;
48// The maximum number of messages a block can hold.
49const BLOCK_CAP: usize = LAP as usize - 1;
50// How many lower bits are reserved for metadata.
51const SHIFT: usize = 1;
52// Has two different purposes:
53// * If set in head, indicates that the block is not the last one.
54// * If set in tail, indicates that the channel is disconnected.
55const MARK_BIT: Index = 1;
56
57/// A slot in a block.
58struct Slot<T> {
59    /// The message.
60    msg: UnsafeCell<MaybeUninit<T>>,
61
62    /// The state of the slot.
63    state: AtomicUsize,
64}
65
66impl<T> Slot<T> {
67    /// Waits until a message is written into the slot.
68    fn wait_write(&self) {
69        let backoff = Backoff::new();
70        while self.state.load(Ordering::Acquire) & WRITE == 0 {
71            backoff.snooze();
72        }
73    }
74}
75
76/// A block in a linked list.
77///
78/// Each block in the list can hold up to `BLOCK_CAP` messages.
79struct Block<T> {
80    /// The next block in the linked list.
81    next: AtomicPtr<Block<T>>,
82
83    /// Slots for messages.
84    slots: [Slot<T>; BLOCK_CAP],
85}
86
87impl<T> Block<T> {
88    const LAYOUT: Layout = {
89        let layout = Layout::new::<Self>();
90        assert!(
91            layout.size() != 0,
92            "Block should never be zero-sized, as it has an AtomicPtr field"
93        );
94        layout
95    };
96
97    /// Creates an empty block.
98    fn new() -> Box<Self> {
99        // SAFETY: layout is not zero-sized
100        let ptr = unsafe { alloc_zeroed(Self::LAYOUT) };
101        // Handle allocation failure
102        if ptr.is_null() {
103            handle_alloc_error(Self::LAYOUT)
104        }
105        // SAFETY: This is safe because:
106        //  [1] `Block::next` (AtomicPtr) may be safely zero initialized.
107        //  [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4].
108        //  [3] `Slot::msg` (UnsafeCell) may be safely zero initialized because it
109        //       holds a MaybeUninit.
110        //  [4] `Slot::state` (AtomicUsize) may be safely zero initialized.
111        // TODO: unsafe { Box::new_zeroed().assume_init() }
112        unsafe { Box::from_raw(ptr.cast()) }
113    }
114
115    /// Waits until the next pointer is set.
116    fn wait_next(&self) -> *mut Block<T> {
117        let backoff = Backoff::new();
118        loop {
119            let next = self.next.load(Ordering::Acquire);
120            if !next.is_null() {
121                return next;
122            }
123            backoff.snooze();
124        }
125    }
126
127    /// Sets the `DESTROY` bit in slots starting from `start` and destroys the block.
128    unsafe fn destroy(this: *mut Block<T>, start: usize) {
129        // It is not necessary to set the `DESTROY` bit in the last slot because that slot has
130        // begun destruction of the block.
131        for i in start..BLOCK_CAP - 1 {
132            let slot = (*this).slots.get_unchecked(i);
133
134            // Mark the `DESTROY` bit if a thread is still using the slot.
135            if slot.state.load(Ordering::Acquire) & READ == 0
136                && slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0
137            {
138                // If a thread is still using the slot, it will continue destruction of the block.
139                return;
140            }
141        }
142
143        // No thread is using the block, now it is safe to destroy it.
144        drop(Box::from_raw(this));
145    }
146}
147
148/// A position in a channel.
149#[derive(Debug)]
150struct Position<T> {
151    /// The index in the channel.
152    index: AtomicIndex,
153
154    /// The block in the linked list.
155    block: AtomicPtr<Block<T>>,
156}
157
158/// The token type for the list flavor.
159#[derive(Debug)]
160pub(crate) struct ListToken {
161    /// The block of slots.
162    block: *const u8,
163
164    /// The offset into the block.
165    offset: usize,
166}
167
168impl Default for ListToken {
169    #[inline]
170    fn default() -> Self {
171        ListToken {
172            block: ptr::null(),
173            offset: 0,
174        }
175    }
176}
177
178/// Unbounded channel implemented as a linked list.
179///
180/// Each message sent into the channel is assigned a sequence number, i.e. an index. Indices are
181/// represented as numbers of type `Index` and wrap on overflow.
182///
183/// Consecutive messages are grouped into blocks in order to put less pressure on the allocator and
184/// improve cache efficiency.
185pub(crate) struct Channel<T> {
186    /// The head of the channel.
187    head: CachePadded<Position<T>>,
188
189    /// The tail of the channel.
190    tail: CachePadded<Position<T>>,
191
192    /// Receivers waiting while the channel is empty and not disconnected.
193    receivers: SyncWaker,
194
195    /// Indicates that dropping a `Channel<T>` may drop messages of type `T`.
196    _marker: PhantomData<T>,
197}
198
199impl<T> Channel<T> {
200    /// Creates a new unbounded channel.
201    pub(crate) fn new() -> Self {
202        Channel {
203            head: CachePadded::new(Position {
204                block: AtomicPtr::new(ptr::null_mut()),
205                index: AtomicIndex::new(0),
206            }),
207            tail: CachePadded::new(Position {
208                block: AtomicPtr::new(ptr::null_mut()),
209                index: AtomicIndex::new(0),
210            }),
211            receivers: SyncWaker::new(),
212            _marker: PhantomData,
213        }
214    }
215
216    /// Returns a receiver handle to the channel.
217    pub(crate) fn receiver(&self) -> Receiver<'_, T> {
218        Receiver(self)
219    }
220
221    /// Returns a sender handle to the channel.
222    pub(crate) fn sender(&self) -> Sender<'_, T> {
223        Sender(self)
224    }
225
226    /// Attempts to reserve a slot for sending a message.
227    fn start_send(&self, token: &mut Token) -> bool {
228        let backoff = Backoff::new();
229        let mut tail = self.tail.index.load(Ordering::Acquire);
230        let mut block = self.tail.block.load(Ordering::Acquire);
231        let mut next_block = None;
232
233        loop {
234            // Check if the channel is disconnected.
235            if tail & MARK_BIT != 0 {
236                token.list.block = ptr::null();
237                return true;
238            }
239
240            // Calculate the offset of the index into the block.
241            let offset = ((tail >> SHIFT) % LAP) as usize;
242
243            // If we reached the end of the block, wait until the next one is installed.
244            if offset == BLOCK_CAP {
245                backoff.snooze();
246                tail = self.tail.index.load(Ordering::Acquire);
247                block = self.tail.block.load(Ordering::Acquire);
248                continue;
249            }
250
251            // If we're going to have to install the next block, allocate it in advance in order to
252            // make the wait for other threads as short as possible.
253            if offset + 1 == BLOCK_CAP && next_block.is_none() {
254                next_block = Some(Block::<T>::new());
255            }
256
257            // If this is the first message to be sent into the channel, we need to allocate the
258            // first block and install it.
259            if block.is_null() {
260                let new = Box::into_raw(Block::<T>::new());
261
262                if self
263                    .tail
264                    .block
265                    .compare_exchange(block, new, Ordering::Release, Ordering::Relaxed)
266                    .is_ok()
267                {
268                    self.head.block.store(new, Ordering::Release);
269                    block = new;
270                } else {
271                    next_block = unsafe { Some(Box::from_raw(new)) };
272                    tail = self.tail.index.load(Ordering::Acquire);
273                    block = self.tail.block.load(Ordering::Acquire);
274                    continue;
275                }
276            }
277
278            let new_tail = tail + (1 << SHIFT);
279
280            // Try advancing the tail forward.
281            match self.tail.index.compare_exchange_weak(
282                tail,
283                new_tail,
284                Ordering::SeqCst,
285                Ordering::Acquire,
286            ) {
287                Ok(_) => unsafe {
288                    // If we've reached the end of the block, install the next one.
289                    if offset + 1 == BLOCK_CAP {
290                        let next_block = Box::into_raw(next_block.unwrap());
291                        self.tail.block.store(next_block, Ordering::Release);
292                        self.tail.index.fetch_add(1 << SHIFT, Ordering::Release);
293                        (*block).next.store(next_block, Ordering::Release);
294                    }
295
296                    token.list.block = block as *const u8;
297                    token.list.offset = offset;
298                    return true;
299                },
300                Err(t) => {
301                    tail = t;
302                    block = self.tail.block.load(Ordering::Acquire);
303                    backoff.spin();
304                }
305            }
306        }
307    }
308
309    /// Writes a message into the channel.
310    pub(crate) unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> {
311        // If there is no slot, the channel is disconnected.
312        if token.list.block.is_null() {
313            return Err(msg);
314        }
315
316        // Write the message into the slot.
317        let block = token.list.block.cast::<Block<T>>();
318        let offset = token.list.offset;
319        let slot = (*block).slots.get_unchecked(offset);
320        slot.msg.get().write(MaybeUninit::new(msg));
321        slot.state.fetch_or(WRITE, Ordering::Release);
322
323        // Wake a sleeping receiver.
324        self.receivers.notify();
325        Ok(())
326    }
327
328    /// Attempts to reserve a slot for receiving a message.
329    fn start_recv(&self, token: &mut Token) -> bool {
330        let backoff = Backoff::new();
331        let mut head = self.head.index.load(Ordering::Acquire);
332        let mut block = self.head.block.load(Ordering::Acquire);
333
334        loop {
335            // Calculate the offset of the index into the block.
336            let offset = ((head >> SHIFT) % LAP) as usize;
337
338            // If we reached the end of the block, wait until the next one is installed.
339            if offset == BLOCK_CAP {
340                backoff.snooze();
341                head = self.head.index.load(Ordering::Acquire);
342                block = self.head.block.load(Ordering::Acquire);
343                continue;
344            }
345
346            let mut new_head = head + (1 << SHIFT);
347
348            if new_head & MARK_BIT == 0 {
349                atomic::fence(Ordering::SeqCst);
350                let tail = self.tail.index.load(Ordering::Relaxed);
351
352                // If the tail equals the head, that means the channel is empty.
353                if head >> SHIFT == tail >> SHIFT {
354                    // If the channel is disconnected...
355                    if tail & MARK_BIT != 0 {
356                        // ...then receive an error.
357                        token.list.block = ptr::null();
358                        return true;
359                    } else {
360                        // Otherwise, the receive operation is not ready.
361                        return false;
362                    }
363                }
364
365                // If head and tail are not in the same block, set `MARK_BIT` in head.
366                if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP {
367                    new_head |= MARK_BIT;
368                }
369            }
370
371            // The block can be null here only if the first message is being sent into the channel.
372            // In that case, just wait until it gets initialized.
373            if block.is_null() {
374                backoff.snooze();
375                head = self.head.index.load(Ordering::Acquire);
376                block = self.head.block.load(Ordering::Acquire);
377                continue;
378            }
379
380            // Try moving the head index forward.
381            match self.head.index.compare_exchange_weak(
382                head,
383                new_head,
384                Ordering::SeqCst,
385                Ordering::Acquire,
386            ) {
387                Ok(_) => unsafe {
388                    // If we've reached the end of the block, move to the next one.
389                    if offset + 1 == BLOCK_CAP {
390                        let next = (*block).wait_next();
391                        let mut next_index = (new_head & !MARK_BIT).wrapping_add(1 << SHIFT);
392                        if !(*next).next.load(Ordering::Relaxed).is_null() {
393                            next_index |= MARK_BIT;
394                        }
395
396                        self.head.block.store(next, Ordering::Release);
397                        self.head.index.store(next_index, Ordering::Release);
398                    }
399
400                    token.list.block = block as *const u8;
401                    token.list.offset = offset;
402                    return true;
403                },
404                Err(h) => {
405                    head = h;
406                    block = self.head.block.load(Ordering::Acquire);
407                    backoff.spin();
408                }
409            }
410        }
411    }
412
413    /// Reads a message from the channel.
414    pub(crate) unsafe fn read(&self, token: &mut Token) -> Result<T, ()> {
415        if token.list.block.is_null() {
416            // The channel is disconnected.
417            return Err(());
418        }
419
420        // Read the message.
421        let block = token.list.block as *mut Block<T>;
422        let offset = token.list.offset;
423        let slot = (*block).slots.get_unchecked(offset);
424        slot.wait_write();
425        let msg = slot.msg.get().read().assume_init();
426
427        // Destroy the block if we've reached the end, or if another thread wanted to destroy but
428        // couldn't because we were busy reading from the slot.
429        if offset + 1 == BLOCK_CAP {
430            Block::destroy(block, 0);
431        } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 {
432            Block::destroy(block, offset + 1);
433        }
434
435        Ok(msg)
436    }
437
438    /// Attempts to send a message into the channel.
439    pub(crate) fn try_send(&self, msg: T) -> Result<(), TrySendError<T>> {
440        self.send(msg, None).map_err(|err| match err {
441            SendTimeoutError::Disconnected(msg) => TrySendError::Disconnected(msg),
442            SendTimeoutError::Timeout(_) => unreachable!(),
443        })
444    }
445
446    /// Sends a message into the channel.
447    pub(crate) fn send(
448        &self,
449        msg: T,
450        _deadline: Option<Instant>,
451    ) -> Result<(), SendTimeoutError<T>> {
452        let token = &mut Token::default();
453        assert!(self.start_send(token));
454        unsafe {
455            self.write(token, msg)
456                .map_err(SendTimeoutError::Disconnected)
457        }
458    }
459
460    /// Attempts to receive a message without blocking.
461    pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
462        let token = &mut Token::default();
463
464        if self.start_recv(token) {
465            unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) }
466        } else {
467            Err(TryRecvError::Empty)
468        }
469    }
470
471    /// Receives a message from the channel.
472    pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
473        let token = &mut Token::default();
474        loop {
475            // Try receiving a message several times.
476            let backoff = Backoff::new();
477            loop {
478                if self.start_recv(token) {
479                    unsafe {
480                        return self.read(token).map_err(|_| RecvTimeoutError::Disconnected);
481                    }
482                }
483
484                if backoff.is_completed() {
485                    break;
486                } else {
487                    backoff.snooze();
488                }
489            }
490
491            if let Some(d) = deadline {
492                if Instant::now() >= d {
493                    return Err(RecvTimeoutError::Timeout);
494                }
495            }
496
497            // Prepare for blocking until a sender wakes us up.
498            Context::with(|cx| {
499                let oper = Operation::hook(token);
500                self.receivers.register(oper, cx);
501
502                // Has the channel become ready just now?
503                if !self.is_empty() || self.is_disconnected() {
504                    let _ = cx.try_select(Selected::Aborted);
505                }
506
507                // Block the current thread.
508                let sel = cx.wait_until(deadline);
509
510                match sel {
511                    Selected::Waiting => unreachable!(),
512                    Selected::Aborted | Selected::Disconnected => {
513                        self.receivers.unregister(oper).unwrap();
514                        // If the channel was disconnected, we still have to check for remaining
515                        // messages.
516                    }
517                    Selected::Operation(_) => {}
518                }
519            });
520        }
521    }
522
523    /// Returns the current number of messages inside the channel.
524    pub(crate) fn len(&self) -> usize {
525        loop {
526            // Load the tail index, then load the head index.
527            let mut tail = self.tail.index.load(Ordering::SeqCst);
528            let mut head = self.head.index.load(Ordering::SeqCst);
529
530            // If the tail index didn't change, we've got consistent indices to work with.
531            if self.tail.index.load(Ordering::SeqCst) == tail {
532                // Erase the lower bits.
533                tail &= !((1 << SHIFT) - 1);
534                head &= !((1 << SHIFT) - 1);
535
536                // Fix up indices if they fall onto block ends.
537                if (tail >> SHIFT) & (LAP - 1) == LAP - 1 {
538                    tail = tail.wrapping_add(1 << SHIFT);
539                }
540                if (head >> SHIFT) & (LAP - 1) == LAP - 1 {
541                    head = head.wrapping_add(1 << SHIFT);
542                }
543
544                // Rotate indices so that head falls into the first block.
545                let lap = (head >> SHIFT) / LAP;
546                tail = tail.wrapping_sub((lap * LAP) << SHIFT);
547                head = head.wrapping_sub((lap * LAP) << SHIFT);
548
549                // Remove the lower bits.
550                tail >>= SHIFT;
551                head >>= SHIFT;
552
553                // Return the difference minus the number of blocks between tail and head.
554                return (tail - head - tail / LAP) as usize;
555            }
556        }
557    }
558
559    /// Returns the capacity of the channel.
560    pub(crate) fn capacity(&self) -> Option<usize> {
561        None
562    }
563
564    /// Disconnects senders and wakes up all blocked receivers.
565    ///
566    /// Returns `true` if this call disconnected the channel.
567    pub(crate) fn disconnect_senders(&self) -> bool {
568        let tail = self.tail.index.fetch_or(MARK_BIT, Ordering::SeqCst);
569
570        if tail & MARK_BIT == 0 {
571            self.receivers.disconnect();
572            true
573        } else {
574            false
575        }
576    }
577
578    /// Disconnects receivers.
579    ///
580    /// Returns `true` if this call disconnected the channel.
581    pub(crate) fn disconnect_receivers(&self) -> bool {
582        let tail = self.tail.index.fetch_or(MARK_BIT, Ordering::SeqCst);
583
584        if tail & MARK_BIT == 0 {
585            // If receivers are dropped first, discard all messages to free
586            // memory eagerly.
587            self.discard_all_messages();
588            true
589        } else {
590            false
591        }
592    }
593
594    /// Discards all messages.
595    ///
596    /// This method should only be called when all receivers are dropped.
597    fn discard_all_messages(&self) {
598        let backoff = Backoff::new();
599        let mut tail = self.tail.index.load(Ordering::Acquire);
600        loop {
601            let offset = ((tail >> SHIFT) % LAP) as usize;
602            if offset != BLOCK_CAP {
603                break;
604            }
605
606            // New updates to tail will be rejected by MARK_BIT and aborted unless it's
607            // at boundary. We need to wait for the updates take affect otherwise there
608            // can be memory leaks.
609            backoff.snooze();
610            tail = self.tail.index.load(Ordering::Acquire);
611        }
612
613        let mut head = self.head.index.load(Ordering::Acquire);
614        // The channel may be uninitialized, so we have to swap to avoid overwriting any sender's attempts
615        // to initialize the first block before noticing that the receivers disconnected. Late allocations
616        // will be deallocated by the sender in Drop
617        let mut block = self.head.block.swap(ptr::null_mut(), Ordering::AcqRel);
618
619        // If we're going to be dropping messages we need to synchronize with initialization
620        if head >> SHIFT != tail >> SHIFT {
621            // The block can be null here only if a sender is in the process of initializing the
622            // channel while another sender managed to send a message by inserting it into the
623            // semi-initialized channel and advanced the tail.
624            // In that case, just wait until it gets initialized.
625            while block.is_null() {
626                backoff.snooze();
627                block = self.head.block.swap(ptr::null_mut(), Ordering::AcqRel);
628            }
629        }
630
631        unsafe {
632            // Drop all messages between head and tail and deallocate the heap-allocated blocks.
633            while head >> SHIFT != tail >> SHIFT {
634                let offset = ((head >> SHIFT) % LAP) as usize;
635
636                if offset < BLOCK_CAP {
637                    // Drop the message in the slot.
638                    let slot = (*block).slots.get_unchecked(offset);
639                    slot.wait_write();
640                    (*slot.msg.get()).assume_init_drop();
641                } else {
642                    (*block).wait_next();
643                    // Deallocate the block and move to the next one.
644                    let next = (*block).next.load(Ordering::Acquire);
645                    drop(Box::from_raw(block));
646                    block = next;
647                }
648
649                head = head.wrapping_add(1 << SHIFT);
650            }
651
652            // Deallocate the last remaining block.
653            if !block.is_null() {
654                drop(Box::from_raw(block));
655            }
656        }
657        head &= !MARK_BIT;
658        self.head.index.store(head, Ordering::Release);
659    }
660
661    /// Returns `true` if the channel is disconnected.
662    pub(crate) fn is_disconnected(&self) -> bool {
663        self.tail.index.load(Ordering::SeqCst) & MARK_BIT != 0
664    }
665
666    /// Returns `true` if the channel is empty.
667    pub(crate) fn is_empty(&self) -> bool {
668        let head = self.head.index.load(Ordering::SeqCst);
669        let tail = self.tail.index.load(Ordering::SeqCst);
670        head >> SHIFT == tail >> SHIFT
671    }
672
673    /// Returns `true` if the channel is full.
674    pub(crate) fn is_full(&self) -> bool {
675        false
676    }
677}
678
679impl<T> Drop for Channel<T> {
680    fn drop(&mut self) {
681        let mut head = *self.head.index.get_mut();
682        let mut tail = *self.tail.index.get_mut();
683        let mut block = *self.head.block.get_mut();
684
685        // Erase the lower bits.
686        head &= !((1 << SHIFT) - 1);
687        tail &= !((1 << SHIFT) - 1);
688
689        unsafe {
690            // Drop all messages between head and tail and deallocate the heap-allocated blocks.
691            while head != tail {
692                let offset = ((head >> SHIFT) % LAP) as usize;
693
694                if offset < BLOCK_CAP {
695                    // Drop the message in the slot.
696                    let slot = (*block).slots.get_unchecked_mut(offset);
697                    if *slot.state.get_mut() & WRITE != 0 {
698                        (*slot.msg.get()).assume_init_drop();
699                    }
700                } else {
701                    // Deallocate the block and move to the next one.
702                    let next = *(*block).next.get_mut();
703                    drop(Box::from_raw(block));
704                    block = next;
705                }
706
707                head = head.wrapping_add(1 << SHIFT);
708            }
709
710            // Deallocate the last remaining block.
711            if !block.is_null() {
712                drop(Box::from_raw(block));
713            }
714        }
715    }
716}
717
718/// Receiver handle to a channel.
719pub(crate) struct Receiver<'a, T>(&'a Channel<T>);
720
721/// Sender handle to a channel.
722pub(crate) struct Sender<'a, T>(&'a Channel<T>);
723
724impl<T> SelectHandle for Receiver<'_, T> {
725    fn try_select(&self, token: &mut Token) -> bool {
726        self.0.start_recv(token)
727    }
728
729    fn deadline(&self) -> Option<Instant> {
730        None
731    }
732
733    fn register(&self, oper: Operation, cx: &Context) -> bool {
734        self.0.receivers.register(oper, cx);
735        self.is_ready()
736    }
737
738    fn unregister(&self, oper: Operation) {
739        self.0.receivers.unregister(oper);
740    }
741
742    fn accept(&self, token: &mut Token, _cx: &Context) -> bool {
743        self.try_select(token)
744    }
745
746    fn is_ready(&self) -> bool {
747        !self.0.is_empty() || self.0.is_disconnected()
748    }
749
750    fn watch(&self, oper: Operation, cx: &Context) -> bool {
751        self.0.receivers.watch(oper, cx);
752        self.is_ready()
753    }
754
755    fn unwatch(&self, oper: Operation) {
756        self.0.receivers.unwatch(oper);
757    }
758}
759
760impl<T> SelectHandle for Sender<'_, T> {
761    fn try_select(&self, token: &mut Token) -> bool {
762        self.0.start_send(token)
763    }
764
765    fn deadline(&self) -> Option<Instant> {
766        None
767    }
768
769    fn register(&self, _oper: Operation, _cx: &Context) -> bool {
770        self.is_ready()
771    }
772
773    fn unregister(&self, _oper: Operation) {}
774
775    fn accept(&self, token: &mut Token, _cx: &Context) -> bool {
776        self.try_select(token)
777    }
778
779    fn is_ready(&self) -> bool {
780        true
781    }
782
783    fn watch(&self, _oper: Operation, _cx: &Context) -> bool {
784        self.is_ready()
785    }
786
787    fn unwatch(&self, _oper: Operation) {}
788}