aboutsummaryrefslogtreecommitdiff
path: root/src/macros/select.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/macros/select.rs')
-rw-r--r--src/macros/select.rs31
1 files changed, 23 insertions, 8 deletions
diff --git a/src/macros/select.rs b/src/macros/select.rs
index 051f8cb..7ba04a0 100644
--- a/src/macros/select.rs
+++ b/src/macros/select.rs
@@ -101,6 +101,7 @@
/// * [`tokio::sync::watch::Receiver::changed`](crate::sync::watch::Receiver::changed)
/// * [`tokio::net::TcpListener::accept`](crate::net::TcpListener::accept)
/// * [`tokio::net::UnixListener::accept`](crate::net::UnixListener::accept)
+/// * [`tokio::signal::unix::Signal::recv`](crate::signal::unix::Signal::recv)
/// * [`tokio::io::AsyncReadExt::read`](crate::io::AsyncReadExt::read) on any `AsyncRead`
/// * [`tokio::io::AsyncReadExt::read_buf`](crate::io::AsyncReadExt::read_buf) on any `AsyncRead`
/// * [`tokio::io::AsyncWriteExt::write`](crate::io::AsyncWriteExt::write) on any `AsyncWrite`
@@ -429,7 +430,8 @@ macro_rules! select {
//
// This module is defined within a scope and should not leak out of this
// macro.
- mod util {
+ #[doc(hidden)]
+ mod __tokio_select_util {
// Generate an enum with one variant per select branch
$crate::select_priv_declare_output_enum!( ( $($count)* ) );
}
@@ -442,13 +444,13 @@ macro_rules! select {
const BRANCHES: u32 = $crate::count!( $($count)* );
- let mut disabled: util::Mask = Default::default();
+ let mut disabled: __tokio_select_util::Mask = Default::default();
// First, invoke all the pre-conditions. For any that return true,
// set the appropriate bit in `disabled`.
$(
if !$c {
- let mask: util::Mask = 1 << $crate::count!( $($skip)* );
+ let mask: __tokio_select_util::Mask = 1 << $crate::count!( $($skip)* );
disabled |= mask;
}
)*
@@ -458,8 +460,18 @@ macro_rules! select {
let mut output = {
// Safety: Nothing must be moved out of `futures`. This is to
// satisfy the requirement of `Pin::new_unchecked` called below.
+ //
+ // We can't use the `pin!` macro for this because `futures` is a
+ // tuple and the standard library provides no way to pin-project to
+ // the fields of a tuple.
let mut futures = ( $( $fut , )+ );
+ // This assignment makes sure that the `poll_fn` closure only has a
+ // reference to the futures, instead of taking ownership of them.
+ // This mitigates the issue described in
+ // <https://internals.rust-lang.org/t/surprising-soundness-trouble-around-pollfn/17484>
+ let mut futures = &mut futures;
+
$crate::macros::support::poll_fn(|cx| {
// Track if any branch returns pending. If no branch completes
// **or** returns pending, this implies that all branches are
@@ -495,7 +507,7 @@ macro_rules! select {
// Extract the future for this branch from the
// tuple
- let ( $($skip,)* fut, .. ) = &mut futures;
+ let ( $($skip,)* fut, .. ) = &mut *futures;
// Safety: future is stored on the stack above
// and never moved.
@@ -525,7 +537,7 @@ macro_rules! select {
}
// The select is complete, return the value
- return Ready($crate::select_variant!(util::Out, ($($skip)*))(out));
+ return Ready($crate::select_variant!(__tokio_select_util::Out, ($($skip)*))(out));
}
)*
_ => unreachable!("reaching this means there probably is an off by one bug"),
@@ -536,16 +548,16 @@ macro_rules! select {
Pending
} else {
// All branches have been disabled.
- Ready(util::Out::Disabled)
+ Ready(__tokio_select_util::Out::Disabled)
}
}).await
};
match output {
$(
- $crate::select_variant!(util::Out, ($($skip)*) ($bind)) => $handle,
+ $crate::select_variant!(__tokio_select_util::Out, ($($skip)*) ($bind)) => $handle,
)*
- util::Out::Disabled => $else,
+ __tokio_select_util::Out::Disabled => $else,
_ => unreachable!("failed to match bind"),
}
}};
@@ -801,6 +813,9 @@ macro_rules! count {
(_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _) => {
63
};
+ (_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _) => {
+ 64
+ };
}
#[macro_export]