-
-
Notifications
You must be signed in to change notification settings - Fork 89
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
ref: make Context::alloc_ongoing return a guard #4248
Conversation
This guard can be awaited and will resolve when Context::stop_ongoing is called, i.e. the ongoing process is cancelled. The guard will also free the ongoing process when dropped, making it RAII and easier to not accidentally free the ongoing process.
This is now handled better by the Drop from the OngoingGuard returned by Context::alloc_ongoing.
This also found a real bug: #4249 |
@@ -536,21 +553,24 @@ impl Context { | |||
/// Signal an ongoing process to stop. | |||
pub async fn stop_ongoing(&self) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe cancel_ongoing()? Because it doesn't actually wait for the ongoing process to stop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I agree that cancel_ongoing()
would be a nicer name. I guess I could change that as well. I didn't touch it because it is a pub API though and I feel like if we try and rename it maybe it should also be renamed in the FFI and JSON-RPC APIs and now we're breaking all clients. That seemed like a bit too much work for a slightly unfortunate name.
RunningState::ShallStop | RunningState::Stopped => { | ||
// Put back the current state | ||
*s = current_state; | ||
info!(self, "No ongoing process to stop.",); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this log correct for ShallStop
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kind off, yes. The ongoing process is already requested to stop so there's no ongoing process to stop. 🤷
I am completely stumped by the test failure since merging master... it's not a flaky failure. |
@flub Could you rebase it or redo it on top of the current |
oh wow, i completely lost sight of this. yes, i'll update it |
I guess now this PR also should go to |
Yes, |
I looked a bit at the failures now. And while I could fix them I'm a bit unsure how to proceed: The failures occurring are because async drop is difficult. So this PR works around that by spawning a task when the drop guard is created and the drop guard itself only sends a message to that task to do run the drop impl. The major problem with this approach is that drop is no longer deterministic. It could run any other time. And this is what makes the tests falky now: sometimes drop has run, sometimes it hasn't and the context is not yet freed. One could argue this is a matter of more synchronisation: I can add code that sends a signal when drop is finished and we can await until the mutex is truly freed. However this makes using it again brittle: because it is easy enough to write code that may suddenly need to rely on this signal, but nothing forces you to do it. And often you'll only realise with difficult to track bugs. This kind of was the entire point of the drop guard: to make it easier to write correct code. But this drop guard impl does not achieve that because it moves some other subtle synchronisation issues to the user. So really, the only way to make this drop guard work is to really release the mutex in the sync Drop code. Maybe that's doable somehow, but it's so easy. |
Btw, the same problem as i had in |
@@ -250,7 +252,7 @@ pub struct InnerContext { | |||
#[derive(Debug)] | |||
enum RunningState { | |||
/// Ongoing process is allocated. | |||
Running { cancel_sender: Sender<()> }, | |||
Running { cancel_sender: oneshot::Sender<()> }, | |||
|
|||
/// Cancel signal has been sent, waiting for ongoing process to be freed. | |||
ShallStop { request: Instant }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm unsure we want to use Instant
anywhere because it may freeze during the deep sleep on some systems e.g. Android. In #5108 i'm removing it
1abb12e
to
2af9ff1
Compare
I'm closing this for now and adding it to Project resurrection since there was no progress since a long time and it needs a rebase (I didn't look the PR yet, so I don't have an opinion on whether the refactoring is worth it). |
This guard can be awaited and will resolve when Context::stop_ongoing
is called, i.e. the ongoing process is cancelled. The guard will also
free the ongoing process when dropped, making it RAII and easier to
not accidentally free the ongoing process.
#skip-changelog