mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-29 00:00:11 +02:00
sync: support mpsc send with &self (#2861)
Updates the mpsc channel to use the intrusive waker based sempahore. This enables using `Sender` with `&self`. Instead of using `Sender::poll_ready` to ensure capacity and updating the `Sender` state, `async fn Sender::reserve()` is added. This function returns a `Permit` value representing the reserved capacity. Fixes: #2637 Refs: #2718 (intrusive waiters)
This commit is contained in:
@@ -200,7 +200,9 @@ impl Inner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn poll_action(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Action>> {
|
fn poll_action(&mut self, cx: &mut task::Context<'_>) -> Poll<Option<Action>> {
|
||||||
self.rx.poll_recv(cx)
|
use futures_core::stream::Stream;
|
||||||
|
|
||||||
|
Pin::new(&mut self.rx).poll_next(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&mut self, dst: &mut ReadBuf<'_>) -> io::Result<()> {
|
fn read(&mut self, dst: &mut ReadBuf<'_>) -> io::Result<()> {
|
||||||
|
|||||||
@@ -391,35 +391,7 @@ impl Signal {
|
|||||||
poll_fn(|cx| self.poll_recv(cx)).await
|
poll_fn(|cx| self.poll_recv(cx)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Polls to receive the next signal notification event, outside of an
|
pub(crate) fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
|
||||||
/// `async` context.
|
|
||||||
///
|
|
||||||
/// `None` is returned if no more events can be received by this stream.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// Polling from a manually implemented future
|
|
||||||
///
|
|
||||||
/// ```rust,no_run
|
|
||||||
/// use std::pin::Pin;
|
|
||||||
/// use std::future::Future;
|
|
||||||
/// use std::task::{Context, Poll};
|
|
||||||
/// use tokio::signal::unix::Signal;
|
|
||||||
///
|
|
||||||
/// struct MyFuture {
|
|
||||||
/// signal: Signal,
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// impl Future for MyFuture {
|
|
||||||
/// type Output = Option<()>;
|
|
||||||
///
|
|
||||||
/// fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
||||||
/// println!("polling MyFuture");
|
|
||||||
/// self.signal.poll_recv(cx)
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<()>> {
|
|
||||||
self.rx.poll_recv(cx)
|
self.rx.poll_recv(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -270,8 +270,8 @@ pub trait StreamExt: Stream {
|
|||||||
/// # #[tokio::main(basic_scheduler)]
|
/// # #[tokio::main(basic_scheduler)]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// # time::pause();
|
/// # time::pause();
|
||||||
/// let (mut tx1, rx1) = mpsc::channel(10);
|
/// let (tx1, rx1) = mpsc::channel(10);
|
||||||
/// let (mut tx2, rx2) = mpsc::channel(10);
|
/// let (tx2, rx2) = mpsc::channel(10);
|
||||||
///
|
///
|
||||||
/// let mut rx = rx1.merge(rx2);
|
/// let mut rx = rx1.merge(rx2);
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ use std::task::{Context, Poll};
|
|||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let (mut tx1, rx1) = mpsc::channel(10);
|
/// let (tx1, rx1) = mpsc::channel(10);
|
||||||
/// let (mut tx2, rx2) = mpsc::channel(10);
|
/// let (tx2, rx2) = mpsc::channel(10);
|
||||||
///
|
///
|
||||||
/// tokio::spawn(async move {
|
/// tokio::spawn(async move {
|
||||||
/// tx1.send(1).await.unwrap();
|
/// tx1.send(1).await.unwrap();
|
||||||
|
|||||||
@@ -165,7 +165,6 @@ impl Semaphore {
|
|||||||
/// permits and notifies all pending waiters.
|
/// permits and notifies all pending waiters.
|
||||||
// This will be used once the bounded MPSC is updated to use the new
|
// This will be used once the bounded MPSC is updated to use the new
|
||||||
// semaphore implementation.
|
// semaphore implementation.
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) fn close(&self) {
|
pub(crate) fn close(&self) {
|
||||||
let mut waiters = self.waiters.lock().unwrap();
|
let mut waiters = self.waiters.lock().unwrap();
|
||||||
// If the semaphore's permits counter has enough permits for an
|
// If the semaphore's permits counter has enough permits for an
|
||||||
@@ -185,6 +184,11 @@ impl Semaphore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the semaphore is closed
|
||||||
|
pub(crate) fn is_closed(&self) -> bool {
|
||||||
|
self.permits.load(Acquire) & Self::CLOSED == Self::CLOSED
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn try_acquire(&self, num_permits: u32) -> Result<(), TryAcquireError> {
|
pub(crate) fn try_acquire(&self, num_permits: u32) -> Result<(), TryAcquireError> {
|
||||||
assert!(
|
assert!(
|
||||||
num_permits as usize <= Self::MAX_PERMITS,
|
num_permits as usize <= Self::MAX_PERMITS,
|
||||||
@@ -194,8 +198,8 @@ impl Semaphore {
|
|||||||
let num_permits = (num_permits as usize) << Self::PERMIT_SHIFT;
|
let num_permits = (num_permits as usize) << Self::PERMIT_SHIFT;
|
||||||
let mut curr = self.permits.load(Acquire);
|
let mut curr = self.permits.load(Acquire);
|
||||||
loop {
|
loop {
|
||||||
// Has the semaphore closed?git
|
// Has the semaphore closed?
|
||||||
if curr & Self::CLOSED > 0 {
|
if curr & Self::CLOSED == Self::CLOSED {
|
||||||
return Err(TryAcquireError::Closed);
|
return Err(TryAcquireError::Closed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,7 @@
|
|||||||
//!
|
//!
|
||||||
//! #[tokio::main]
|
//! #[tokio::main]
|
||||||
//! async fn main() {
|
//! async fn main() {
|
||||||
//! let (mut tx, mut rx) = mpsc::channel(100);
|
//! let (tx, mut rx) = mpsc::channel(100);
|
||||||
//!
|
//!
|
||||||
//! tokio::spawn(async move {
|
//! tokio::spawn(async move {
|
||||||
//! for i in 0..10 {
|
//! for i in 0..10 {
|
||||||
@@ -150,7 +150,7 @@
|
|||||||
//! for _ in 0..10 {
|
//! for _ in 0..10 {
|
||||||
//! // Each task needs its own `tx` handle. This is done by cloning the
|
//! // Each task needs its own `tx` handle. This is done by cloning the
|
||||||
//! // original handle.
|
//! // original handle.
|
||||||
//! let mut tx = tx.clone();
|
//! let tx = tx.clone();
|
||||||
//!
|
//!
|
||||||
//! tokio::spawn(async move {
|
//! tokio::spawn(async move {
|
||||||
//! tx.send(&b"data to write"[..]).await.unwrap();
|
//! tx.send(&b"data to write"[..]).await.unwrap();
|
||||||
@@ -213,7 +213,7 @@
|
|||||||
//!
|
//!
|
||||||
//! // Spawn tasks that will send the increment command.
|
//! // Spawn tasks that will send the increment command.
|
||||||
//! for _ in 0..10 {
|
//! for _ in 0..10 {
|
||||||
//! let mut cmd_tx = cmd_tx.clone();
|
//! let cmd_tx = cmd_tx.clone();
|
||||||
//!
|
//!
|
||||||
//! join_handles.push(tokio::spawn(async move {
|
//! join_handles.push(tokio::spawn(async move {
|
||||||
//! let (resp_tx, resp_rx) = oneshot::channel();
|
//! let (resp_tx, resp_rx) = oneshot::channel();
|
||||||
@@ -443,7 +443,6 @@ cfg_sync! {
|
|||||||
pub mod oneshot;
|
pub mod oneshot;
|
||||||
|
|
||||||
pub(crate) mod batch_semaphore;
|
pub(crate) mod batch_semaphore;
|
||||||
pub(crate) mod semaphore_ll;
|
|
||||||
mod semaphore;
|
mod semaphore;
|
||||||
pub use semaphore::{Semaphore, SemaphorePermit, OwnedSemaphorePermit};
|
pub use semaphore::{Semaphore, SemaphorePermit, OwnedSemaphorePermit};
|
||||||
|
|
||||||
@@ -473,7 +472,7 @@ cfg_not_sync! {
|
|||||||
|
|
||||||
cfg_signal_internal! {
|
cfg_signal_internal! {
|
||||||
pub(crate) mod mpsc;
|
pub(crate) mod mpsc;
|
||||||
pub(crate) mod semaphore_ll;
|
pub(crate) mod batch_semaphore;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+212
-144
@@ -1,6 +1,6 @@
|
|||||||
|
use crate::sync::batch_semaphore::{self as semaphore, TryAcquireError};
|
||||||
use crate::sync::mpsc::chan;
|
use crate::sync::mpsc::chan;
|
||||||
use crate::sync::mpsc::error::{ClosedError, SendError, TryRecvError, TrySendError};
|
use crate::sync::mpsc::error::{SendError, TryRecvError, TrySendError};
|
||||||
use crate::sync::semaphore_ll as semaphore;
|
|
||||||
|
|
||||||
cfg_time! {
|
cfg_time! {
|
||||||
use crate::sync::mpsc::error::SendTimeoutError;
|
use crate::sync::mpsc::error::SendTimeoutError;
|
||||||
@@ -8,6 +8,7 @@ cfg_time! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
#[cfg(any(feature = "signal", feature = "process", feature = "stream"))]
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
/// Send values to the associated `Receiver`.
|
/// Send values to the associated `Receiver`.
|
||||||
@@ -17,20 +18,14 @@ pub struct Sender<T> {
|
|||||||
chan: chan::Tx<T, Semaphore>,
|
chan: chan::Tx<T, Semaphore>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Clone for Sender<T> {
|
/// Permit to send one value into the channel.
|
||||||
fn clone(&self) -> Self {
|
///
|
||||||
Sender {
|
/// `Permit` values are returned by [`Sender::reserve()`] and are used to
|
||||||
chan: self.chan.clone(),
|
/// guarantee channel capacity before generating a message to send.
|
||||||
}
|
///
|
||||||
}
|
/// [`Sender::reserve()`]: Sender::reserve
|
||||||
}
|
pub struct Permit<'a, T> {
|
||||||
|
chan: &'a chan::Tx<T, Semaphore>,
|
||||||
impl<T> fmt::Debug for Sender<T> {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
fmt.debug_struct("Sender")
|
|
||||||
.field("chan", &self.chan)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receive values from the associated `Sender`.
|
/// Receive values from the associated `Sender`.
|
||||||
@@ -41,14 +36,6 @@ pub struct Receiver<T> {
|
|||||||
chan: chan::Rx<T, Semaphore>,
|
chan: chan::Rx<T, Semaphore>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> fmt::Debug for Receiver<T> {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
fmt.debug_struct("Receiver")
|
|
||||||
.field("chan", &self.chan)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a bounded mpsc channel for communicating between asynchronous tasks
|
/// Creates a bounded mpsc channel for communicating between asynchronous tasks
|
||||||
/// with backpressure.
|
/// with backpressure.
|
||||||
///
|
///
|
||||||
@@ -77,7 +64,7 @@ impl<T> fmt::Debug for Receiver<T> {
|
|||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let (mut tx, mut rx) = mpsc::channel(100);
|
/// let (tx, mut rx) = mpsc::channel(100);
|
||||||
///
|
///
|
||||||
/// tokio::spawn(async move {
|
/// tokio::spawn(async move {
|
||||||
/// for i in 0..10 {
|
/// for i in 0..10 {
|
||||||
@@ -125,7 +112,7 @@ impl<T> Receiver<T> {
|
|||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let (mut tx, mut rx) = mpsc::channel(100);
|
/// let (tx, mut rx) = mpsc::channel(100);
|
||||||
///
|
///
|
||||||
/// tokio::spawn(async move {
|
/// tokio::spawn(async move {
|
||||||
/// tx.send("hello").await.unwrap();
|
/// tx.send("hello").await.unwrap();
|
||||||
@@ -143,7 +130,7 @@ impl<T> Receiver<T> {
|
|||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let (mut tx, mut rx) = mpsc::channel(100);
|
/// let (tx, mut rx) = mpsc::channel(100);
|
||||||
///
|
///
|
||||||
/// tx.send("hello").await.unwrap();
|
/// tx.send("hello").await.unwrap();
|
||||||
/// tx.send("world").await.unwrap();
|
/// tx.send("world").await.unwrap();
|
||||||
@@ -154,12 +141,11 @@ impl<T> Receiver<T> {
|
|||||||
/// ```
|
/// ```
|
||||||
pub async fn recv(&mut self) -> Option<T> {
|
pub async fn recv(&mut self) -> Option<T> {
|
||||||
use crate::future::poll_fn;
|
use crate::future::poll_fn;
|
||||||
|
poll_fn(|cx| self.chan.recv(cx)).await
|
||||||
poll_fn(|cx| self.poll_recv(cx)).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)] // TODO: document
|
#[cfg(any(feature = "signal", feature = "process"))]
|
||||||
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
pub(crate) fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
||||||
self.chan.recv(cx)
|
self.chan.recv(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +164,7 @@ impl<T> Receiver<T> {
|
|||||||
/// use tokio::sync::mpsc;
|
/// use tokio::sync::mpsc;
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let (mut tx, mut rx) = mpsc::channel::<u8>(10);
|
/// let (tx, mut rx) = mpsc::channel::<u8>(10);
|
||||||
///
|
///
|
||||||
/// let sync_code = thread::spawn(move || {
|
/// let sync_code = thread::spawn(move || {
|
||||||
/// assert_eq!(Some(10), rx.blocking_recv());
|
/// assert_eq!(Some(10), rx.blocking_recv());
|
||||||
@@ -215,12 +201,53 @@ impl<T> Receiver<T> {
|
|||||||
/// Closes the receiving half of a channel, without dropping it.
|
/// Closes the receiving half of a channel, without dropping it.
|
||||||
///
|
///
|
||||||
/// This prevents any further messages from being sent on the channel while
|
/// This prevents any further messages from being sent on the channel while
|
||||||
/// still enabling the receiver to drain messages that are buffered.
|
/// still enabling the receiver to drain messages that are buffered. Any
|
||||||
|
/// outstanding [`Permit`] values will still be able to send messages.
|
||||||
|
///
|
||||||
|
/// In order to guarantee no messages are dropped, after calling `close()`,
|
||||||
|
/// `recv()` must be called until `None` is returned.
|
||||||
|
///
|
||||||
|
/// [`Permit`]: Permit
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use tokio::sync::mpsc;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() {
|
||||||
|
/// let (tx, mut rx) = mpsc::channel(20);
|
||||||
|
///
|
||||||
|
/// tokio::spawn(async move {
|
||||||
|
/// let mut i = 0;
|
||||||
|
/// while let Ok(permit) = tx.reserve().await {
|
||||||
|
/// permit.send(i);
|
||||||
|
/// i += 1;
|
||||||
|
/// }
|
||||||
|
/// });
|
||||||
|
///
|
||||||
|
/// rx.close();
|
||||||
|
///
|
||||||
|
/// while let Some(msg) = rx.recv().await {
|
||||||
|
/// println!("got {}", msg);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Channel closed and no messages are lost.
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn close(&mut self) {
|
pub fn close(&mut self) {
|
||||||
self.chan.close();
|
self.chan.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> fmt::Debug for Receiver<T> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt.debug_struct("Receiver")
|
||||||
|
.field("chan", &self.chan)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Unpin for Receiver<T> {}
|
impl<T> Unpin for Receiver<T> {}
|
||||||
|
|
||||||
cfg_stream! {
|
cfg_stream! {
|
||||||
@@ -228,7 +255,7 @@ cfg_stream! {
|
|||||||
type Item = T;
|
type Item = T;
|
||||||
|
|
||||||
fn poll_next(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
fn poll_next(mut self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
||||||
self.poll_recv(cx)
|
self.chan.recv(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,7 +294,7 @@ impl<T> Sender<T> {
|
|||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let (mut tx, mut rx) = mpsc::channel(1);
|
/// let (tx, mut rx) = mpsc::channel(1);
|
||||||
///
|
///
|
||||||
/// tokio::spawn(async move {
|
/// tokio::spawn(async move {
|
||||||
/// for i in 0..10 {
|
/// for i in 0..10 {
|
||||||
@@ -283,17 +310,13 @@ impl<T> Sender<T> {
|
|||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn send(&mut self, value: T) -> Result<(), SendError<T>> {
|
pub async fn send(&self, value: T) -> Result<(), SendError<T>> {
|
||||||
use crate::future::poll_fn;
|
match self.reserve().await {
|
||||||
|
Ok(permit) => {
|
||||||
if poll_fn(|cx| self.poll_ready(cx)).await.is_err() {
|
permit.send(value);
|
||||||
return Err(SendError(value));
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Err(_) => Err(SendError(value)),
|
||||||
match self.try_send(value) {
|
|
||||||
Ok(()) => Ok(()),
|
|
||||||
Err(TrySendError::Full(_)) => unreachable!(),
|
|
||||||
Err(TrySendError::Closed(value)) => Err(SendError(value)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,9 +327,6 @@ impl<T> Sender<T> {
|
|||||||
/// with [`send`], this function has two failure cases instead of one (one for
|
/// with [`send`], this function has two failure cases instead of one (one for
|
||||||
/// disconnection, one for a full buffer).
|
/// disconnection, one for a full buffer).
|
||||||
///
|
///
|
||||||
/// This function may be paired with [`poll_ready`] in order to wait for
|
|
||||||
/// channel capacity before trying to send a value.
|
|
||||||
///
|
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// If the channel capacity has been reached, i.e., the channel has `n`
|
/// If the channel capacity has been reached, i.e., the channel has `n`
|
||||||
@@ -318,7 +338,6 @@ impl<T> Sender<T> {
|
|||||||
/// an error. The error includes the value passed to `send`.
|
/// an error. The error includes the value passed to `send`.
|
||||||
///
|
///
|
||||||
/// [`send`]: Sender::send
|
/// [`send`]: Sender::send
|
||||||
/// [`poll_ready`]: Sender::poll_ready
|
|
||||||
/// [`channel`]: channel
|
/// [`channel`]: channel
|
||||||
/// [`close`]: Receiver::close
|
/// [`close`]: Receiver::close
|
||||||
///
|
///
|
||||||
@@ -330,8 +349,8 @@ impl<T> Sender<T> {
|
|||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// // Create a channel with buffer size 1
|
/// // Create a channel with buffer size 1
|
||||||
/// let (mut tx1, mut rx) = mpsc::channel(1);
|
/// let (tx1, mut rx) = mpsc::channel(1);
|
||||||
/// let mut tx2 = tx1.clone();
|
/// let tx2 = tx1.clone();
|
||||||
///
|
///
|
||||||
/// tokio::spawn(async move {
|
/// tokio::spawn(async move {
|
||||||
/// tx1.send(1).await.unwrap();
|
/// tx1.send(1).await.unwrap();
|
||||||
@@ -359,8 +378,15 @@ impl<T> Sender<T> {
|
|||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn try_send(&mut self, message: T) -> Result<(), TrySendError<T>> {
|
pub fn try_send(&self, message: T) -> Result<(), TrySendError<T>> {
|
||||||
self.chan.try_send(message)?;
|
match self.chan.semaphore().0.try_acquire(1) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(TryAcquireError::Closed) => return Err(TrySendError::Closed(message)),
|
||||||
|
Err(TryAcquireError::NoPermits) => return Err(TrySendError::Full(message)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the message
|
||||||
|
self.chan.send(message);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,7 +418,7 @@ impl<T> Sender<T> {
|
|||||||
///
|
///
|
||||||
/// #[tokio::main]
|
/// #[tokio::main]
|
||||||
/// async fn main() {
|
/// async fn main() {
|
||||||
/// let (mut tx, mut rx) = mpsc::channel(1);
|
/// let (tx, mut rx) = mpsc::channel(1);
|
||||||
///
|
///
|
||||||
/// tokio::spawn(async move {
|
/// tokio::spawn(async move {
|
||||||
/// for i in 0..10 {
|
/// for i in 0..10 {
|
||||||
@@ -412,27 +438,22 @@ impl<T> Sender<T> {
|
|||||||
#[cfg(feature = "time")]
|
#[cfg(feature = "time")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "time")))]
|
||||||
pub async fn send_timeout(
|
pub async fn send_timeout(
|
||||||
&mut self,
|
&self,
|
||||||
value: T,
|
value: T,
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
) -> Result<(), SendTimeoutError<T>> {
|
) -> Result<(), SendTimeoutError<T>> {
|
||||||
use crate::future::poll_fn;
|
let permit = match crate::time::timeout(timeout, self.reserve()).await {
|
||||||
|
|
||||||
match crate::time::timeout(timeout, poll_fn(|cx| self.poll_ready(cx))).await {
|
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return Err(SendTimeoutError::Timeout(value));
|
return Err(SendTimeoutError::Timeout(value));
|
||||||
}
|
}
|
||||||
Ok(Err(_)) => {
|
Ok(Err(_)) => {
|
||||||
return Err(SendTimeoutError::Closed(value));
|
return Err(SendTimeoutError::Closed(value));
|
||||||
}
|
}
|
||||||
Ok(_) => {}
|
Ok(Ok(permit)) => permit,
|
||||||
}
|
};
|
||||||
|
|
||||||
match self.try_send(value) {
|
permit.send(value);
|
||||||
Ok(()) => Ok(()),
|
Ok(())
|
||||||
Err(TrySendError::Full(_)) => unreachable!(),
|
|
||||||
Err(TrySendError::Closed(value)) => Err(SendTimeoutError::Closed(value)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Blocking send to call outside of asynchronous contexts.
|
/// Blocking send to call outside of asynchronous contexts.
|
||||||
@@ -450,7 +471,7 @@ impl<T> Sender<T> {
|
|||||||
/// use tokio::sync::mpsc;
|
/// use tokio::sync::mpsc;
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let (mut tx, mut rx) = mpsc::channel::<u8>(1);
|
/// let (tx, mut rx) = mpsc::channel::<u8>(1);
|
||||||
///
|
///
|
||||||
/// let sync_code = thread::spawn(move || {
|
/// let sync_code = thread::spawn(move || {
|
||||||
/// tx.blocking_send(10).unwrap();
|
/// tx.blocking_send(10).unwrap();
|
||||||
@@ -462,92 +483,139 @@ impl<T> Sender<T> {
|
|||||||
/// sync_code.join().unwrap()
|
/// sync_code.join().unwrap()
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn blocking_send(&mut self, value: T) -> Result<(), SendError<T>> {
|
pub fn blocking_send(&self, value: T) -> Result<(), SendError<T>> {
|
||||||
let mut enter_handle = crate::runtime::enter::enter(false);
|
let mut enter_handle = crate::runtime::enter::enter(false);
|
||||||
enter_handle.block_on(self.send(value)).unwrap()
|
enter_handle.block_on(self.send(value)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `Poll::Ready(Ok(()))` when the channel is able to accept another item.
|
/// Wait for channel capacity. Once capacity to send one message is
|
||||||
|
/// available, it is reserved for the caller.
|
||||||
///
|
///
|
||||||
/// If the channel is full, then `Poll::Pending` is returned and the task is notified when a
|
/// If the channel is full, the function waits for the number of unreceived
|
||||||
/// slot becomes available.
|
/// messages to become less than the channel capacity. Capacity to send one
|
||||||
|
/// message is reserved for the caller. A [`Permit`] is returned to track
|
||||||
|
/// the reserved capacity. The [`send`] function on [`Permit`] consumes the
|
||||||
|
/// reserved capacity.
|
||||||
///
|
///
|
||||||
/// Once `poll_ready` returns `Poll::Ready(Ok(()))`, a call to `try_send` will succeed unless
|
/// Dropping [`Permit`] without sending a message releases the capacity back
|
||||||
/// the channel has since been closed. To provide this guarantee, the channel reserves one slot
|
/// to the channel.
|
||||||
/// in the channel for the coming send. This reserved slot is not available to other `Sender`
|
|
||||||
/// instances, so you need to be careful to not end up with deadlocks by blocking after calling
|
|
||||||
/// `poll_ready` but before sending an element.
|
|
||||||
///
|
///
|
||||||
/// If, after `poll_ready` succeeds, you decide you do not wish to send an item after all, you
|
/// [`Permit`]: Permit
|
||||||
/// can use [`disarm`](Sender::disarm) to release the reserved slot.
|
/// [`send`]: Permit::send
|
||||||
///
|
///
|
||||||
/// Until an item is sent or [`disarm`](Sender::disarm) is called, repeated calls to
|
/// # Examples
|
||||||
/// `poll_ready` will return either `Poll::Ready(Ok(()))` or `Poll::Ready(Err(_))` if channel
|
///
|
||||||
/// is closed.
|
/// ```
|
||||||
pub fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ClosedError>> {
|
/// use tokio::sync::mpsc;
|
||||||
self.chan.poll_ready(cx).map_err(|_| ClosedError::new())
|
///
|
||||||
}
|
/// #[tokio::main]
|
||||||
|
/// async fn main() {
|
||||||
|
/// let (tx, mut rx) = mpsc::channel(1);
|
||||||
|
///
|
||||||
|
/// // Reserve capacity
|
||||||
|
/// let permit = tx.reserve().await.unwrap();
|
||||||
|
///
|
||||||
|
/// // Trying to send directly on the `tx` will fail due to no
|
||||||
|
/// // available capacity.
|
||||||
|
/// assert!(tx.try_send(123).is_err());
|
||||||
|
///
|
||||||
|
/// // Sending on the permit succeeds
|
||||||
|
/// permit.send(456);
|
||||||
|
///
|
||||||
|
/// // The value sent on the permit is received
|
||||||
|
/// assert_eq!(rx.recv().await.unwrap(), 456);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub async fn reserve(&self) -> Result<Permit<'_, T>, SendError<()>> {
|
||||||
|
match self.chan.semaphore().0.acquire(1).await {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(_) => return Err(SendError(())),
|
||||||
|
}
|
||||||
|
|
||||||
/// Undo a successful call to `poll_ready`.
|
Ok(Permit { chan: &self.chan })
|
||||||
///
|
}
|
||||||
/// Once a call to `poll_ready` returns `Poll::Ready(Ok(()))`, it holds up one slot in the
|
}
|
||||||
/// channel to make room for the coming send. `disarm` allows you to give up that slot if you
|
|
||||||
/// decide you do not wish to send an item after all. After calling `disarm`, you must call
|
impl<T> Clone for Sender<T> {
|
||||||
/// `poll_ready` until it returns `Poll::Ready(Ok(()))` before attempting to send again.
|
fn clone(&self) -> Self {
|
||||||
///
|
Sender {
|
||||||
/// Returns `false` if no slot is reserved for this sender (usually because `poll_ready` was
|
chan: self.chan.clone(),
|
||||||
/// not previously called, or did not succeed).
|
|
||||||
///
|
|
||||||
/// # Motivation
|
|
||||||
///
|
|
||||||
/// Since `poll_ready` takes up one of the finite number of slots in a bounded channel, callers
|
|
||||||
/// need to send an item shortly after `poll_ready` succeeds. If they do not, idle senders may
|
|
||||||
/// take up all the slots of the channel, and prevent active senders from getting any requests
|
|
||||||
/// through. Consider this code that forwards from one channel to another:
|
|
||||||
///
|
|
||||||
/// ```rust,ignore
|
|
||||||
/// loop {
|
|
||||||
/// ready!(tx.poll_ready(cx))?;
|
|
||||||
/// if let Some(item) = ready!(rx.poll_recv(cx)) {
|
|
||||||
/// tx.try_send(item)?;
|
|
||||||
/// } else {
|
|
||||||
/// break;
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// If many such forwarders exist, and they all forward into a single (cloned) `Sender`, then
|
|
||||||
/// any number of forwarders may be waiting for `rx.poll_recv` at the same time. While they do,
|
|
||||||
/// they are effectively each reducing the channel's capacity by 1. If enough of these
|
|
||||||
/// forwarders are idle, forwarders whose `rx` _do_ have elements will be unable to find a spot
|
|
||||||
/// for them through `poll_ready`, and the system will deadlock.
|
|
||||||
///
|
|
||||||
/// `disarm` solves this problem by allowing you to give up the reserved slot if you find that
|
|
||||||
/// you have to block. We can then fix the code above by writing:
|
|
||||||
///
|
|
||||||
/// ```rust,ignore
|
|
||||||
/// loop {
|
|
||||||
/// ready!(tx.poll_ready(cx))?;
|
|
||||||
/// let item = rx.poll_recv(cx);
|
|
||||||
/// if let Poll::Ready(Ok(_)) = item {
|
|
||||||
/// // we're going to send the item below, so don't disarm
|
|
||||||
/// } else {
|
|
||||||
/// // give up our send slot, we won't need it for a while
|
|
||||||
/// tx.disarm();
|
|
||||||
/// }
|
|
||||||
/// if let Some(item) = ready!(item) {
|
|
||||||
/// tx.try_send(item)?;
|
|
||||||
/// } else {
|
|
||||||
/// break;
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
pub fn disarm(&mut self) -> bool {
|
|
||||||
if self.chan.is_ready() {
|
|
||||||
self.chan.disarm();
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> fmt::Debug for Sender<T> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt.debug_struct("Sender")
|
||||||
|
.field("chan", &self.chan)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== impl Permit =====
|
||||||
|
|
||||||
|
impl<T> Permit<'_, T> {
|
||||||
|
/// Sends a value using the reserved capacity.
|
||||||
|
///
|
||||||
|
/// Capacity for the message has already been reserved. The message is sent
|
||||||
|
/// to the receiver and the permit is consumed. The operation will succeed
|
||||||
|
/// even if the receiver half has been closed. See [`Receiver::close`] for
|
||||||
|
/// more details on performing a clean shutdown.
|
||||||
|
///
|
||||||
|
/// [`Receiver::close`]: Receiver::close
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use tokio::sync::mpsc;
|
||||||
|
///
|
||||||
|
/// #[tokio::main]
|
||||||
|
/// async fn main() {
|
||||||
|
/// let (tx, mut rx) = mpsc::channel(1);
|
||||||
|
///
|
||||||
|
/// // Reserve capacity
|
||||||
|
/// let permit = tx.reserve().await.unwrap();
|
||||||
|
///
|
||||||
|
/// // Trying to send directly on the `tx` will fail due to no
|
||||||
|
/// // available capacity.
|
||||||
|
/// assert!(tx.try_send(123).is_err());
|
||||||
|
///
|
||||||
|
/// // Send a message on the permit
|
||||||
|
/// permit.send(456);
|
||||||
|
///
|
||||||
|
/// // The value sent on the permit is received
|
||||||
|
/// assert_eq!(rx.recv().await.unwrap(), 456);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn send(self, value: T) {
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
self.chan.send(value);
|
||||||
|
|
||||||
|
// Avoid the drop logic
|
||||||
|
mem::forget(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Drop for Permit<'_, T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
use chan::Semaphore;
|
||||||
|
|
||||||
|
let semaphore = self.chan.semaphore();
|
||||||
|
|
||||||
|
// Add the permit back to the semaphore
|
||||||
|
semaphore.add_permit();
|
||||||
|
|
||||||
|
if semaphore.is_closed() && semaphore.is_idle() {
|
||||||
|
self.chan.wake_rx();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> fmt::Debug for Permit<'_, T> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt.debug_struct("Permit")
|
||||||
|
.field("chan", &self.chan)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+37
-235
@@ -2,8 +2,8 @@ use crate::loom::cell::UnsafeCell;
|
|||||||
use crate::loom::future::AtomicWaker;
|
use crate::loom::future::AtomicWaker;
|
||||||
use crate::loom::sync::atomic::AtomicUsize;
|
use crate::loom::sync::atomic::AtomicUsize;
|
||||||
use crate::loom::sync::Arc;
|
use crate::loom::sync::Arc;
|
||||||
use crate::sync::mpsc::error::{ClosedError, TryRecvError};
|
use crate::sync::mpsc::error::TryRecvError;
|
||||||
use crate::sync::mpsc::{error, list};
|
use crate::sync::mpsc::list;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::process;
|
use std::process;
|
||||||
@@ -12,21 +12,13 @@ use std::task::Poll::{Pending, Ready};
|
|||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
/// Channel sender
|
/// Channel sender
|
||||||
pub(crate) struct Tx<T, S: Semaphore> {
|
pub(crate) struct Tx<T, S> {
|
||||||
inner: Arc<Chan<T, S>>,
|
inner: Arc<Chan<T, S>>,
|
||||||
permit: S::Permit,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S: Semaphore> fmt::Debug for Tx<T, S>
|
impl<T, S: fmt::Debug> fmt::Debug for Tx<T, S> {
|
||||||
where
|
|
||||||
S::Permit: fmt::Debug,
|
|
||||||
S: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt.debug_struct("Tx")
|
fmt.debug_struct("Tx").field("inner", &self.inner).finish()
|
||||||
.field("inner", &self.inner)
|
|
||||||
.field("permit", &self.permit)
|
|
||||||
.finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,71 +27,20 @@ pub(crate) struct Rx<T, S: Semaphore> {
|
|||||||
inner: Arc<Chan<T, S>>,
|
inner: Arc<Chan<T, S>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S: Semaphore> fmt::Debug for Rx<T, S>
|
impl<T, S: Semaphore + fmt::Debug> fmt::Debug for Rx<T, S> {
|
||||||
where
|
|
||||||
S: fmt::Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt.debug_struct("Rx").field("inner", &self.inner).finish()
|
fmt.debug_struct("Rx").field("inner", &self.inner).finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
|
||||||
pub(crate) enum TrySendError {
|
|
||||||
Closed,
|
|
||||||
Full,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<(T, TrySendError)> for error::SendError<T> {
|
|
||||||
fn from(src: (T, TrySendError)) -> error::SendError<T> {
|
|
||||||
match src.1 {
|
|
||||||
TrySendError::Closed => error::SendError(src.0),
|
|
||||||
TrySendError::Full => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<(T, TrySendError)> for error::TrySendError<T> {
|
|
||||||
fn from(src: (T, TrySendError)) -> error::TrySendError<T> {
|
|
||||||
match src.1 {
|
|
||||||
TrySendError::Closed => error::TrySendError::Closed(src.0),
|
|
||||||
TrySendError::Full => error::TrySendError::Full(src.0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) trait Semaphore {
|
pub(crate) trait Semaphore {
|
||||||
type Permit;
|
|
||||||
|
|
||||||
fn new_permit() -> Self::Permit;
|
|
||||||
|
|
||||||
/// The permit is dropped without a value being sent. In this case, the
|
|
||||||
/// permit must be returned to the semaphore.
|
|
||||||
///
|
|
||||||
/// # Return
|
|
||||||
///
|
|
||||||
/// Returns true if the permit was acquired.
|
|
||||||
fn drop_permit(&self, permit: &mut Self::Permit) -> bool;
|
|
||||||
|
|
||||||
fn is_idle(&self) -> bool;
|
fn is_idle(&self) -> bool;
|
||||||
|
|
||||||
fn add_permit(&self);
|
fn add_permit(&self);
|
||||||
|
|
||||||
fn poll_acquire(
|
|
||||||
&self,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
permit: &mut Self::Permit,
|
|
||||||
) -> Poll<Result<(), ClosedError>>;
|
|
||||||
|
|
||||||
fn try_acquire(&self, permit: &mut Self::Permit) -> Result<(), TrySendError>;
|
|
||||||
|
|
||||||
/// A value was sent into the channel and the permit held by `tx` is
|
|
||||||
/// dropped. In this case, the permit should not immeditely be returned to
|
|
||||||
/// the semaphore. Instead, the permit is returnred to the semaphore once
|
|
||||||
/// the sent value is read by the rx handle.
|
|
||||||
fn forget(&self, permit: &mut Self::Permit);
|
|
||||||
|
|
||||||
fn close(&self);
|
fn close(&self);
|
||||||
|
|
||||||
|
fn is_closed(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Chan<T, S> {
|
struct Chan<T, S> {
|
||||||
@@ -157,10 +98,7 @@ impl<T> fmt::Debug for RxFields<T> {
|
|||||||
unsafe impl<T: Send, S: Send> Send for Chan<T, S> {}
|
unsafe impl<T: Send, S: Send> Send for Chan<T, S> {}
|
||||||
unsafe impl<T: Send, S: Sync> Sync for Chan<T, S> {}
|
unsafe impl<T: Send, S: Sync> Sync for Chan<T, S> {}
|
||||||
|
|
||||||
pub(crate) fn channel<T, S>(semaphore: S) -> (Tx<T, S>, Rx<T, S>)
|
pub(crate) fn channel<T, S: Semaphore>(semaphore: S) -> (Tx<T, S>, Rx<T, S>) {
|
||||||
where
|
|
||||||
S: Semaphore,
|
|
||||||
{
|
|
||||||
let (tx, rx) = list::channel();
|
let (tx, rx) = list::channel();
|
||||||
|
|
||||||
let chan = Arc::new(Chan {
|
let chan = Arc::new(Chan {
|
||||||
@@ -179,48 +117,27 @@ where
|
|||||||
|
|
||||||
// ===== impl Tx =====
|
// ===== impl Tx =====
|
||||||
|
|
||||||
impl<T, S> Tx<T, S>
|
impl<T, S> Tx<T, S> {
|
||||||
where
|
|
||||||
S: Semaphore,
|
|
||||||
{
|
|
||||||
fn new(chan: Arc<Chan<T, S>>) -> Tx<T, S> {
|
fn new(chan: Arc<Chan<T, S>>) -> Tx<T, S> {
|
||||||
Tx {
|
Tx { inner: chan }
|
||||||
inner: chan,
|
|
||||||
permit: S::new_permit(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), ClosedError>> {
|
pub(super) fn semaphore(&self) -> &S {
|
||||||
self.inner.semaphore.poll_acquire(cx, &mut self.permit)
|
&self.inner.semaphore
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn disarm(&mut self) {
|
|
||||||
// TODO: should this error if not acquired?
|
|
||||||
self.inner.semaphore.drop_permit(&mut self.permit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a message and notify the receiver.
|
/// Send a message and notify the receiver.
|
||||||
pub(crate) fn try_send(&mut self, value: T) -> Result<(), (T, TrySendError)> {
|
pub(crate) fn send(&self, value: T) {
|
||||||
self.inner.try_send(value, &mut self.permit)
|
self.inner.send(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wake the receive half
|
||||||
|
pub(crate) fn wake_rx(&self) {
|
||||||
|
self.inner.rx_waker.wake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Tx<T, (crate::sync::semaphore_ll::Semaphore, usize)> {
|
impl<T, S> Clone for Tx<T, S> {
|
||||||
pub(crate) fn is_ready(&self) -> bool {
|
|
||||||
self.permit.is_acquired()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Tx<T, AtomicUsize> {
|
|
||||||
pub(crate) fn send_unbounded(&self, value: T) -> Result<(), (T, TrySendError)> {
|
|
||||||
self.inner.try_send(value, &mut ())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, S> Clone for Tx<T, S>
|
|
||||||
where
|
|
||||||
S: Semaphore,
|
|
||||||
{
|
|
||||||
fn clone(&self) -> Tx<T, S> {
|
fn clone(&self) -> Tx<T, S> {
|
||||||
// Using a Relaxed ordering here is sufficient as the caller holds a
|
// Using a Relaxed ordering here is sufficient as the caller holds a
|
||||||
// strong ref to `self`, preventing a concurrent decrement to zero.
|
// strong ref to `self`, preventing a concurrent decrement to zero.
|
||||||
@@ -228,22 +145,12 @@ where
|
|||||||
|
|
||||||
Tx {
|
Tx {
|
||||||
inner: self.inner.clone(),
|
inner: self.inner.clone(),
|
||||||
permit: S::new_permit(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> Drop for Tx<T, S>
|
impl<T, S> Drop for Tx<T, S> {
|
||||||
where
|
|
||||||
S: Semaphore,
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let notify = self.inner.semaphore.drop_permit(&mut self.permit);
|
|
||||||
|
|
||||||
if notify && self.inner.semaphore.is_idle() {
|
|
||||||
self.inner.rx_waker.wake();
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.inner.tx_count.fetch_sub(1, AcqRel) != 1 {
|
if self.inner.tx_count.fetch_sub(1, AcqRel) != 1 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -252,16 +159,13 @@ where
|
|||||||
self.inner.tx.close();
|
self.inner.tx.close();
|
||||||
|
|
||||||
// Notify the receiver
|
// Notify the receiver
|
||||||
self.inner.rx_waker.wake();
|
self.wake_rx();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== impl Rx =====
|
// ===== impl Rx =====
|
||||||
|
|
||||||
impl<T, S> Rx<T, S>
|
impl<T, S: Semaphore> Rx<T, S> {
|
||||||
where
|
|
||||||
S: Semaphore,
|
|
||||||
{
|
|
||||||
fn new(chan: Arc<Chan<T, S>>) -> Rx<T, S> {
|
fn new(chan: Arc<Chan<T, S>>) -> Rx<T, S> {
|
||||||
Rx { inner: chan }
|
Rx { inner: chan }
|
||||||
}
|
}
|
||||||
@@ -349,10 +253,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S> Drop for Rx<T, S>
|
impl<T, S: Semaphore> Drop for Rx<T, S> {
|
||||||
where
|
|
||||||
S: Semaphore,
|
|
||||||
{
|
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
use super::block::Read::Value;
|
use super::block::Read::Value;
|
||||||
|
|
||||||
@@ -370,25 +271,13 @@ where
|
|||||||
|
|
||||||
// ===== impl Chan =====
|
// ===== impl Chan =====
|
||||||
|
|
||||||
impl<T, S> Chan<T, S>
|
impl<T, S> Chan<T, S> {
|
||||||
where
|
fn send(&self, value: T) {
|
||||||
S: Semaphore,
|
|
||||||
{
|
|
||||||
fn try_send(&self, value: T, permit: &mut S::Permit) -> Result<(), (T, TrySendError)> {
|
|
||||||
if let Err(e) = self.semaphore.try_acquire(permit) {
|
|
||||||
return Err((value, e));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push the value
|
// Push the value
|
||||||
self.tx.push(value);
|
self.tx.push(value);
|
||||||
|
|
||||||
// Notify the rx task
|
// Notify the rx task
|
||||||
self.rx_waker.wake();
|
self.rx_waker.wake();
|
||||||
|
|
||||||
// Release the permit
|
|
||||||
self.semaphore.forget(permit);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,74 +296,24 @@ impl<T, S> Drop for Chan<T, S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::sync::semaphore_ll::TryAcquireError;
|
|
||||||
|
|
||||||
impl From<TryAcquireError> for TrySendError {
|
|
||||||
fn from(src: TryAcquireError) -> TrySendError {
|
|
||||||
if src.is_closed() {
|
|
||||||
TrySendError::Closed
|
|
||||||
} else if src.is_no_permits() {
|
|
||||||
TrySendError::Full
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===== impl Semaphore for (::Semaphore, capacity) =====
|
// ===== impl Semaphore for (::Semaphore, capacity) =====
|
||||||
|
|
||||||
use crate::sync::semaphore_ll::Permit;
|
impl Semaphore for (crate::sync::batch_semaphore::Semaphore, usize) {
|
||||||
|
|
||||||
impl Semaphore for (crate::sync::semaphore_ll::Semaphore, usize) {
|
|
||||||
type Permit = Permit;
|
|
||||||
|
|
||||||
fn new_permit() -> Permit {
|
|
||||||
Permit::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn drop_permit(&self, permit: &mut Permit) -> bool {
|
|
||||||
let ret = permit.is_acquired();
|
|
||||||
permit.release(1, &self.0);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_permit(&self) {
|
fn add_permit(&self) {
|
||||||
self.0.add_permits(1)
|
self.0.release(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_idle(&self) -> bool {
|
fn is_idle(&self) -> bool {
|
||||||
self.0.available_permits() == self.1
|
self.0.available_permits() == self.1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_acquire(
|
|
||||||
&self,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
permit: &mut Permit,
|
|
||||||
) -> Poll<Result<(), ClosedError>> {
|
|
||||||
// Keep track of task budget
|
|
||||||
let coop = ready!(crate::coop::poll_proceed(cx));
|
|
||||||
|
|
||||||
permit
|
|
||||||
.poll_acquire(cx, 1, &self.0)
|
|
||||||
.map_err(|_| ClosedError::new())
|
|
||||||
.map(move |r| {
|
|
||||||
coop.made_progress();
|
|
||||||
r
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_acquire(&self, permit: &mut Permit) -> Result<(), TrySendError> {
|
|
||||||
permit.try_acquire(1, &self.0)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn forget(&self, permit: &mut Self::Permit) {
|
|
||||||
permit.forget(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn close(&self) {
|
fn close(&self) {
|
||||||
self.0.close();
|
self.0.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_closed(&self) -> bool {
|
||||||
|
self.0.is_closed()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== impl Semaphore for AtomicUsize =====
|
// ===== impl Semaphore for AtomicUsize =====
|
||||||
@@ -483,14 +322,6 @@ use std::sync::atomic::Ordering::{Acquire, Release};
|
|||||||
use std::usize;
|
use std::usize;
|
||||||
|
|
||||||
impl Semaphore for AtomicUsize {
|
impl Semaphore for AtomicUsize {
|
||||||
type Permit = ();
|
|
||||||
|
|
||||||
fn new_permit() {}
|
|
||||||
|
|
||||||
fn drop_permit(&self, _permit: &mut ()) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_permit(&self) {
|
fn add_permit(&self) {
|
||||||
let prev = self.fetch_sub(2, Release);
|
let prev = self.fetch_sub(2, Release);
|
||||||
|
|
||||||
@@ -504,40 +335,11 @@ impl Semaphore for AtomicUsize {
|
|||||||
self.load(Acquire) >> 1 == 0
|
self.load(Acquire) >> 1 == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_acquire(
|
|
||||||
&self,
|
|
||||||
_cx: &mut Context<'_>,
|
|
||||||
permit: &mut (),
|
|
||||||
) -> Poll<Result<(), ClosedError>> {
|
|
||||||
Ready(self.try_acquire(permit).map_err(|_| ClosedError::new()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_acquire(&self, _permit: &mut ()) -> Result<(), TrySendError> {
|
|
||||||
let mut curr = self.load(Acquire);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if curr & 1 == 1 {
|
|
||||||
return Err(TrySendError::Closed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if curr == usize::MAX ^ 1 {
|
|
||||||
// Overflowed the ref count. There is no safe way to recover, so
|
|
||||||
// abort the process. In practice, this should never happen.
|
|
||||||
process::abort()
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.compare_exchange(curr, curr + 2, AcqRel, Acquire) {
|
|
||||||
Ok(_) => return Ok(()),
|
|
||||||
Err(actual) => {
|
|
||||||
curr = actual;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn forget(&self, _permit: &mut ()) {}
|
|
||||||
|
|
||||||
fn close(&self) {
|
fn close(&self) {
|
||||||
self.fetch_or(1, Release);
|
self.fetch_or(1, Release);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_closed(&self) -> bool {
|
||||||
|
self.load(Acquire) & 1 == 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,26 +94,6 @@ impl fmt::Display for TryRecvError {
|
|||||||
|
|
||||||
impl Error for TryRecvError {}
|
impl Error for TryRecvError {}
|
||||||
|
|
||||||
// ===== ClosedError =====
|
|
||||||
|
|
||||||
/// Error returned by [`Sender::poll_ready`](super::Sender::poll_ready).
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ClosedError(());
|
|
||||||
|
|
||||||
impl ClosedError {
|
|
||||||
pub(crate) fn new() -> ClosedError {
|
|
||||||
ClosedError(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ClosedError {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(fmt, "channel closed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for ClosedError {}
|
|
||||||
|
|
||||||
cfg_time! {
|
cfg_time! {
|
||||||
// ===== SendTimeoutError =====
|
// ===== SendTimeoutError =====
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
pub(super) mod block;
|
pub(super) mod block;
|
||||||
|
|
||||||
mod bounded;
|
mod bounded;
|
||||||
pub use self::bounded::{channel, Receiver, Sender};
|
pub use self::bounded::{channel, Permit, Receiver, Sender};
|
||||||
|
|
||||||
mod chan;
|
mod chan;
|
||||||
|
|
||||||
|
|||||||
@@ -73,8 +73,7 @@ impl<T> UnboundedReceiver<T> {
|
|||||||
UnboundedReceiver { chan }
|
UnboundedReceiver { chan }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)] // TODO: doc
|
fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
||||||
pub fn poll_recv(&mut self, cx: &mut Context<'_>) -> Poll<Option<T>> {
|
|
||||||
self.chan.recv(cx)
|
self.chan.recv(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,7 +173,41 @@ impl<T> UnboundedSender<T> {
|
|||||||
/// [`close`]: UnboundedReceiver::close
|
/// [`close`]: UnboundedReceiver::close
|
||||||
/// [`UnboundedReceiver`]: UnboundedReceiver
|
/// [`UnboundedReceiver`]: UnboundedReceiver
|
||||||
pub fn send(&self, message: T) -> Result<(), SendError<T>> {
|
pub fn send(&self, message: T) -> Result<(), SendError<T>> {
|
||||||
self.chan.send_unbounded(message)?;
|
if !self.inc_num_messages() {
|
||||||
|
return Err(SendError(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.chan.send(message);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inc_num_messages(&self) -> bool {
|
||||||
|
use std::process;
|
||||||
|
use std::sync::atomic::Ordering::{AcqRel, Acquire};
|
||||||
|
|
||||||
|
let mut curr = self.chan.semaphore().load(Acquire);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if curr & 1 == 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if curr == usize::MAX ^ 1 {
|
||||||
|
// Overflowed the ref count. There is no safe way to recover, so
|
||||||
|
// abort the process. In practice, this should never happen.
|
||||||
|
process::abort()
|
||||||
|
}
|
||||||
|
|
||||||
|
match self
|
||||||
|
.chan
|
||||||
|
.semaphore()
|
||||||
|
.compare_exchange(curr, curr + 2, AcqRel, Acquire)
|
||||||
|
{
|
||||||
|
Ok(_) => return true,
|
||||||
|
Err(actual) => {
|
||||||
|
curr = actual;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,17 +7,17 @@ use loom::thread;
|
|||||||
#[test]
|
#[test]
|
||||||
fn closing_tx() {
|
fn closing_tx() {
|
||||||
loom::model(|| {
|
loom::model(|| {
|
||||||
let (mut tx, mut rx) = mpsc::channel(16);
|
let (tx, mut rx) = mpsc::channel(16);
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
tx.try_send(()).unwrap();
|
tx.try_send(()).unwrap();
|
||||||
drop(tx);
|
drop(tx);
|
||||||
});
|
});
|
||||||
|
|
||||||
let v = block_on(poll_fn(|cx| rx.poll_recv(cx)));
|
let v = block_on(rx.recv());
|
||||||
assert!(v.is_some());
|
assert!(v.is_some());
|
||||||
|
|
||||||
let v = block_on(poll_fn(|cx| rx.poll_recv(cx)));
|
let v = block_on(rx.recv());
|
||||||
assert!(v.is_none());
|
assert!(v.is_none());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -32,10 +32,10 @@ fn closing_unbounded_tx() {
|
|||||||
drop(tx);
|
drop(tx);
|
||||||
});
|
});
|
||||||
|
|
||||||
let v = block_on(poll_fn(|cx| rx.poll_recv(cx)));
|
let v = block_on(rx.recv());
|
||||||
assert!(v.is_some());
|
assert!(v.is_some());
|
||||||
|
|
||||||
let v = block_on(poll_fn(|cx| rx.poll_recv(cx)));
|
let v = block_on(rx.recv());
|
||||||
assert!(v.is_none());
|
assert!(v.is_none());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ fn dropping_tx() {
|
|||||||
}
|
}
|
||||||
drop(tx);
|
drop(tx);
|
||||||
|
|
||||||
let v = block_on(poll_fn(|cx| rx.poll_recv(cx)));
|
let v = block_on(rx.recv());
|
||||||
assert!(v.is_none());
|
assert!(v.is_none());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ fn dropping_unbounded_tx() {
|
|||||||
}
|
}
|
||||||
drop(tx);
|
drop(tx);
|
||||||
|
|
||||||
let v = block_on(poll_fn(|cx| rx.poll_recv(cx)));
|
let v = block_on(rx.recv());
|
||||||
assert!(v.is_none());
|
assert!(v.is_none());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,192 +0,0 @@
|
|||||||
use crate::sync::semaphore_ll::*;
|
|
||||||
|
|
||||||
use futures::future::poll_fn;
|
|
||||||
use loom::future::block_on;
|
|
||||||
use loom::thread;
|
|
||||||
use std::future::Future;
|
|
||||||
use std::pin::Pin;
|
|
||||||
use std::sync::atomic::AtomicUsize;
|
|
||||||
use std::sync::atomic::Ordering::SeqCst;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::task::Poll::Ready;
|
|
||||||
use std::task::{Context, Poll};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn basic_usage() {
|
|
||||||
const NUM: usize = 2;
|
|
||||||
|
|
||||||
struct Actor {
|
|
||||||
waiter: Permit,
|
|
||||||
shared: Arc<Shared>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Shared {
|
|
||||||
semaphore: Semaphore,
|
|
||||||
active: AtomicUsize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Future for Actor {
|
|
||||||
type Output = ();
|
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
|
|
||||||
let me = &mut *self;
|
|
||||||
|
|
||||||
ready!(me.waiter.poll_acquire(cx, 1, &me.shared.semaphore)).unwrap();
|
|
||||||
|
|
||||||
let actual = me.shared.active.fetch_add(1, SeqCst);
|
|
||||||
assert!(actual <= NUM - 1);
|
|
||||||
|
|
||||||
let actual = me.shared.active.fetch_sub(1, SeqCst);
|
|
||||||
assert!(actual <= NUM);
|
|
||||||
|
|
||||||
me.waiter.release(1, &me.shared.semaphore);
|
|
||||||
|
|
||||||
Ready(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loom::model(|| {
|
|
||||||
let shared = Arc::new(Shared {
|
|
||||||
semaphore: Semaphore::new(NUM),
|
|
||||||
active: AtomicUsize::new(0),
|
|
||||||
});
|
|
||||||
|
|
||||||
for _ in 0..NUM {
|
|
||||||
let shared = shared.clone();
|
|
||||||
|
|
||||||
thread::spawn(move || {
|
|
||||||
block_on(Actor {
|
|
||||||
waiter: Permit::new(),
|
|
||||||
shared,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
block_on(Actor {
|
|
||||||
waiter: Permit::new(),
|
|
||||||
shared,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn release() {
|
|
||||||
loom::model(|| {
|
|
||||||
let semaphore = Arc::new(Semaphore::new(1));
|
|
||||||
|
|
||||||
{
|
|
||||||
let semaphore = semaphore.clone();
|
|
||||||
thread::spawn(move || {
|
|
||||||
let mut permit = Permit::new();
|
|
||||||
|
|
||||||
block_on(poll_fn(|cx| permit.poll_acquire(cx, 1, &semaphore))).unwrap();
|
|
||||||
|
|
||||||
permit.release(1, &semaphore);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut permit = Permit::new();
|
|
||||||
|
|
||||||
block_on(poll_fn(|cx| permit.poll_acquire(cx, 1, &semaphore))).unwrap();
|
|
||||||
|
|
||||||
permit.release(1, &semaphore);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn basic_closing() {
|
|
||||||
const NUM: usize = 2;
|
|
||||||
|
|
||||||
loom::model(|| {
|
|
||||||
let semaphore = Arc::new(Semaphore::new(1));
|
|
||||||
|
|
||||||
for _ in 0..NUM {
|
|
||||||
let semaphore = semaphore.clone();
|
|
||||||
|
|
||||||
thread::spawn(move || {
|
|
||||||
let mut permit = Permit::new();
|
|
||||||
|
|
||||||
for _ in 0..2 {
|
|
||||||
block_on(poll_fn(|cx| {
|
|
||||||
permit.poll_acquire(cx, 1, &semaphore).map_err(|_| ())
|
|
||||||
}))?;
|
|
||||||
|
|
||||||
permit.release(1, &semaphore);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok::<(), ()>(())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
semaphore.close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn concurrent_close() {
|
|
||||||
const NUM: usize = 3;
|
|
||||||
|
|
||||||
loom::model(|| {
|
|
||||||
let semaphore = Arc::new(Semaphore::new(1));
|
|
||||||
|
|
||||||
for _ in 0..NUM {
|
|
||||||
let semaphore = semaphore.clone();
|
|
||||||
|
|
||||||
thread::spawn(move || {
|
|
||||||
let mut permit = Permit::new();
|
|
||||||
|
|
||||||
block_on(poll_fn(|cx| {
|
|
||||||
permit.poll_acquire(cx, 1, &semaphore).map_err(|_| ())
|
|
||||||
}))?;
|
|
||||||
|
|
||||||
permit.release(1, &semaphore);
|
|
||||||
|
|
||||||
semaphore.close();
|
|
||||||
|
|
||||||
Ok::<(), ()>(())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn batch() {
|
|
||||||
let mut b = loom::model::Builder::new();
|
|
||||||
b.preemption_bound = Some(1);
|
|
||||||
|
|
||||||
b.check(|| {
|
|
||||||
let semaphore = Arc::new(Semaphore::new(10));
|
|
||||||
let active = Arc::new(AtomicUsize::new(0));
|
|
||||||
let mut ths = vec![];
|
|
||||||
|
|
||||||
for _ in 0..2 {
|
|
||||||
let semaphore = semaphore.clone();
|
|
||||||
let active = active.clone();
|
|
||||||
|
|
||||||
ths.push(thread::spawn(move || {
|
|
||||||
let mut permit = Permit::new();
|
|
||||||
|
|
||||||
for n in &[4, 10, 8] {
|
|
||||||
block_on(poll_fn(|cx| permit.poll_acquire(cx, *n, &semaphore))).unwrap();
|
|
||||||
|
|
||||||
active.fetch_add(*n as usize, SeqCst);
|
|
||||||
|
|
||||||
let num_active = active.load(SeqCst);
|
|
||||||
assert!(num_active <= 10);
|
|
||||||
|
|
||||||
thread::yield_now();
|
|
||||||
|
|
||||||
active.fetch_sub(*n as usize, SeqCst);
|
|
||||||
|
|
||||||
permit.release(*n, &semaphore);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
for th in ths.into_iter() {
|
|
||||||
th.join().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(10, semaphore.available_permits());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
cfg_not_loom! {
|
cfg_not_loom! {
|
||||||
mod atomic_waker;
|
mod atomic_waker;
|
||||||
mod semaphore_ll;
|
|
||||||
mod semaphore_batch;
|
mod semaphore_batch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12,6 +11,5 @@ cfg_loom! {
|
|||||||
mod loom_notify;
|
mod loom_notify;
|
||||||
mod loom_oneshot;
|
mod loom_oneshot;
|
||||||
mod loom_semaphore_batch;
|
mod loom_semaphore_batch;
|
||||||
mod loom_semaphore_ll;
|
|
||||||
mod loom_watch;
|
mod loom_watch;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,470 +0,0 @@
|
|||||||
use crate::sync::semaphore_ll::{Permit, Semaphore};
|
|
||||||
use tokio_test::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn poll_acquire_one_available() {
|
|
||||||
let s = Semaphore::new(100);
|
|
||||||
assert_eq!(s.available_permits(), 100);
|
|
||||||
|
|
||||||
// Polling for a permit succeeds immediately
|
|
||||||
let mut permit = task::spawn(Permit::new());
|
|
||||||
assert!(!permit.is_acquired());
|
|
||||||
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
assert_eq!(s.available_permits(), 99);
|
|
||||||
assert!(permit.is_acquired());
|
|
||||||
|
|
||||||
// Polling again on the same waiter does not claim a new permit
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
assert_eq!(s.available_permits(), 99);
|
|
||||||
assert!(permit.is_acquired());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn poll_acquire_many_available() {
|
|
||||||
let s = Semaphore::new(100);
|
|
||||||
assert_eq!(s.available_permits(), 100);
|
|
||||||
|
|
||||||
// Polling for a permit succeeds immediately
|
|
||||||
let mut permit = task::spawn(Permit::new());
|
|
||||||
assert!(!permit.is_acquired());
|
|
||||||
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 5, &s)));
|
|
||||||
assert_eq!(s.available_permits(), 95);
|
|
||||||
assert!(permit.is_acquired());
|
|
||||||
|
|
||||||
// Polling again on the same waiter does not claim a new permit
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
assert_eq!(s.available_permits(), 95);
|
|
||||||
assert!(permit.is_acquired());
|
|
||||||
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 5, &s)));
|
|
||||||
assert_eq!(s.available_permits(), 95);
|
|
||||||
assert!(permit.is_acquired());
|
|
||||||
|
|
||||||
// Polling for a larger number of permits acquires more
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 8, &s)));
|
|
||||||
assert_eq!(s.available_permits(), 92);
|
|
||||||
assert!(permit.is_acquired());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn try_acquire_one_available() {
|
|
||||||
let s = Semaphore::new(100);
|
|
||||||
assert_eq!(s.available_permits(), 100);
|
|
||||||
|
|
||||||
// Polling for a permit succeeds immediately
|
|
||||||
let mut permit = Permit::new();
|
|
||||||
assert!(!permit.is_acquired());
|
|
||||||
|
|
||||||
assert_ok!(permit.try_acquire(1, &s));
|
|
||||||
assert_eq!(s.available_permits(), 99);
|
|
||||||
assert!(permit.is_acquired());
|
|
||||||
|
|
||||||
// Polling again on the same waiter does not claim a new permit
|
|
||||||
assert_ok!(permit.try_acquire(1, &s));
|
|
||||||
assert_eq!(s.available_permits(), 99);
|
|
||||||
assert!(permit.is_acquired());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn try_acquire_many_available() {
|
|
||||||
let s = Semaphore::new(100);
|
|
||||||
assert_eq!(s.available_permits(), 100);
|
|
||||||
|
|
||||||
// Polling for a permit succeeds immediately
|
|
||||||
let mut permit = Permit::new();
|
|
||||||
assert!(!permit.is_acquired());
|
|
||||||
|
|
||||||
assert_ok!(permit.try_acquire(5, &s));
|
|
||||||
assert_eq!(s.available_permits(), 95);
|
|
||||||
assert!(permit.is_acquired());
|
|
||||||
|
|
||||||
// Polling again on the same waiter does not claim a new permit
|
|
||||||
assert_ok!(permit.try_acquire(5, &s));
|
|
||||||
assert_eq!(s.available_permits(), 95);
|
|
||||||
assert!(permit.is_acquired());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn poll_acquire_one_unavailable() {
|
|
||||||
let s = Semaphore::new(1);
|
|
||||||
|
|
||||||
let mut permit_1 = task::spawn(Permit::new());
|
|
||||||
let mut permit_2 = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
// Acquire the first permit
|
|
||||||
assert_ready_ok!(permit_1.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
|
|
||||||
permit_2.enter(|cx, mut p| {
|
|
||||||
// Try to acquire the second permit
|
|
||||||
assert_pending!(p.poll_acquire(cx, 1, &s));
|
|
||||||
});
|
|
||||||
|
|
||||||
permit_1.release(1, &s);
|
|
||||||
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
assert!(permit_2.is_woken());
|
|
||||||
assert_ready_ok!(permit_2.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
|
|
||||||
permit_2.release(1, &s);
|
|
||||||
assert_eq!(s.available_permits(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn forget_acquired() {
|
|
||||||
let s = Semaphore::new(1);
|
|
||||||
|
|
||||||
// Polling for a permit succeeds immediately
|
|
||||||
let mut permit = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
|
|
||||||
permit.forget(1);
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn forget_waiting() {
|
|
||||||
let s = Semaphore::new(0);
|
|
||||||
|
|
||||||
// Polling for a permit succeeds immediately
|
|
||||||
let mut permit = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
assert_pending!(permit.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
|
|
||||||
permit.forget(1);
|
|
||||||
|
|
||||||
s.add_permits(1);
|
|
||||||
|
|
||||||
assert!(!permit.is_woken());
|
|
||||||
assert_eq!(s.available_permits(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn poll_acquire_many_unavailable() {
|
|
||||||
let s = Semaphore::new(5);
|
|
||||||
|
|
||||||
let mut permit_1 = task::spawn(Permit::new());
|
|
||||||
let mut permit_2 = task::spawn(Permit::new());
|
|
||||||
let mut permit_3 = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
// Acquire the first permit
|
|
||||||
assert_ready_ok!(permit_1.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
assert_eq!(s.available_permits(), 4);
|
|
||||||
|
|
||||||
permit_2.enter(|cx, mut p| {
|
|
||||||
// Try to acquire the second permit
|
|
||||||
assert_pending!(p.poll_acquire(cx, 5, &s));
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
|
|
||||||
permit_3.enter(|cx, mut p| {
|
|
||||||
// Try to acquire the third permit
|
|
||||||
assert_pending!(p.poll_acquire(cx, 3, &s));
|
|
||||||
});
|
|
||||||
|
|
||||||
permit_1.release(1, &s);
|
|
||||||
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
assert!(permit_2.is_woken());
|
|
||||||
assert_ready_ok!(permit_2.enter(|cx, mut p| p.poll_acquire(cx, 5, &s)));
|
|
||||||
|
|
||||||
assert!(!permit_3.is_woken());
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
|
|
||||||
permit_2.release(1, &s);
|
|
||||||
assert!(!permit_3.is_woken());
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
|
|
||||||
permit_2.release(2, &s);
|
|
||||||
assert!(permit_3.is_woken());
|
|
||||||
|
|
||||||
assert_ready_ok!(permit_3.enter(|cx, mut p| p.poll_acquire(cx, 3, &s)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn try_acquire_one_unavailable() {
|
|
||||||
let s = Semaphore::new(1);
|
|
||||||
|
|
||||||
let mut permit_1 = Permit::new();
|
|
||||||
let mut permit_2 = Permit::new();
|
|
||||||
|
|
||||||
// Acquire the first permit
|
|
||||||
assert_ok!(permit_1.try_acquire(1, &s));
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
|
|
||||||
assert_err!(permit_2.try_acquire(1, &s));
|
|
||||||
|
|
||||||
permit_1.release(1, &s);
|
|
||||||
|
|
||||||
assert_eq!(s.available_permits(), 1);
|
|
||||||
assert_ok!(permit_2.try_acquire(1, &s));
|
|
||||||
|
|
||||||
permit_2.release(1, &s);
|
|
||||||
assert_eq!(s.available_permits(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn try_acquire_many_unavailable() {
|
|
||||||
let s = Semaphore::new(5);
|
|
||||||
|
|
||||||
let mut permit_1 = Permit::new();
|
|
||||||
let mut permit_2 = Permit::new();
|
|
||||||
|
|
||||||
// Acquire the first permit
|
|
||||||
assert_ok!(permit_1.try_acquire(1, &s));
|
|
||||||
assert_eq!(s.available_permits(), 4);
|
|
||||||
|
|
||||||
assert_err!(permit_2.try_acquire(5, &s));
|
|
||||||
|
|
||||||
permit_1.release(1, &s);
|
|
||||||
assert_eq!(s.available_permits(), 5);
|
|
||||||
|
|
||||||
assert_ok!(permit_2.try_acquire(5, &s));
|
|
||||||
|
|
||||||
permit_2.release(1, &s);
|
|
||||||
assert_eq!(s.available_permits(), 1);
|
|
||||||
|
|
||||||
permit_2.release(1, &s);
|
|
||||||
assert_eq!(s.available_permits(), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn poll_acquire_one_zero_permits() {
|
|
||||||
let s = Semaphore::new(0);
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
|
|
||||||
let mut permit = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
// Try to acquire the permit
|
|
||||||
permit.enter(|cx, mut p| {
|
|
||||||
assert_pending!(p.poll_acquire(cx, 1, &s));
|
|
||||||
});
|
|
||||||
|
|
||||||
s.add_permits(1);
|
|
||||||
|
|
||||||
assert!(permit.is_woken());
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn validates_max_permits() {
|
|
||||||
use std::usize;
|
|
||||||
Semaphore::new((usize::MAX >> 2) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn close_semaphore_prevents_acquire() {
|
|
||||||
let s = Semaphore::new(5);
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
assert_eq!(5, s.available_permits());
|
|
||||||
|
|
||||||
let mut permit_1 = task::spawn(Permit::new());
|
|
||||||
let mut permit_2 = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
assert_ready_err!(permit_1.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
assert_eq!(5, s.available_permits());
|
|
||||||
|
|
||||||
assert_ready_err!(permit_2.enter(|cx, mut p| p.poll_acquire(cx, 2, &s)));
|
|
||||||
assert_eq!(5, s.available_permits());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn close_semaphore_notifies_permit1() {
|
|
||||||
let s = Semaphore::new(0);
|
|
||||||
let mut permit = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
assert_pending!(permit.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
assert!(permit.is_woken());
|
|
||||||
assert_ready_err!(permit.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn close_semaphore_notifies_permit2() {
|
|
||||||
let s = Semaphore::new(2);
|
|
||||||
|
|
||||||
let mut permit1 = task::spawn(Permit::new());
|
|
||||||
let mut permit2 = task::spawn(Permit::new());
|
|
||||||
let mut permit3 = task::spawn(Permit::new());
|
|
||||||
let mut permit4 = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
// Acquire a couple of permits
|
|
||||||
assert_ready_ok!(permit1.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
assert_ready_ok!(permit2.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
|
|
||||||
assert_pending!(permit3.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
assert_pending!(permit4.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
assert!(permit3.is_woken());
|
|
||||||
assert!(permit4.is_woken());
|
|
||||||
|
|
||||||
assert_ready_err!(permit3.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
assert_ready_err!(permit4.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
|
|
||||||
assert_eq!(0, s.available_permits());
|
|
||||||
|
|
||||||
permit1.release(1, &s);
|
|
||||||
|
|
||||||
assert_eq!(1, s.available_permits());
|
|
||||||
|
|
||||||
assert_ready_err!(permit1.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
|
|
||||||
permit2.release(1, &s);
|
|
||||||
|
|
||||||
assert_eq!(2, s.available_permits());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn poll_acquire_additional_permits_while_waiting_before_assigned() {
|
|
||||||
let s = Semaphore::new(1);
|
|
||||||
|
|
||||||
let mut permit = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
assert_pending!(permit.enter(|cx, mut p| p.poll_acquire(cx, 2, &s)));
|
|
||||||
assert_pending!(permit.enter(|cx, mut p| p.poll_acquire(cx, 3, &s)));
|
|
||||||
|
|
||||||
s.add_permits(1);
|
|
||||||
assert!(!permit.is_woken());
|
|
||||||
|
|
||||||
s.add_permits(1);
|
|
||||||
assert!(permit.is_woken());
|
|
||||||
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 3, &s)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn try_acquire_additional_permits_while_waiting_before_assigned() {
|
|
||||||
let s = Semaphore::new(1);
|
|
||||||
|
|
||||||
let mut permit = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
assert_pending!(permit.enter(|cx, mut p| p.poll_acquire(cx, 2, &s)));
|
|
||||||
|
|
||||||
assert_err!(permit.enter(|_, mut p| p.try_acquire(3, &s)));
|
|
||||||
|
|
||||||
s.add_permits(1);
|
|
||||||
assert!(permit.is_woken());
|
|
||||||
|
|
||||||
assert_ok!(permit.enter(|_, mut p| p.try_acquire(2, &s)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn poll_acquire_additional_permits_while_waiting_after_assigned_success() {
|
|
||||||
let s = Semaphore::new(1);
|
|
||||||
|
|
||||||
let mut permit = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
assert_pending!(permit.enter(|cx, mut p| p.poll_acquire(cx, 2, &s)));
|
|
||||||
|
|
||||||
s.add_permits(2);
|
|
||||||
|
|
||||||
assert!(permit.is_woken());
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 3, &s)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn poll_acquire_additional_permits_while_waiting_after_assigned_requeue() {
|
|
||||||
let s = Semaphore::new(1);
|
|
||||||
|
|
||||||
let mut permit = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
assert_pending!(permit.enter(|cx, mut p| p.poll_acquire(cx, 2, &s)));
|
|
||||||
|
|
||||||
s.add_permits(2);
|
|
||||||
|
|
||||||
assert!(permit.is_woken());
|
|
||||||
assert_pending!(permit.enter(|cx, mut p| p.poll_acquire(cx, 4, &s)));
|
|
||||||
|
|
||||||
s.add_permits(1);
|
|
||||||
|
|
||||||
assert!(permit.is_woken());
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 4, &s)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn poll_acquire_fewer_permits_while_waiting() {
|
|
||||||
let s = Semaphore::new(1);
|
|
||||||
|
|
||||||
let mut permit = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
assert_pending!(permit.enter(|cx, mut p| p.poll_acquire(cx, 2, &s)));
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn poll_acquire_fewer_permits_after_assigned() {
|
|
||||||
let s = Semaphore::new(1);
|
|
||||||
|
|
||||||
let mut permit1 = task::spawn(Permit::new());
|
|
||||||
let mut permit2 = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
assert_pending!(permit1.enter(|cx, mut p| p.poll_acquire(cx, 5, &s)));
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
|
|
||||||
assert_pending!(permit2.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
|
|
||||||
s.add_permits(4);
|
|
||||||
assert!(permit1.is_woken());
|
|
||||||
assert!(!permit2.is_woken());
|
|
||||||
|
|
||||||
assert_ready_ok!(permit1.enter(|cx, mut p| p.poll_acquire(cx, 3, &s)));
|
|
||||||
|
|
||||||
assert!(permit2.is_woken());
|
|
||||||
assert_eq!(s.available_permits(), 1);
|
|
||||||
|
|
||||||
assert_ready_ok!(permit2.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn forget_partial_1() {
|
|
||||||
let s = Semaphore::new(0);
|
|
||||||
|
|
||||||
let mut permit = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
assert_pending!(permit.enter(|cx, mut p| p.poll_acquire(cx, 2, &s)));
|
|
||||||
s.add_permits(1);
|
|
||||||
|
|
||||||
assert_eq!(0, s.available_permits());
|
|
||||||
|
|
||||||
permit.release(1, &s);
|
|
||||||
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 1, &s)));
|
|
||||||
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn forget_partial_2() {
|
|
||||||
let s = Semaphore::new(0);
|
|
||||||
|
|
||||||
let mut permit = task::spawn(Permit::new());
|
|
||||||
|
|
||||||
assert_pending!(permit.enter(|cx, mut p| p.poll_acquire(cx, 2, &s)));
|
|
||||||
s.add_permits(1);
|
|
||||||
|
|
||||||
assert_eq!(0, s.available_permits());
|
|
||||||
|
|
||||||
permit.release(1, &s);
|
|
||||||
|
|
||||||
s.add_permits(1);
|
|
||||||
|
|
||||||
assert_ready_ok!(permit.enter(|cx, mut p| p.poll_acquire(cx, 2, &s)));
|
|
||||||
assert_eq!(s.available_permits(), 0);
|
|
||||||
}
|
|
||||||
@@ -126,7 +126,6 @@ impl<L: Link> LinkedList<L, L::Target> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the linked list doesn not contain any node
|
/// Returns whether the linked list doesn not contain any node
|
||||||
#[cfg_attr(any(feature = "udp", feature = "uds"), allow(unused))]
|
|
||||||
pub(crate) fn is_empty(&self) -> bool {
|
pub(crate) fn is_empty(&self) -> bool {
|
||||||
if self.head.is_some() {
|
if self.head.is_some() {
|
||||||
return false;
|
return false;
|
||||||
@@ -182,20 +181,17 @@ impl<L: Link> fmt::Debug for LinkedList<L, L::Target> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L: Link> Default for LinkedList<L, L::Target> {
|
#[cfg(any(feature = "sync", feature = "signal", feature = "process"))]
|
||||||
fn default() -> Self {
|
impl<L: Link> LinkedList<L, L::Target> {
|
||||||
Self::new()
|
pub(crate) fn last(&self) -> Option<&L::Target> {
|
||||||
|
let tail = self.tail.as_ref()?;
|
||||||
|
unsafe { Some(&*tail.as_ptr()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_sync! {
|
impl<L: Link> Default for LinkedList<L, L::Target> {
|
||||||
impl<L: Link> LinkedList<L, L::Target> {
|
fn default() -> Self {
|
||||||
pub(crate) fn last(&self) -> Option<&L::Target> {
|
Self::new()
|
||||||
let tail = self.tail.as_ref()?;
|
|
||||||
unsafe {
|
|
||||||
Some(&*tail.as_ptr())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ fn many_multishot_futures() {
|
|||||||
let (start_tx, mut chain_rx) = tokio::sync::mpsc::channel(10);
|
let (start_tx, mut chain_rx) = tokio::sync::mpsc::channel(10);
|
||||||
|
|
||||||
for _ in 0..CHAIN {
|
for _ in 0..CHAIN {
|
||||||
let (mut next_tx, next_rx) = tokio::sync::mpsc::channel(10);
|
let (next_tx, next_rx) = tokio::sync::mpsc::channel(10);
|
||||||
|
|
||||||
// Forward all the messages
|
// Forward all the messages
|
||||||
rt.spawn(async move {
|
rt.spawn(async move {
|
||||||
@@ -83,8 +83,8 @@ fn many_multishot_futures() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This final task cycles if needed
|
// This final task cycles if needed
|
||||||
let (mut final_tx, final_rx) = tokio::sync::mpsc::channel(10);
|
let (final_tx, final_rx) = tokio::sync::mpsc::channel(10);
|
||||||
let mut cycle_tx = start_tx.clone();
|
let cycle_tx = start_tx.clone();
|
||||||
let mut rem = CYCLES;
|
let mut rem = CYCLES;
|
||||||
|
|
||||||
rt.spawn(async move {
|
rt.spawn(async move {
|
||||||
@@ -107,7 +107,7 @@ fn many_multishot_futures() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
rt.block_on(async move {
|
rt.block_on(async move {
|
||||||
for mut start_tx in start_txs {
|
for start_tx in start_txs {
|
||||||
start_tx.send("ping").await.unwrap();
|
start_tx.send("ping").await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +340,7 @@ fn coop_and_block_in_place() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
rt.block_on(async move {
|
rt.block_on(async move {
|
||||||
let (mut tx, mut rx) = tokio::sync::mpsc::channel(1024);
|
let (tx, mut rx) = tokio::sync::mpsc::channel(1024);
|
||||||
|
|
||||||
// Fill the channel
|
// Fill the channel
|
||||||
for _ in 0..1024 {
|
for _ in 0..1024 {
|
||||||
|
|||||||
+148
-221
@@ -17,74 +17,72 @@ trait AssertSend: Send {}
|
|||||||
impl AssertSend for mpsc::Sender<i32> {}
|
impl AssertSend for mpsc::Sender<i32> {}
|
||||||
impl AssertSend for mpsc::Receiver<i32> {}
|
impl AssertSend for mpsc::Receiver<i32> {}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn send_recv_with_buffer() {
|
async fn send_recv_with_buffer() {
|
||||||
let (tx, rx) = mpsc::channel::<i32>(16);
|
let (tx, mut rx) = mpsc::channel::<i32>(16);
|
||||||
let mut tx = task::spawn(tx);
|
|
||||||
let mut rx = task::spawn(rx);
|
|
||||||
|
|
||||||
// Using poll_ready / try_send
|
// Using poll_ready / try_send
|
||||||
assert_ready_ok!(tx.enter(|cx, mut tx| tx.poll_ready(cx)));
|
// let permit assert_ready_ok!(tx.reserve());
|
||||||
tx.try_send(1).unwrap();
|
let permit = tx.reserve().await.unwrap();
|
||||||
|
permit.send(1);
|
||||||
|
|
||||||
// Without poll_ready
|
// Without poll_ready
|
||||||
tx.try_send(2).unwrap();
|
tx.try_send(2).unwrap();
|
||||||
|
|
||||||
drop(tx);
|
drop(tx);
|
||||||
|
|
||||||
let val = assert_ready!(rx.enter(|cx, mut rx| rx.poll_recv(cx)));
|
let val = rx.recv().await;
|
||||||
assert_eq!(val, Some(1));
|
assert_eq!(val, Some(1));
|
||||||
|
|
||||||
let val = assert_ready!(rx.enter(|cx, mut rx| rx.poll_recv(cx)));
|
let val = rx.recv().await;
|
||||||
assert_eq!(val, Some(2));
|
assert_eq!(val, Some(2));
|
||||||
|
|
||||||
let val = assert_ready!(rx.enter(|cx, mut rx| rx.poll_recv(cx)));
|
let val = rx.recv().await;
|
||||||
assert!(val.is_none());
|
assert!(val.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn disarm() {
|
async fn reserve_disarm() {
|
||||||
let (tx, rx) = mpsc::channel::<i32>(2);
|
let (tx, mut rx) = mpsc::channel::<i32>(2);
|
||||||
let mut tx1 = task::spawn(tx.clone());
|
let tx1 = tx.clone();
|
||||||
let mut tx2 = task::spawn(tx.clone());
|
let tx2 = tx.clone();
|
||||||
let mut tx3 = task::spawn(tx.clone());
|
let tx3 = tx.clone();
|
||||||
let mut tx4 = task::spawn(tx);
|
let tx4 = tx;
|
||||||
let mut rx = task::spawn(rx);
|
|
||||||
|
|
||||||
// We should be able to `poll_ready` two handles without problem
|
// We should be able to `poll_ready` two handles without problem
|
||||||
assert_ready_ok!(tx1.enter(|cx, mut tx| tx.poll_ready(cx)));
|
let permit1 = assert_ok!(tx1.reserve().await);
|
||||||
assert_ready_ok!(tx2.enter(|cx, mut tx| tx.poll_ready(cx)));
|
let permit2 = assert_ok!(tx2.reserve().await);
|
||||||
|
|
||||||
// But a third should not be ready
|
// But a third should not be ready
|
||||||
assert_pending!(tx3.enter(|cx, mut tx| tx.poll_ready(cx)));
|
let mut r3 = task::spawn(tx3.reserve());
|
||||||
|
assert_pending!(r3.poll());
|
||||||
|
|
||||||
|
let mut r4 = task::spawn(tx4.reserve());
|
||||||
|
assert_pending!(r4.poll());
|
||||||
|
|
||||||
// Using one of the reserved slots should allow a new handle to become ready
|
// Using one of the reserved slots should allow a new handle to become ready
|
||||||
tx1.try_send(1).unwrap();
|
permit1.send(1);
|
||||||
|
|
||||||
// We also need to receive for the slot to be free
|
// We also need to receive for the slot to be free
|
||||||
let _ = assert_ready!(rx.enter(|cx, mut rx| rx.poll_recv(cx))).unwrap();
|
assert!(!r3.is_woken());
|
||||||
|
rx.recv().await.unwrap();
|
||||||
// Now there's a free slot!
|
// Now there's a free slot!
|
||||||
assert_ready_ok!(tx3.enter(|cx, mut tx| tx.poll_ready(cx)));
|
assert!(r3.is_woken());
|
||||||
assert_pending!(tx4.enter(|cx, mut tx| tx.poll_ready(cx)));
|
assert!(!r4.is_woken());
|
||||||
|
|
||||||
// Dropping a ready handle should also open up a slot
|
// Dropping a permit should also open up a slot
|
||||||
drop(tx2);
|
drop(permit2);
|
||||||
assert_ready_ok!(tx4.enter(|cx, mut tx| tx.poll_ready(cx)));
|
assert!(r4.is_woken());
|
||||||
assert_pending!(tx1.enter(|cx, mut tx| tx.poll_ready(cx)));
|
|
||||||
|
|
||||||
// Explicitly disarming a handle should also open a slot
|
let mut r1 = task::spawn(tx1.reserve());
|
||||||
assert!(tx3.disarm());
|
assert_pending!(r1.poll());
|
||||||
assert_ready_ok!(tx1.enter(|cx, mut tx| tx.poll_ready(cx)));
|
|
||||||
|
|
||||||
// Disarming a non-armed sender does not free up a slot
|
|
||||||
assert!(!tx3.disarm());
|
|
||||||
assert_pending!(tx3.enter(|cx, mut tx| tx.poll_ready(cx)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn send_recv_stream_with_buffer() {
|
async fn send_recv_stream_with_buffer() {
|
||||||
use tokio::stream::StreamExt;
|
use tokio::stream::StreamExt;
|
||||||
|
|
||||||
let (mut tx, mut rx) = mpsc::channel::<i32>(16);
|
let (tx, mut rx) = mpsc::channel::<i32>(16);
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
assert_ok!(tx.send(1).await);
|
assert_ok!(tx.send(1).await);
|
||||||
@@ -98,7 +96,7 @@ async fn send_recv_stream_with_buffer() {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn async_send_recv_with_buffer() {
|
async fn async_send_recv_with_buffer() {
|
||||||
let (mut tx, mut rx) = mpsc::channel(16);
|
let (tx, mut rx) = mpsc::channel(16);
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
assert_ok!(tx.send(1).await);
|
assert_ok!(tx.send(1).await);
|
||||||
@@ -110,37 +108,36 @@ async fn async_send_recv_with_buffer() {
|
|||||||
assert_eq!(None, rx.recv().await);
|
assert_eq!(None, rx.recv().await);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn start_send_past_cap() {
|
async fn start_send_past_cap() {
|
||||||
let mut t1 = task::spawn(());
|
use std::future::Future;
|
||||||
let mut t2 = task::spawn(());
|
|
||||||
let mut t3 = task::spawn(());
|
|
||||||
|
|
||||||
let (mut tx1, mut rx) = mpsc::channel(1);
|
let mut t1 = task::spawn(());
|
||||||
let mut tx2 = tx1.clone();
|
|
||||||
|
let (tx1, mut rx) = mpsc::channel(1);
|
||||||
|
let tx2 = tx1.clone();
|
||||||
|
|
||||||
assert_ok!(tx1.try_send(()));
|
assert_ok!(tx1.try_send(()));
|
||||||
|
|
||||||
t1.enter(|cx, _| {
|
let mut r1 = Box::pin(tx1.reserve());
|
||||||
assert_pending!(tx1.poll_ready(cx));
|
t1.enter(|cx, _| assert_pending!(r1.as_mut().poll(cx)));
|
||||||
});
|
|
||||||
|
|
||||||
t2.enter(|cx, _| {
|
{
|
||||||
assert_pending!(tx2.poll_ready(cx));
|
let mut r2 = task::spawn(tx2.reserve());
|
||||||
});
|
assert_pending!(r2.poll());
|
||||||
|
|
||||||
|
drop(r1);
|
||||||
|
|
||||||
|
assert!(rx.recv().await.is_some());
|
||||||
|
|
||||||
|
assert!(r2.is_woken());
|
||||||
|
assert!(!t1.is_woken());
|
||||||
|
}
|
||||||
|
|
||||||
drop(tx1);
|
drop(tx1);
|
||||||
|
|
||||||
let val = t3.enter(|cx, _| assert_ready!(rx.poll_recv(cx)));
|
|
||||||
assert!(val.is_some());
|
|
||||||
|
|
||||||
assert!(t2.is_woken());
|
|
||||||
assert!(!t1.is_woken());
|
|
||||||
|
|
||||||
drop(tx2);
|
drop(tx2);
|
||||||
|
|
||||||
let val = t3.enter(|cx, _| assert_ready!(rx.poll_recv(cx)));
|
assert!(rx.recv().await.is_none());
|
||||||
assert!(val.is_none());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -149,26 +146,20 @@ fn buffer_gteq_one() {
|
|||||||
mpsc::channel::<i32>(0);
|
mpsc::channel::<i32>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn send_recv_unbounded() {
|
async fn send_recv_unbounded() {
|
||||||
let mut t1 = task::spawn(());
|
|
||||||
|
|
||||||
let (tx, mut rx) = mpsc::unbounded_channel::<i32>();
|
let (tx, mut rx) = mpsc::unbounded_channel::<i32>();
|
||||||
|
|
||||||
// Using `try_send`
|
// Using `try_send`
|
||||||
assert_ok!(tx.send(1));
|
assert_ok!(tx.send(1));
|
||||||
assert_ok!(tx.send(2));
|
assert_ok!(tx.send(2));
|
||||||
|
|
||||||
let val = assert_ready!(t1.enter(|cx, _| rx.poll_recv(cx)));
|
assert_eq!(rx.recv().await, Some(1));
|
||||||
assert_eq!(val, Some(1));
|
assert_eq!(rx.recv().await, Some(2));
|
||||||
|
|
||||||
let val = assert_ready!(t1.enter(|cx, _| rx.poll_recv(cx)));
|
|
||||||
assert_eq!(val, Some(2));
|
|
||||||
|
|
||||||
drop(tx);
|
drop(tx);
|
||||||
|
|
||||||
let val = assert_ready!(t1.enter(|cx, _| rx.poll_recv(cx)));
|
assert!(rx.recv().await.is_none());
|
||||||
assert!(val.is_none());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -201,11 +192,10 @@ async fn send_recv_stream_unbounded() {
|
|||||||
assert_eq!(None, rx.next().await);
|
assert_eq!(None, rx.next().await);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn no_t_bounds_buffer() {
|
async fn no_t_bounds_buffer() {
|
||||||
struct NoImpls;
|
struct NoImpls;
|
||||||
|
|
||||||
let mut t1 = task::spawn(());
|
|
||||||
let (tx, mut rx) = mpsc::channel(100);
|
let (tx, mut rx) = mpsc::channel(100);
|
||||||
|
|
||||||
// sender should be Debug even though T isn't Debug
|
// sender should be Debug even though T isn't Debug
|
||||||
@@ -215,15 +205,13 @@ fn no_t_bounds_buffer() {
|
|||||||
// and sender should be Clone even though T isn't Clone
|
// and sender should be Clone even though T isn't Clone
|
||||||
assert!(tx.clone().try_send(NoImpls).is_ok());
|
assert!(tx.clone().try_send(NoImpls).is_ok());
|
||||||
|
|
||||||
let val = assert_ready!(t1.enter(|cx, _| rx.poll_recv(cx)));
|
assert!(rx.recv().await.is_some());
|
||||||
assert!(val.is_some());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn no_t_bounds_unbounded() {
|
async fn no_t_bounds_unbounded() {
|
||||||
struct NoImpls;
|
struct NoImpls;
|
||||||
|
|
||||||
let mut t1 = task::spawn(());
|
|
||||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||||
|
|
||||||
// sender should be Debug even though T isn't Debug
|
// sender should be Debug even though T isn't Debug
|
||||||
@@ -233,133 +221,87 @@ fn no_t_bounds_unbounded() {
|
|||||||
// and sender should be Clone even though T isn't Clone
|
// and sender should be Clone even though T isn't Clone
|
||||||
assert!(tx.clone().send(NoImpls).is_ok());
|
assert!(tx.clone().send(NoImpls).is_ok());
|
||||||
|
|
||||||
let val = assert_ready!(t1.enter(|cx, _| rx.poll_recv(cx)));
|
assert!(rx.recv().await.is_some());
|
||||||
assert!(val.is_some());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn send_recv_buffer_limited() {
|
async fn send_recv_buffer_limited() {
|
||||||
let mut t1 = task::spawn(());
|
let (tx, mut rx) = mpsc::channel::<i32>(1);
|
||||||
let mut t2 = task::spawn(());
|
|
||||||
|
|
||||||
let (mut tx, mut rx) = mpsc::channel::<i32>(1);
|
// Reserve capacity
|
||||||
|
let p1 = assert_ok!(tx.reserve().await);
|
||||||
|
|
||||||
// Run on a task context
|
// Send first message
|
||||||
t1.enter(|cx, _| {
|
p1.send(1);
|
||||||
assert_ready_ok!(tx.poll_ready(cx));
|
|
||||||
|
|
||||||
// Send first message
|
// Not ready
|
||||||
assert_ok!(tx.try_send(1));
|
let mut p2 = task::spawn(tx.reserve());
|
||||||
|
assert_pending!(p2.poll());
|
||||||
|
|
||||||
// Not ready
|
// Take the value
|
||||||
assert_pending!(tx.poll_ready(cx));
|
assert!(rx.recv().await.is_some());
|
||||||
|
|
||||||
// Send second message
|
// Notified
|
||||||
assert_err!(tx.try_send(1337));
|
assert!(p2.is_woken());
|
||||||
});
|
|
||||||
|
|
||||||
t2.enter(|cx, _| {
|
// Trying to send fails
|
||||||
// Take the value
|
assert_err!(tx.try_send(1337));
|
||||||
let val = assert_ready!(rx.poll_recv(cx));
|
|
||||||
assert_eq!(Some(1), val);
|
|
||||||
});
|
|
||||||
|
|
||||||
assert!(t1.is_woken());
|
// Send second
|
||||||
|
let permit = assert_ready_ok!(p2.poll());
|
||||||
|
permit.send(2);
|
||||||
|
|
||||||
t1.enter(|cx, _| {
|
assert!(rx.recv().await.is_some());
|
||||||
assert_ready_ok!(tx.poll_ready(cx));
|
|
||||||
|
|
||||||
assert_ok!(tx.try_send(2));
|
|
||||||
|
|
||||||
// Not ready
|
|
||||||
assert_pending!(tx.poll_ready(cx));
|
|
||||||
});
|
|
||||||
|
|
||||||
t2.enter(|cx, _| {
|
|
||||||
// Take the value
|
|
||||||
let val = assert_ready!(rx.poll_recv(cx));
|
|
||||||
assert_eq!(Some(2), val);
|
|
||||||
});
|
|
||||||
|
|
||||||
t1.enter(|cx, _| {
|
|
||||||
assert_ready_ok!(tx.poll_ready(cx));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn recv_close_gets_none_idle() {
|
async fn recv_close_gets_none_idle() {
|
||||||
let mut t1 = task::spawn(());
|
let (tx, mut rx) = mpsc::channel::<i32>(10);
|
||||||
|
|
||||||
let (mut tx, mut rx) = mpsc::channel::<i32>(10);
|
|
||||||
|
|
||||||
rx.close();
|
rx.close();
|
||||||
|
|
||||||
t1.enter(|cx, _| {
|
assert!(rx.recv().await.is_none());
|
||||||
let val = assert_ready!(rx.poll_recv(cx));
|
|
||||||
assert!(val.is_none());
|
assert_err!(tx.send(1).await);
|
||||||
assert_ready_err!(tx.poll_ready(cx));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn recv_close_gets_none_reserved() {
|
async fn recv_close_gets_none_reserved() {
|
||||||
let mut t1 = task::spawn(());
|
let (tx1, mut rx) = mpsc::channel::<i32>(1);
|
||||||
let mut t2 = task::spawn(());
|
let tx2 = tx1.clone();
|
||||||
let mut t3 = task::spawn(());
|
|
||||||
|
|
||||||
let (mut tx1, mut rx) = mpsc::channel::<i32>(1);
|
let permit1 = assert_ok!(tx1.reserve().await);
|
||||||
let mut tx2 = tx1.clone();
|
let mut permit2 = task::spawn(tx2.reserve());
|
||||||
|
assert_pending!(permit2.poll());
|
||||||
assert_ready_ok!(t1.enter(|cx, _| tx1.poll_ready(cx)));
|
|
||||||
|
|
||||||
t2.enter(|cx, _| {
|
|
||||||
assert_pending!(tx2.poll_ready(cx));
|
|
||||||
});
|
|
||||||
|
|
||||||
rx.close();
|
rx.close();
|
||||||
|
|
||||||
assert!(t2.is_woken());
|
assert!(permit2.is_woken());
|
||||||
|
assert_ready_err!(permit2.poll());
|
||||||
|
|
||||||
t2.enter(|cx, _| {
|
{
|
||||||
assert_ready_err!(tx2.poll_ready(cx));
|
let mut recv = task::spawn(rx.recv());
|
||||||
});
|
assert_pending!(recv.poll());
|
||||||
|
|
||||||
t3.enter(|cx, _| assert_pending!(rx.poll_recv(cx)));
|
permit1.send(123);
|
||||||
|
assert!(recv.is_woken());
|
||||||
|
|
||||||
assert!(!t1.is_woken());
|
let v = assert_ready!(recv.poll());
|
||||||
assert!(!t2.is_woken());
|
|
||||||
|
|
||||||
assert_ok!(tx1.try_send(123));
|
|
||||||
|
|
||||||
assert!(t3.is_woken());
|
|
||||||
|
|
||||||
t3.enter(|cx, _| {
|
|
||||||
let v = assert_ready!(rx.poll_recv(cx));
|
|
||||||
assert_eq!(v, Some(123));
|
assert_eq!(v, Some(123));
|
||||||
|
}
|
||||||
|
|
||||||
let v = assert_ready!(rx.poll_recv(cx));
|
assert!(rx.recv().await.is_none());
|
||||||
assert!(v.is_none());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn tx_close_gets_none() {
|
async fn tx_close_gets_none() {
|
||||||
let mut t1 = task::spawn(());
|
|
||||||
|
|
||||||
let (_, mut rx) = mpsc::channel::<i32>(10);
|
let (_, mut rx) = mpsc::channel::<i32>(10);
|
||||||
|
assert!(rx.recv().await.is_none());
|
||||||
// Run on a task context
|
|
||||||
t1.enter(|cx, _| {
|
|
||||||
let v = assert_ready!(rx.poll_recv(cx));
|
|
||||||
assert!(v.is_none());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn try_send_fail() {
|
async fn try_send_fail() {
|
||||||
let mut t1 = task::spawn(());
|
let (tx, mut rx) = mpsc::channel(1);
|
||||||
|
|
||||||
let (mut tx, mut rx) = mpsc::channel(1);
|
|
||||||
|
|
||||||
tx.try_send("hello").unwrap();
|
tx.try_send("hello").unwrap();
|
||||||
|
|
||||||
@@ -369,60 +311,48 @@ fn try_send_fail() {
|
|||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
let val = assert_ready!(t1.enter(|cx, _| rx.poll_recv(cx)));
|
assert_eq!(rx.recv().await, Some("hello"));
|
||||||
assert_eq!(val, Some("hello"));
|
|
||||||
|
|
||||||
assert_ok!(tx.try_send("goodbye"));
|
assert_ok!(tx.try_send("goodbye"));
|
||||||
drop(tx);
|
drop(tx);
|
||||||
|
|
||||||
let val = assert_ready!(t1.enter(|cx, _| rx.poll_recv(cx)));
|
assert_eq!(rx.recv().await, Some("goodbye"));
|
||||||
assert_eq!(val, Some("goodbye"));
|
assert!(rx.recv().await.is_none());
|
||||||
|
|
||||||
let val = assert_ready!(t1.enter(|cx, _| rx.poll_recv(cx)));
|
|
||||||
assert!(val.is_none());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn drop_tx_with_permit_releases_permit() {
|
async fn drop_permit_releases_permit() {
|
||||||
let mut t1 = task::spawn(());
|
|
||||||
let mut t2 = task::spawn(());
|
|
||||||
|
|
||||||
// poll_ready reserves capacity, ensure that the capacity is released if tx
|
// poll_ready reserves capacity, ensure that the capacity is released if tx
|
||||||
// is dropped w/o sending a value.
|
// is dropped w/o sending a value.
|
||||||
let (mut tx1, _rx) = mpsc::channel::<i32>(1);
|
let (tx1, _rx) = mpsc::channel::<i32>(1);
|
||||||
let mut tx2 = tx1.clone();
|
let tx2 = tx1.clone();
|
||||||
|
|
||||||
assert_ready_ok!(t1.enter(|cx, _| tx1.poll_ready(cx)));
|
let permit = assert_ok!(tx1.reserve().await);
|
||||||
|
|
||||||
t2.enter(|cx, _| {
|
let mut reserve2 = task::spawn(tx2.reserve());
|
||||||
assert_pending!(tx2.poll_ready(cx));
|
assert_pending!(reserve2.poll());
|
||||||
});
|
|
||||||
|
|
||||||
drop(tx1);
|
drop(permit);
|
||||||
|
|
||||||
assert!(t2.is_woken());
|
assert!(reserve2.is_woken());
|
||||||
|
assert_ready_ok!(reserve2.poll());
|
||||||
assert_ready_ok!(t2.enter(|cx, _| tx2.poll_ready(cx)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn dropping_rx_closes_channel() {
|
async fn dropping_rx_closes_channel() {
|
||||||
let mut t1 = task::spawn(());
|
let (tx, rx) = mpsc::channel(100);
|
||||||
|
|
||||||
let (mut tx, rx) = mpsc::channel(100);
|
|
||||||
|
|
||||||
let msg = Arc::new(());
|
let msg = Arc::new(());
|
||||||
assert_ok!(tx.try_send(msg.clone()));
|
assert_ok!(tx.try_send(msg.clone()));
|
||||||
|
|
||||||
drop(rx);
|
drop(rx);
|
||||||
assert_ready_err!(t1.enter(|cx, _| tx.poll_ready(cx)));
|
assert_err!(tx.reserve().await);
|
||||||
|
|
||||||
assert_eq!(1, Arc::strong_count(&msg));
|
assert_eq!(1, Arc::strong_count(&msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dropping_rx_closes_channel_for_try() {
|
fn dropping_rx_closes_channel_for_try() {
|
||||||
let (mut tx, rx) = mpsc::channel(100);
|
let (tx, rx) = mpsc::channel(100);
|
||||||
|
|
||||||
let msg = Arc::new(());
|
let msg = Arc::new(());
|
||||||
tx.try_send(msg.clone()).unwrap();
|
tx.try_send(msg.clone()).unwrap();
|
||||||
@@ -444,7 +374,7 @@ fn dropping_rx_closes_channel_for_try() {
|
|||||||
fn unconsumed_messages_are_dropped() {
|
fn unconsumed_messages_are_dropped() {
|
||||||
let msg = Arc::new(());
|
let msg = Arc::new(());
|
||||||
|
|
||||||
let (mut tx, rx) = mpsc::channel(100);
|
let (tx, rx) = mpsc::channel(100);
|
||||||
|
|
||||||
tx.try_send(msg.clone()).unwrap();
|
tx.try_send(msg.clone()).unwrap();
|
||||||
|
|
||||||
@@ -457,7 +387,7 @@ fn unconsumed_messages_are_dropped() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn try_recv() {
|
fn try_recv() {
|
||||||
let (mut tx, mut rx) = mpsc::channel(1);
|
let (tx, mut rx) = mpsc::channel(1);
|
||||||
match rx.try_recv() {
|
match rx.try_recv() {
|
||||||
Err(TryRecvError::Empty) => {}
|
Err(TryRecvError::Empty) => {}
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
@@ -495,7 +425,7 @@ fn try_recv_unbounded() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn blocking_recv() {
|
fn blocking_recv() {
|
||||||
let (mut tx, mut rx) = mpsc::channel::<u8>(1);
|
let (tx, mut rx) = mpsc::channel::<u8>(1);
|
||||||
|
|
||||||
let sync_code = thread::spawn(move || {
|
let sync_code = thread::spawn(move || {
|
||||||
assert_eq!(Some(10), rx.blocking_recv());
|
assert_eq!(Some(10), rx.blocking_recv());
|
||||||
@@ -516,7 +446,7 @@ async fn blocking_recv_async() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn blocking_send() {
|
fn blocking_send() {
|
||||||
let (mut tx, mut rx) = mpsc::channel::<u8>(1);
|
let (tx, mut rx) = mpsc::channel::<u8>(1);
|
||||||
|
|
||||||
let sync_code = thread::spawn(move || {
|
let sync_code = thread::spawn(move || {
|
||||||
tx.blocking_send(10).unwrap();
|
tx.blocking_send(10).unwrap();
|
||||||
@@ -531,28 +461,25 @@ fn blocking_send() {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
async fn blocking_send_async() {
|
async fn blocking_send_async() {
|
||||||
let (mut tx, _rx) = mpsc::channel::<()>(1);
|
let (tx, _rx) = mpsc::channel::<()>(1);
|
||||||
let _ = tx.blocking_send(());
|
let _ = tx.blocking_send(());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[tokio::test]
|
||||||
fn ready_close_cancel_bounded() {
|
async fn ready_close_cancel_bounded() {
|
||||||
use futures::future::poll_fn;
|
let (tx, mut rx) = mpsc::channel::<()>(100);
|
||||||
|
|
||||||
let (mut tx, mut rx) = mpsc::channel::<()>(100);
|
|
||||||
let _tx2 = tx.clone();
|
let _tx2 = tx.clone();
|
||||||
|
|
||||||
{
|
let permit = assert_ok!(tx.reserve().await);
|
||||||
let mut ready = task::spawn(async { poll_fn(|cx| tx.poll_ready(cx)).await });
|
|
||||||
assert_ready_ok!(ready.poll());
|
|
||||||
}
|
|
||||||
|
|
||||||
rx.close();
|
rx.close();
|
||||||
|
|
||||||
let mut recv = task::spawn(async { rx.recv().await });
|
let mut recv = task::spawn(rx.recv());
|
||||||
assert_pending!(recv.poll());
|
assert_pending!(recv.poll());
|
||||||
|
|
||||||
drop(tx);
|
drop(permit);
|
||||||
|
|
||||||
assert!(recv.is_woken());
|
assert!(recv.is_woken());
|
||||||
|
let val = assert_ready!(recv.poll());
|
||||||
|
assert!(val.is_none());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user