Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sync: oneshot::Receiver::is_terminated() #7152

Merged
merged 3 commits into from
Feb 16, 2025

Conversation

cratelyn
Copy link
Contributor

@cratelyn cratelyn commented Feb 13, 2025

this commit introduces a new method to tokio::sync::oneshot::Receiver<T>.

broadly speaking, users of the oneshot channel are encouraged to .await the Receiver<T> directly, as it will only yield a single value.

users implementing their own std::future::Futures directly may instead poll the receiver via <Receiver<T> as Future<Output = Result<T, RecvError>::poll(..). note that the contract of Future::poll() states that clients should not poll a future after it has yielded Poll::Ready(value).

this commit provides a way to inspect the state of a receiver, to avoid violating the contact of Future::poll(..), or requiring that a oneshot channel users track this state themselves externally via mechanisms like futures::future::FusedFuture, or wrapping the receiver in an Option<T>.

NB: this makes a small behavioral change to the implementation of <Receiver<T> as Future<Output = Result<T, RecvError>::poll(..). this change is acceptable, per the Future::poll() documentation regarding panics:

Once a future has completed (returned Ready from poll), calling its
poll method again may panic, block forever, or cause other kinds of problems; the Future trait places no requirements on the effects of such a call.

the upside of this is that it means a broken or closed channel, e.g. when the sender is dropped, will settle as "finished" after it yields an error.

see:

@github-actions github-actions bot added the R-loom-sync Run loom sync tests on this PR label Feb 13, 2025
@cratelyn cratelyn marked this pull request as ready for review February 13, 2025 20:39
@cratelyn

This comment was marked as resolved.

@Darksonn Darksonn added A-tokio Area: The main tokio crate M-sync Module: tokio/sync labels Feb 14, 2025
cratelyn added a commit to cratelyn/tokio that referenced this pull request Feb 15, 2025
> You could also add a test for `is_terminated` before and after
> `try_recv` as well.

tokio-rs#7152 (comment)

Co-authored-by: M.Amin Rayej <[email protected]>
Signed-off-by: katelyn martin <[email protected]>
cratelyn and others added 2 commits February 15, 2025 14:38
this commit introduces a new method to
`tokio::sync::oneshot::Receiver<T>`.

broadly speaking, users of the oneshot channel are encouraged to
`.await` the `Receiver<T>` directly, as it will only yield a single
value.

users implementing their own `std::future::Future`s directly may instead
poll the receiver via
`<Receiver<T> as Future<Output = Result<T, RecvError>::poll(..)`.
note that the contract of `Future::poll()` states that clients should
not poll a future after it has yielded `Poll::Ready(value)`.

this commit provides a way to inspect the
state of a receiver, to avoid violating the contact of
`Future::poll(..)`, or requiring that a oneshot channel users track this
state themselves externally via mechanisms like
`futures::future::FusedFuture`, or wrapping the receiver in an
`Option<T>`.

NB: this makes a small behavioral change to the implementation of
`<Receiver<T> as Future<Output = Result<T, RecvError>::poll(..)`. this
change is acceptable, per the `Future::poll()` documentation regarding
panics:

> Once a future has completed (returned Ready from poll), calling its
poll method again may panic, block forever, or cause other kinds of
problems; the Future trait places no requirements on the effects of such
a call.

the upside of this is that it means a broken or closed channel, e.g.
when the sender is dropped, will settle as "finished" after it yields an
error.

see:
* tokio-rs#7137 (comment)
* https://doc.rust-lang.org/stable/std/future/trait.Future.html#panics

Signed-off-by: katelyn martin <[email protected]>
> You could also add a test for `is_terminated` before and after
> `try_recv` as well.

tokio-rs#7152 (comment)

Co-authored-by: M.Amin Rayej <[email protected]>
Signed-off-by: katelyn martin <[email protected]>
@cratelyn cratelyn force-pushed the sync-oneshot.is_terminated branch from 036c002 to 8fc0759 Compare February 15, 2025 19:38
cratelyn added a commit to cratelyn/tokio that referenced this pull request Feb 15, 2025
NB: this commit means that this branch (tokio-rs#7153) is dependent upon
interfaces proposed in (tokio-rs#7152).

pr tokio-rs#7152 proposes a `is_terminated()` method for the oneshot channel's
receiver. that is the proper method to use to check whether or not it is
safe to poll a oneshot receiver as a future.

this commit adds a note cross-referencing this method to the
documentation of `is_empty()`, to help mitigate misuse. this method only
reports whether a value is currently waiting in the channel; a channel
that has already received and yielded a value to its receiver is also
empty, but would panic when polled.

Signed-off-by: katelyn martin <[email protected]>
cratelyn added a commit to cratelyn/tokio that referenced this pull request Feb 15, 2025
NB: this commit means that this branch (tokio-rs#7153) is dependent upon
interfaces proposed in (tokio-rs#7152).

pr tokio-rs#7152 proposes a `is_terminated()` method for the oneshot channel's
receiver. that is the proper method to use to check whether or not it is
safe to poll a oneshot receiver as a future.

this commit adds a note cross-referencing this method to the
documentation of `is_empty()`, to help mitigate misuse. this method only
reports whether a value is currently waiting in the channel; a channel
that has already received and yielded a value to its receiver is also
empty, but would panic when polled.

Signed-off-by: katelyn martin <[email protected]>
@maminrayej
Copy link
Member

Thanks.

@maminrayej maminrayej merged commit 17117b5 into tokio-rs:master Feb 16, 2025
82 checks passed
cratelyn added a commit to cratelyn/tokio that referenced this pull request Feb 16, 2025
NB: this commit means that this branch (tokio-rs#7153) is dependent upon
interfaces proposed in (tokio-rs#7152).

pr tokio-rs#7152 proposes a `is_terminated()` method for the oneshot channel's
receiver. that is the proper method to use to check whether or not it is
safe to poll a oneshot receiver as a future.

this commit adds a note cross-referencing this method to the
documentation of `is_empty()`, to help mitigate misuse. this method only
reports whether a value is currently waiting in the channel; a channel
that has already received and yielded a value to its receiver is also
empty, but would panic when polled.

Signed-off-by: katelyn martin <[email protected]>
@cratelyn cratelyn deleted the sync-oneshot.is_terminated branch February 16, 2025 20:46
@rushilmehra
Copy link

Lol this started causing some panics in production for us. Misuse on our part but it was a tricky one to root cause

@mox692
Copy link
Member

mox692 commented Apr 5, 2025

@rushilmehra Can you describe it in a separate issue? I think this change is not supposed to affect the existing code.

@rushilmehra
Copy link

rushilmehra commented Apr 6, 2025

@rushilmehra Can you describe it in a separate issue? I think this change is not supposed to affect the existing code.

We were accidentally polling a oneshot receiver after it was complete, honestly just misuse on our side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio Area: The main tokio crate M-sync Module: tokio/sync R-loom-sync Run loom sync tests on this PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants