diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d895a3c0f..bee3535e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1038,10 +1038,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Install Rust ${{ env.rust_stable }} + - name: Install Rust 1.88.0 uses: dtolnay/rust-toolchain@stable with: - toolchain: ${{ env.rust_stable }} + toolchain: 1.88.0 - name: Install wasm-pack uses: taiki-e/install-action@wasm-pack @@ -1061,10 +1061,10 @@ jobs: - wasm32-wasip1-threads steps: - uses: actions/checkout@v4 - - name: Install Rust ${{ env.rust_stable }} + - name: Install Rust 1.88.0 uses: dtolnay/rust-toolchain@stable with: - toolchain: ${{ env.rust_stable }} + toolchain: 1.88.0 targets: ${{ matrix.target }} # Install dependencies diff --git a/tests-build/tests/fail/macros_type_mismatch.stderr b/tests-build/tests/fail/macros_type_mismatch.stderr index f9c32f005..c20dae302 100644 --- a/tests-build/tests/fail/macros_type_mismatch.stderr +++ b/tests-build/tests/fail/macros_type_mismatch.stderr @@ -25,7 +25,7 @@ error[E0308]: mismatched types found enum `Result<(), _>` help: a return type might be missing here | -9 | async fn missing_return_type() -> _ { + 9 | async fn missing_return_type() -> _ { | ++++ help: consider using `Result::expect` to unwrap the `Result<(), _>` value, panicking if the value is a `Result::Err` | diff --git a/tokio/CHANGELOG.md b/tokio/CHANGELOG.md index 149bb0e76..6d4124f2d 100644 --- a/tokio/CHANGELOG.md +++ b/tokio/CHANGELOG.md @@ -249,6 +249,18 @@ comment on [#7172]. [#7186]: https://github.com/tokio-rs/tokio/pull/7186 [#7192]: https://github.com/tokio-rs/tokio/pull/7192 +# 1.43.3 (October 14th, 2025) + +### Fixed + +- runtime: use release ordering in `wake_by_ref()` even if already woken ([#7622]) +- sync: close the `broadcast::Sender` in `broadcast::Sender::new()` ([#7629]) +- process: fix error when runtime is shut down on nightly-2025-10-12 ([#7672]) + +[#7622]: https://github.com/tokio-rs/tokio/pull/7622 +[#7629]: https://github.com/tokio-rs/tokio/pull/7629 +[#7672]: https://github.com/tokio-rs/tokio/pull/7672 + # 1.43.2 (August 1st, 2025) ### Fixed diff --git a/tokio/src/process/unix/pidfd_reaper.rs b/tokio/src/process/unix/pidfd_reaper.rs index 2574f360f..f29e99b1d 100644 --- a/tokio/src/process/unix/pidfd_reaper.rs +++ b/tokio/src/process/unix/pidfd_reaper.rs @@ -95,14 +95,41 @@ where pidfd: PollEvented, } +fn display_eq(d: impl std::fmt::Display, s: &str) -> bool { + use std::fmt::Write; + + struct FormatEq<'r> { + remainder: &'r str, + unequal: bool, + } + + impl<'r> Write for FormatEq<'r> { + fn write_str(&mut self, s: &str) -> std::fmt::Result { + if !self.unequal { + if let Some(new_remainder) = self.remainder.strip_prefix(s) { + self.remainder = new_remainder; + } else { + self.unequal = true; + } + } + Ok(()) + } + } + + let mut fmt_eq = FormatEq { + remainder: s, + unequal: false, + }; + let _ = write!(fmt_eq, "{d}"); + fmt_eq.remainder.is_empty() && !fmt_eq.unequal +} + #[allow(deprecated)] fn is_rt_shutdown_err(err: &io::Error) -> bool { if let Some(inner) = err.get_ref() { - // Using `Error::description()` is more efficient than `format!("{inner}")`, - // so we use it here even if it is deprecated. err.kind() == io::ErrorKind::Other && inner.source().is_none() - && inner.description() == RUNTIME_SHUTTING_DOWN_ERROR + && display_eq(inner, RUNTIME_SHUTTING_DOWN_ERROR) } else { false } diff --git a/tokio/src/runtime/task/state.rs b/tokio/src/runtime/task/state.rs index da3e8d38d..2d3a1b5c4 100644 --- a/tokio/src/runtime/task/state.rs +++ b/tokio/src/runtime/task/state.rs @@ -252,9 +252,15 @@ impl State { /// Transitions the state to `NOTIFIED`. pub(super) fn transition_to_notified_by_ref(&self) -> TransitionToNotifiedByRef { self.fetch_update_action(|mut snapshot| { - if snapshot.is_complete() || snapshot.is_notified() { - // There is nothing to do in this case. + if snapshot.is_complete() { + // The complete state is final (TransitionToNotifiedByRef::DoNothing, None) + } else if snapshot.is_notified() { + // Even hough we have nothing to do in this branch, + // wake_by_ref() should synchronize-with the task starting execution, + // therefore we must use an Release store (with the same value), + // to pair with the Acquire in transition_to_running. + (TransitionToNotifiedByRef::DoNothing, Some(snapshot)) } else if snapshot.is_running() { // If the task is running, we mark it as notified, but we should // not submit as the thread currently running the future is diff --git a/tokio/src/sync/broadcast.rs b/tokio/src/sync/broadcast.rs index 6cd0bfe93..3936edabd 100644 --- a/tokio/src/sync/broadcast.rs +++ b/tokio/src/sync/broadcast.rs @@ -566,7 +566,7 @@ impl Sender { tail: Mutex::new(Tail { pos: 0, rx_cnt: receiver_count, - closed: false, + closed: receiver_count == 0, waiters: LinkedList::new(), }), num_tx: AtomicUsize::new(1), diff --git a/tokio/tests/sync_broadcast.rs b/tokio/tests/sync_broadcast.rs index 0d657ff77..b742a6f61 100644 --- a/tokio/tests/sync_broadcast.rs +++ b/tokio/tests/sync_broadcast.rs @@ -706,3 +706,17 @@ fn broadcast_sender_closed_with_extra_subscribe() { assert!(task3.is_woken()); assert_ready!(task3.poll()); } + +#[tokio::test] +async fn broadcast_sender_new_must_be_closed() { + let capacity = 1; + let tx: broadcast::Sender<()> = broadcast::Sender::new(capacity); + + let mut task = task::spawn(tx.closed()); + assert_ready!(task.poll()); + + let _rx = tx.subscribe(); + + let mut task2 = task::spawn(tx.closed()); + assert_pending!(task2.poll()); +}