diff --git a/.cirrus.yml b/.cirrus.yml index 0148ad414..aa8150d58 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,7 +1,7 @@ only_if: $CIRRUS_TAG == '' && ($CIRRUS_PR != '' || $CIRRUS_BRANCH == 'master' || $CIRRUS_BRANCH =~ 'tokio-.*') auto_cancellation: $CIRRUS_BRANCH != 'master' && $CIRRUS_BRANCH !=~ 'tokio-.*' freebsd_instance: - image_family: freebsd-14-2 + image_family: freebsd-14-3 env: RUST_STABLE: stable RUST_NIGHTLY: nightly-2025-01-25 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bee3535e2..bed0212e0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1078,21 +1078,21 @@ jobs: run: cargo test -p tokio --target ${{ matrix.target }} --features full env: CARGO_TARGET_WASM32_WASIP1_RUNNER: "wasmtime run --" - CARGO_TARGET_WASM32_WASIP1_THREADS_RUNNER: "wasmtime run -W bulk-memory=y -W threads=y -S threads=y --" + CARGO_TARGET_WASM32_WASIP1_THREADS_RUNNER: "wasmtime run -W bulk-memory=y -W threads=y -W shared-memory=y -S threads=y --" RUSTFLAGS: --cfg tokio_unstable -Dwarnings -C target-feature=+atomics,+bulk-memory -C link-args=--max-memory=67108864 - name: WASI test tokio-util full run: cargo test -p tokio-util --target ${{ matrix.target }} --features full env: CARGO_TARGET_WASM32_WASIP1_RUNNER: "wasmtime run --" - CARGO_TARGET_WASM32_WASIP1_THREADS_RUNNER: "wasmtime run -W bulk-memory=y -W threads=y -S threads=y --" + CARGO_TARGET_WASM32_WASIP1_THREADS_RUNNER: "wasmtime run -W bulk-memory=y -W threads=y -W shared-memory=y -S threads=y --" RUSTFLAGS: --cfg tokio_unstable -Dwarnings -C target-feature=+atomics,+bulk-memory -C link-args=--max-memory=67108864 - name: WASI test tokio-stream run: cargo test -p tokio-stream --target ${{ matrix.target }} --features time,net,io-util,sync env: CARGO_TARGET_WASM32_WASIP1_RUNNER: "wasmtime run --" - CARGO_TARGET_WASM32_WASIP1_THREADS_RUNNER: "wasmtime run -W bulk-memory=y -W threads=y -S threads=y --" + CARGO_TARGET_WASM32_WASIP1_THREADS_RUNNER: "wasmtime run -W bulk-memory=y -W threads=y -W shared-memory=y -S threads=y --" RUSTFLAGS: --cfg tokio_unstable -Dwarnings -C target-feature=+atomics,+bulk-memory -C link-args=--max-memory=67108864 - name: test tests-integration --features wasi-rt @@ -1109,7 +1109,7 @@ jobs: if: matrix.target == 'wasm32-wasip1-threads' working-directory: tests-integration env: - CARGO_TARGET_WASM32_WASIP1_THREADS_RUNNER: "wasmtime run -W bulk-memory=y -W threads=y -S threads=y --" + CARGO_TARGET_WASM32_WASIP1_THREADS_RUNNER: "wasmtime run -W bulk-memory=y -W threads=y -W shared-memory=y -S threads=y --" RUSTFLAGS: --cfg tokio_unstable -Dwarnings -C target-feature=+atomics,+bulk-memory -C link-args=--max-memory=67108864 check-external-types: diff --git a/Cargo.lock b/Cargo.lock index 0dc2a8cb3..e0634fc3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1405,7 +1405,7 @@ dependencies = [ [[package]] name = "tokio" -version = "1.47.1" +version = "1.47.2" dependencies = [ "async-stream", "backtrace", diff --git a/tokio/CHANGELOG.md b/tokio/CHANGELOG.md index 1994e1692..ee234793f 100644 --- a/tokio/CHANGELOG.md +++ b/tokio/CHANGELOG.md @@ -263,6 +263,14 @@ comment on [#7172]. [#7186]: https://github.com/tokio-rs/tokio/pull/7186 [#7192]: https://github.com/tokio-rs/tokio/pull/7192 +# 1.43.4 (January 3rd, 2026) + +### Fixed + +* sync: return `TryRecvError::Disconnected` from `Receiver::try_recv` after `Receiver::close` ([#7686]) + +[#7686]: https://github.com/tokio-rs/tokio/pull/7686 + # 1.43.3 (October 14th, 2025) ### Fixed diff --git a/tokio/src/sync/mpsc/chan.rs b/tokio/src/sync/mpsc/chan.rs index 0bf760aa8..20e2c90d4 100644 --- a/tokio/src/sync/mpsc/chan.rs +++ b/tokio/src/sync/mpsc/chan.rs @@ -439,6 +439,10 @@ impl Rx { return Ok(value); } TryPopResult::Closed => return Err(TryRecvError::Disconnected), + // If close() was called, an empty queue should report Disconnected. + TryPopResult::Empty if rx_fields.rx_closed => { + return Err(TryRecvError::Disconnected) + } TryPopResult::Empty => return Err(TryRecvError::Empty), TryPopResult::Busy => {} // fall through } diff --git a/tokio/src/sync/mpsc/list.rs b/tokio/src/sync/mpsc/list.rs index 90d9b828c..118bac856 100644 --- a/tokio/src/sync/mpsc/list.rs +++ b/tokio/src/sync/mpsc/list.rs @@ -35,8 +35,14 @@ pub(crate) enum TryPopResult { /// Successfully popped a value. Ok(T), /// The channel is empty. + /// + /// Note that `list.rs` only tracks the close state set by senders. If the + /// channel is closed by `Rx::close()`, then `TryPopResult::Empty` is still + /// returned, and the close state needs to be handled by `chan.rs`. Empty, /// The channel is empty and closed. + /// + /// Returned when the send half is closed (all senders dropped). Closed, /// The channel is not empty, but the first value is being written. Busy, diff --git a/tokio/tests/sync_mpsc.rs b/tokio/tests/sync_mpsc.rs index 577e9c35f..3ebac7390 100644 --- a/tokio/tests/sync_mpsc.rs +++ b/tokio/tests/sync_mpsc.rs @@ -966,6 +966,15 @@ fn try_recv_unbounded() { } } +#[test] +fn try_recv_after_receiver_close() { + let (_tx, mut rx) = mpsc::channel::<()>(5); + + assert_eq!(Err(TryRecvError::Empty), rx.try_recv()); + rx.close(); + assert_eq!(Err(TryRecvError::Disconnected), rx.try_recv()); +} + #[test] fn try_recv_close_while_empty_bounded() { let (tx, mut rx) = mpsc::channel::<()>(5);