Skip to content

sync: implement 'Clone' for watch::Sender #5936

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

Closed
wants to merge 3 commits into from

Conversation

bouk
Copy link

@bouk bouk commented Aug 16, 2023

Here I'm implement Clone for watch::Sender, which makes it mpsc

TODO

  • Update docs to make it clear it's mpmc

Motivation

See #4809

Solution

I've implemented one of the suggestions in the issue, which is to keep track of the number of Senders separate from the version.

Open questions: are there other methods that need to be added? E.g. 'upgrading' a receiver to a sender or getting the number of current Senders

@github-actions github-actions bot added the R-loom-sync Run loom sync tests on this PR label Aug 16, 2023
Comment on lines 509 to 518
pub fn has_changed(&self) -> Result<bool, error::RecvError> {
// Load the version from the state
let state = self.shared.state.load();
if state.is_closed() {
if self.shared.is_sender_closed() {
// The sender has dropped.
return Err(error::RecvError(()));
}
let new_version = state.version();

// Load the version from the state
let new_version = self.shared.version();
Ok(self.version != new_version)
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method seems to not match maybe_changed because the order of checking whether it's closed and the version has changed is different. The behavior in other places is that it will give one last true when all the Senders are gone before returning an error, but here it gives an error even when there's an unobserved change.

Maybe I should change it to match behavior?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the inconsistency does exists, but

  • the current version do exactly as the comment say, Returns an error if the channel has been closed.
  • maybe_changed is not a pub method.

The impact of inconsistency may be not particularly large.

But the maybe_changed method does affect the behavior of pub method changed. The comments of changed should be modified to

This method returns an error if there is no new value in the channel has not yet been marked seen and all [`Sender`]s are dropped.

from

This method returns an error if and only if the [`Sender`] is dropped.

@Darksonn Darksonn added A-tokio Area: The main tokio crate M-sync Module: tokio/sync labels Aug 21, 2023
Comment on lines -554 to 517
// Load the version from the state
let state = self.shared.state.load();
if state.is_closed() {
if self.shared.is_sender_closed() {
// The sender has dropped.
return Err(error::RecvError(()));
}
let new_version = state.version();

// Load the version from the state
let new_version = self.shared.version();
Ok(self.version != new_version)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you've split the closed bit out from the atomic, this introduces extra possibilities for race conditions causing incorrect behavior. I would need some time to think about whether this is still correct.

@hawkw
Copy link
Member

hawkw commented Aug 25, 2023

It's interesting that the AtomicWaker loom tests are failing on this PR, when this branch hasn't actually changed AtomicWaker: https://github.com/tokio-rs/tokio/actions/runs/5923638182/job/16059659886?pr=5936#step:5:58

@Darksonn
Copy link
Contributor

This fails the watch smoke test:

thread 'sync::tests::loom_watch::smoke' panicked at 'called `Result::unwrap()` on an `Err` value: RecvError(())', tokio/src/sync/tests/loom_watch.rs:20:33
stack backtrace:
   0: rust_begin_unwind
             at /rustc/eb26296b556cef10fb713a38f3d16b9886080f26/library/std/src/panicking.rs:593:5
   1: core::panicking::panic_fmt
             at /rustc/eb26296b556cef10fb713a38f3d16b9886080f26/library/core/src/panicking.rs:67:14
   2: core::result::unwrap_failed
             at /rustc/eb26296b556cef10fb713a38f3d16b9886080f26/library/core/src/result.rs:1651:5
   3: core::ops::function::FnOnce::call_once{{vtable.shim}}
   4: generator::stack::StackBox<F>::call_once
   5: std::panicking::try
   6: generator::gen_impl::gen_init
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
test sync::tests::loom_watch::smoke ... FAILED

@Darksonn
Copy link
Contributor

@hawkw Those are tests that are supposed to panic, so they print a panic but don't fail.

@Darksonn
Copy link
Contributor

This implementation is currently incorrect. I'll close this PR since there has been no activity for a while.

In either case, thanks for taking the time to submit a PR. If you want to continue working on it in the future, then please feel free to reopen or post a new PR.

@Darksonn Darksonn closed this Oct 22, 2023
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.

4 participants