|
38 | 38 | import java.util.concurrent.atomic.AtomicBoolean; |
39 | 39 | import org.checkerframework.checker.nullness.qual.Nullable; |
40 | 40 | import org.sosy_lab.common.ShutdownNotifier; |
| 41 | +import org.sosy_lab.common.ShutdownNotifier.ShutdownRequestListener; |
41 | 42 | import org.sosy_lab.java_smt.api.BasicProverEnvironment; |
42 | 43 | import org.sosy_lab.java_smt.api.BooleanFormula; |
43 | 44 | import org.sosy_lab.java_smt.api.BooleanFormulaManager; |
|
50 | 51 | class CVC4TheoremProver extends AbstractProverWithAllSat<Void> |
51 | 52 | implements ProverEnvironment, BasicProverEnvironment<Void> { |
52 | 53 |
|
| 54 | + private final class ShutdownHook implements ShutdownRequestListener { |
| 55 | + private final AtomicBoolean interrupted = new AtomicBoolean(false); |
| 56 | + |
| 57 | + @Override |
| 58 | + public void shutdownRequested(String reason) { |
| 59 | + interrupted.set(true); |
| 60 | + while (interrupted.get()) { // flag is reset after leaving isUnsat() |
| 61 | + smtEngine.interrupt(); |
| 62 | + try { |
| 63 | + Thread.sleep(10); |
| 64 | + } catch (InterruptedException e) { |
| 65 | + } |
| 66 | + } |
| 67 | + } |
| 68 | + } |
| 69 | + |
53 | 70 | private final CVC4FormulaCreator creator; |
54 | | - private SmtEngine smtEngine; |
| 71 | + private SmtEngine smtEngine; // final except for SL theory |
| 72 | + private ShutdownHook hook; // final except for SL theory |
55 | 73 | private boolean changedSinceLastSatQuery = false; |
56 | 74 |
|
57 | | - protected final AtomicBoolean interrupted = new AtomicBoolean(false); |
58 | | - |
59 | 75 | /** Tracks formulas on the stack, needed for model generation. */ |
60 | 76 | protected final Deque<List<Expr>> assertedFormulas = new ArrayDeque<>(); |
61 | 77 |
|
@@ -94,7 +110,7 @@ protected CVC4TheoremProver( |
94 | 110 | assertedFormulas.push(new ArrayList<>()); // create initial level |
95 | 111 |
|
96 | 112 | setOptions(randomSeed, pOptions); |
97 | | - registerShutdownHandler(pShutdownNotifier); |
| 113 | + hook = registerShutdownHandler(pShutdownNotifier); |
98 | 114 | } |
99 | 115 |
|
100 | 116 | private void setOptions(int randomSeed, Set<ProverOptions> pOptions) { |
@@ -122,18 +138,10 @@ protected void setOptionForIncremental() { |
122 | 138 | // method SmtEngine::check(), which seems to take about 10 ms. When this is fixed in |
123 | 139 | // CVC4, we can remove the Thread.sleep(10), the AtomicBoolean interrupted and the while |
124 | 140 | // loop surrounding this block. |
125 | | - private void registerShutdownHandler(ShutdownNotifier pShutdownNotifier) { |
126 | | - pShutdownNotifier.register( |
127 | | - (reason) -> { |
128 | | - interrupted.set(true); |
129 | | - while (interrupted.get()) { |
130 | | - smtEngine.interrupt(); |
131 | | - try { |
132 | | - Thread.sleep(10); |
133 | | - } catch (InterruptedException e) { |
134 | | - } |
135 | | - } |
136 | | - }); |
| 141 | + private ShutdownHook registerShutdownHandler(ShutdownNotifier pShutdownNotifier) { |
| 142 | + ShutdownHook listener = new ShutdownHook(); |
| 143 | + pShutdownNotifier.register(listener); |
| 144 | + return listener; |
137 | 145 | } |
138 | 146 |
|
139 | 147 | /** import an expression from global context into this prover's context. */ |
@@ -204,8 +212,9 @@ private void setChanged() { |
204 | 212 | closeAllModels(); |
205 | 213 | if (!incremental) { |
206 | 214 | // create a new clean smtEngine |
| 215 | + shutdownNotifier.unregister(hook); |
207 | 216 | smtEngine = new SmtEngine(exprManager); |
208 | | - registerShutdownHandler(shutdownNotifier); |
| 217 | + hook = registerShutdownHandler(shutdownNotifier); |
209 | 218 | } |
210 | 219 | } |
211 | 220 | } |
@@ -241,10 +250,18 @@ public boolean isUnsat() throws InterruptedException, SolverException { |
241 | 250 | smtEngine.assertFormula(importExpr(expr)); |
242 | 251 | } |
243 | 252 | } |
244 | | - Result result = smtEngine.checkSat(); |
245 | | - if (interrupted.get()) { |
246 | | - interrupted.set(false); // Should we throw InterruptException? |
| 253 | + shutdownNotifier.shutdownIfNecessary(); |
| 254 | + Result result; |
| 255 | + try { |
| 256 | + result = smtEngine.checkSat(); |
| 257 | + } finally { |
| 258 | + hook.interrupted.set(false); |
| 259 | + shutdownNotifier.shutdownIfNecessary(); |
247 | 260 | } |
| 261 | + return convertSatResult(result); |
| 262 | + } |
| 263 | + |
| 264 | + private boolean convertSatResult(Result result) throws InterruptedException, SolverException { |
248 | 265 | if (result.isUnknown()) { |
249 | 266 | if (result.whyUnknown().equals(Result.UnknownExplanation.INTERRUPTED)) { |
250 | 267 | throw new InterruptedException(); |
@@ -299,6 +316,7 @@ public void close() { |
299 | 316 | exportMapping.delete(); |
300 | 317 | // smtEngine.delete(); |
301 | 318 | exprManager.delete(); |
| 319 | + shutdownNotifier.unregister(hook); |
302 | 320 | closed = true; |
303 | 321 | } |
304 | 322 | } |
|
0 commit comments