use std::fmt; use std::process; use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release}; use std::task::Poll::{Pending, Ready}; use std::task::{Context, Poll};
/// Fields only accessed by `Rx` handle. struct RxFields<T> { /// Channel receiver. This field is only accessed by the `Receiver` type.
list: list::Rx<T>,
/// `true` if `Rx::close` is called.
rx_closed: bool,
}
pub(crate) asyncfn closed(&self) { // In order to avoid a race condition, we first request a notification, // **then** check whether the semaphore is closed. If the semaphore is // closed the notification request is dropped. let notified = self.inner.notify_rx_closed.notified();
impl<T, S> Clone for Tx<T, S> { fn clone(&self) -> Tx<T, S> { // Using a Relaxed ordering here is sufficient as the caller holds a // strong ref to `self`, preventing a concurrent decrement to zero. self.inner.tx_count.fetch_add(1, Relaxed);
Tx {
inner: self.inner.clone(),
}
}
}
impl<T, S> Drop for Tx<T, S> { fn drop(&mutself) { ifself.inner.tx_count.fetch_sub(1, AcqRel) != 1 { return;
}
// Close the list, which sends a `Close` message self.inner.tx.close();
pub(crate) fn is_closed(&self) -> bool { // There two internal states that can represent a closed channel // // 1. When `close` is called. // In this case, the inner semaphore will be closed. // // 2. When all senders are dropped. // In this case, the semaphore remains unclosed, and the `index` in the list won't // reach the tail position. It is necessary to check the list if the last block is // `closed`. self.inner.semaphore.is_closed() || self.inner.tx_count.load(Acquire) == 0
}
/// Receive the next value pub(crate) fn recv(&mutself, cx: &mut Context<'_>) -> Poll<Option<T>> { usesuper::block::Read;
ready!(crate::trace::trace_leaf(cx));
// Keep track of task budget let coop = ready!(crate::runtime::coop::poll_proceed(cx));
self.inner.rx_fields.with_mut(|rx_fields_ptr| { let rx_fields = unsafe { &mut *rx_fields_ptr };
macro_rules! try_recv {
() => { match rx_fields.list.pop(&self.inner.tx) {
Some(Read::Value(value)) => { self.inner.semaphore.add_permit();
coop.made_progress(); return Ready(Some(value));
}
Some(Read::Closed) => { // TODO: This check may not be required as it most // likely can only return `true` at this point. A // channel is closed when all tx handles are // dropped. Dropping a tx handle releases memory, // which ensures that if dropping the tx handle is // visible, then all messages sent are also visible.
assert!(self.inner.semaphore.is_idle());
coop.made_progress(); return Ready(None);
}
None => {} // fall through
}
};
}
try_recv!();
self.inner.rx_waker.register_by_ref(cx.waker());
// It is possible that a value was pushed between attempting to read // and registering the task, so we have to check the channel a // second time here.
try_recv!();
Some(Read::Closed) => { let number_added = buffer.len() - initial_length; if number_added > 0 { self.inner.semaphore.add_permits(number_added);
} // TODO: This check may not be required as it most // likely can only return `true` at this point. A // channel is closed when all tx handles are // dropped. Dropping a tx handle releases memory, // which ensures that if dropping the tx handle is // visible, then all messages sent are also visible.
assert!(self.inner.semaphore.is_idle());
coop.made_progress(); return Ready(number_added);
}
None => { break; // fall through
}
}
} let number_added = buffer.len() - initial_length; if number_added > 0 { self.inner.semaphore.add_permits(number_added);
coop.made_progress(); return Ready(number_added);
}
};
}
try_recv!();
self.inner.rx_waker.register_by_ref(cx.waker());
// It is possible that a value was pushed between attempting to read // and registering the task, so we have to check the channel a // second time here.
try_recv!();
// If a previous `poll_recv` call has set a waker, we wake it here. // This allows us to put our own CachedParkThread waker in the // AtomicWaker slot instead. // // This is not a spurious wakeup to `poll_recv` since we just got a // Busy from `try_pop`, which only happens if there are messages in // the queue. self.inner.rx_waker.wake();
// Park the thread until the problematic send has completed. letmut park = CachedParkThread::new(); let waker = park.waker().unwrap(); loop { self.inner.rx_waker.register_by_ref(&waker); // It is possible that the problematic send has now completed, // so we have to check for messages again.
try_recv!();
park.park();
}
})
}
impl<T, S> Drop for Chan<T, S> { fn drop(&mutself) { usesuper::block::Read::Value;
// Safety: the only owner of the rx fields is Chan, and being // inside its own Drop means we're the last ones to touch it. self.rx_fields.with_mut(|rx_fields_ptr| { let rx_fields = unsafe { &mut *rx_fields_ptr };
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.