-
Notifications
You must be signed in to change notification settings - Fork 112
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
fix: Cancellation tokens to cancel and restart checkers #497
fix: Cancellation tokens to cancel and restart checkers #497
Conversation
…e into cancellationToken2
This reverts commit cbecd05.
…nd do not let SMTLibProcess have cancellation support
…e into cancellationToken2
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 don't have enough context to do a sufficient review, but this looks very nice. Can you say why you can ignore the CancelledException early on?
lock (this) { | ||
if (outputReceivers.TryDequeue(out var source)) { | ||
source.SetResult(null); | ||
} |
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.
Could there be more than one item in the queue here? Is it safe to remove just one?
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.
There's a while
so it should remove all of them. I guess you reviewed an older version with just an if
:)
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.
There cannot be two things waiting for it in our current code be because we always prefix the calls to getProverResponse
with await
. However, as a safeguard for future problems that are unlikely to happend, we added the comment that this class is not thread-safe, meaning it should be also used only with one thread (which is what happens, it is owned by a Checker that runs the prover on only one thread.)
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 guess you reviewed an older version with just an if :)
!! Precisely right :)
@@ -632,12 +644,12 @@ private void RecoverIfProverCrashedAfterReset() | |||
|
|||
public override void FullReset(VCExpressionGenerator gen) | |||
{ | |||
if (options.Solver == SolverKind.Z3) | |||
if (options.Solver == SolverKind.Z3 || options.Solver == SolverKind.NoOpWithZ3Options) |
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.
👍
} | ||
SendThisVC("(push 1)"); | ||
var result = action(); | ||
popLater = true; |
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.
This function always set poplater to true, right?
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.
Yes
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 not a fan of this API and its out popLater
parameter, but I'm fine with sticking with what the code used to do.
hasOutput = true; | ||
proverRunTime = DateTime.UtcNow - proverStart; | ||
switch (outcome) | ||
{ |
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.
This would be a good use case for a dictionary
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 can't find the code on which you made this comment, so I don't know how to reply.
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 think it's the switch that converts the outcome to a string..
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.
The code is the switch on outcome
in WaitForOutput. But since all that this PR does to it is reindent it, it's probably not worth changing it.
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.
@@ -39,8 +39,6 @@ public ConditionGenerationContracts(Program p, CheckerPool checkerPool) | |||
[ContractClass(typeof(ConditionGenerationContracts))] | |||
public abstract class ConditionGeneration : IDisposable | |||
{ | |||
protected internal object CheckerCommonState; | |||
|
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.
🎉
public virtual string[] CalculatePath(int controlFlowConstant) | ||
{ | ||
throw new System.NotImplementedException(); | ||
} |
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.
Oh, nice! This doesn't need to be here?
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.
Not for https://github.com/boogie-org/boogie
, but possibly for a consumer of https://github.com/boogie-org/boogie
, although I don't see why you would want to override this. For APIs that are [unexpectedly] used outside of Boogie, we should document the use-case and mark the API with an annotation, like [PublicAPI]
, otherwise it'll be impossible to make changes to Boogie without fear of breaking a consumer.
split.ReleaseChecker(); | ||
throw; |
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.
Have you tested this against a badly-behaved prover? I'm worried that this could undo the fix from #488.
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.
Since we don't catch the exception, we also don't have to rethrow it since it's thrown up automatically. Where does your concern come from?
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.
Ah, right, the change from catch
to finally
should avoid it. And there is a test that would be failing if this change did undo that fix. 👍
/// </summary> | ||
public Checker(CheckerPool pool, VC.ConditionGeneration vcgen, Program prog, string /*?*/ logFilePath, bool appendLogFile, | ||
Split split, ProverContext ctx = null) | ||
public Checker(CheckerPool pool, string /*?*/ logFilePath, bool appendLogFile) |
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 like that Checker
is no longer initialized with program-specific data.
while (true) { | ||
var exprs = await ParseSExprs(true).ToListAsync(); | ||
Contract.Assert(exprs.Count <= 1); | ||
if (exprs.Count == 0) { | ||
return null; | ||
} | ||
|
||
var resp = exprs[0]; |
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.
The existing code ignores possible malformed output from the underlying prover, right? I guess it's OK since it was already like that.
HandleError(error); | ||
errorCnt++; | ||
error = null; | ||
lock (this) { |
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.
Do you want external clients to be able take this lock? If not I'd use a private object.
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.
Oh but I see below that the code was already like this, sorry
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.
Ah, good point. Never thought of that. Is it worth the extra code though? External clients taking the lock seems like only a theoretical issue.
{ | ||
if (e.Data != null) | ||
lock (this) { | ||
if (e.Data == null) |
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.
In the method above you moved the e.data test out of the lock, but not here. Could you do the same here? It would avoid taking the lock when e.Data
is null
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.
LGTM, none of my comments are blocking
This PR enables Boogie's execution engine to effectively kill verification on demand, and recycle killed checkers/SMTLib processes
Changes
Checker
if its associated prover is responsivePipelineOutcome.Cancelled
outcome if a request was cancelled.Issues it fixes
This PR should be able to fix the following bugs:
dafny-lang/ide-vscode#119
dafny-lang/ide-vscode#114
dafny-lang/ide-vscode#96
How it has been tested
Add a unit test
InferAndVerifyCanBeCancelledWhileWaitingForProver
Dafny tests
fix: "Stuck on Verifying..." dafny-lang/dafny#1771
It takes a program which is hard to verify, and two changes that makes it easy to verify and then a parse error.
Without this PR, the test fails and loops indefinitely on the first program.
With this PR, the tests succeeds and all the changes are taken into account.