diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
commit | dc0db358abe19481e475e10c32149b53370f1a1c (patch) | |
tree | ab8ce99c4b255ce46f99ef402c27916055b899ee /vendor/tokio/src/macros/join.rs | |
parent | Releasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff) | |
download | rustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip |
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/tokio/src/macros/join.rs')
-rw-r--r-- | vendor/tokio/src/macros/join.rs | 75 |
1 files changed, 61 insertions, 14 deletions
diff --git a/vendor/tokio/src/macros/join.rs b/vendor/tokio/src/macros/join.rs index 5f37af510..8a0198600 100644 --- a/vendor/tokio/src/macros/join.rs +++ b/vendor/tokio/src/macros/join.rs @@ -1,4 +1,4 @@ -/// Wait on multiple concurrent branches, returning when **all** branches +/// Waits on multiple concurrent branches, returning when **all** branches /// complete. /// /// The `join!` macro must be used inside of async functions, closures, and @@ -12,7 +12,7 @@ /// for **all** branches complete regardless if any complete with `Err`. Use /// [`try_join!`] to return early when `Err` is encountered. /// -/// [`try_join!`]: macro@try_join +/// [`try_join!`]: crate::try_join /// /// # Notes /// @@ -60,6 +60,9 @@ macro_rules! join { // normalization is complete. ( $($count:tt)* ) + // The expression `0+1+1+ ... +1` equal to the number of branches. + ( $($total:tt)* ) + // Normalized join! branches $( ( $($skip:tt)* ) $e:expr, )* @@ -69,24 +72,66 @@ macro_rules! join { // 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 = ( $( maybe_done($e), )* ); + // 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; + + // Each time the future created by poll_fn is polled, a different future will be polled first + // to ensure every future passed to join! gets a chance to make progress even if + // one of the futures consumes the whole budget. + // + // This is number of futures that will be skipped in the first loop + // iteration the next time. + let mut skip_next_time: u32 = 0; + poll_fn(move |cx| { + const COUNT: u32 = $($total)*; + let mut is_pending = false; + let mut to_run = COUNT; + + // The number of futures that will be skipped in the first loop iteration. + let mut skip = skip_next_time; + + skip_next_time = if skip + 1 == COUNT { 0 } else { skip + 1 }; + + // This loop runs twice and the first `skip` futures + // are not polled in the first iteration. + loop { $( - // Extract the future for this branch from the tuple. - let ( $($skip,)* fut, .. ) = &mut futures; + if skip == 0 { + if to_run == 0 { + // Every future has been polled + break; + } + to_run -= 1; - // Safety: future is stored on the stack above - // and never moved. - let mut fut = unsafe { Pin::new_unchecked(fut) }; + // Extract the future for this branch from the tuple. + let ( $($skip,)* fut, .. ) = &mut *futures; - // Try polling - if fut.poll(cx).is_pending() { - is_pending = true; + // Safety: future is stored on the stack above + // and never moved. + let mut fut = unsafe { Pin::new_unchecked(fut) }; + + // Try polling + if fut.poll(cx).is_pending() { + is_pending = true; + } + } else { + // Future skipped, one less future to skip in the next iteration + skip -= 1; } )* + } if is_pending { Pending @@ -107,13 +152,15 @@ macro_rules! join { // ===== Normalize ===== - (@ { ( $($s:tt)* ) $($t:tt)* } $e:expr, $($r:tt)* ) => { - $crate::join!(@{ ($($s)* _) $($t)* ($($s)*) $e, } $($r)*) + (@ { ( $($s:tt)* ) ( $($n:tt)* ) $($t:tt)* } $e:expr, $($r:tt)* ) => { + $crate::join!(@{ ($($s)* _) ($($n)* + 1) $($t)* ($($s)*) $e, } $($r)*) }; // ===== Entry point ===== - ( $($e:expr),* $(,)?) => { - $crate::join!(@{ () } $($e,)*) + ( $($e:expr),+ $(,)?) => { + $crate::join!(@{ () (0) } $($e,)*) }; + + () => { async {}.await } } |