Skip to content

Commit ecba7b3

Browse files
fix #1006
Signed-off-by: Nikolaj Bjorner <[email protected]>
1 parent fd19748 commit ecba7b3

File tree

3 files changed

+54
-5
lines changed

3 files changed

+54
-5
lines changed

src/api/api_solver.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,23 @@ extern "C" {
103103
m_out.flush();
104104
}
105105

106-
107-
solver2smt2_pp::solver2smt2_pp(ast_manager& m, char const* file): m_pp_util(m), m_out(file), m_tracked(m) {
106+
solver2smt2_pp::solver2smt2_pp(ast_manager& m, char const* file):
107+
m_pp_util(m), m_out(file), m_tracked(m) {
108108
if (!m_out) {
109109
throw default_exception("could not open " + std::string(file) + " for output");
110110
}
111111
}
112112

113+
void Z3_solver_ref::set_eh(event_handler* eh) {
114+
std::lock_guard<std::mutex> lock(m_mux);
115+
m_eh = eh;
116+
}
117+
118+
void Z3_solver_ref::set_cancel() {
119+
std::lock_guard<std::mutex> lock(m_mux);
120+
if (m_eh) (*m_eh)(API_INTERRUPT_EH_CALLER);
121+
}
122+
113123
void Z3_solver_ref::assert_expr(expr * e) {
114124
if (m_pp) m_pp->assert_expr(e);
115125
m_solver->assert_expr(e);
@@ -386,6 +396,10 @@ extern "C" {
386396
Z3_CATCH;
387397
}
388398

399+
void Z3_API Z3_solver_interrupt(Z3_context c, Z3_solver s) {
400+
to_solver(s)->set_cancel();
401+
}
402+
389403
void Z3_API Z3_solver_pop(Z3_context c, Z3_solver s, unsigned n) {
390404
Z3_TRY;
391405
LOG_Z3_solver_pop(c, s, n);
@@ -538,6 +552,7 @@ extern "C" {
538552
unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit());
539553
bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", true);
540554
cancel_eh<reslimit> eh(mk_c(c)->m().limit());
555+
to_solver(s)->set_eh(&eh);
541556
api::context::set_interruptable si(*(mk_c(c)), eh);
542557
lbool result;
543558
{
@@ -550,12 +565,16 @@ extern "C" {
550565
}
551566
catch (z3_exception & ex) {
552567
to_solver_ref(s)->set_reason_unknown(eh);
568+
to_solver(s)->set_eh(nullptr);
553569
if (!mk_c(c)->m().canceled()) {
554570
mk_c(c)->handle_exception(ex);
555571
}
556572
return Z3_L_UNDEF;
557573
}
574+
catch (...) {
575+
}
558576
}
577+
to_solver(s)->set_eh(nullptr);
559578
if (result == l_undef) {
560579
to_solver_ref(s)->set_reason_unknown(eh);
561580
}
@@ -730,6 +749,7 @@ extern "C" {
730749
unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit());
731750
bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", true);
732751
cancel_eh<reslimit> eh(mk_c(c)->m().limit());
752+
to_solver(s)->set_eh(&eh);
733753
api::context::set_interruptable si(*(mk_c(c)), eh);
734754
{
735755
scoped_ctrl_c ctrlc(eh, false, use_ctrl_c);
@@ -740,12 +760,16 @@ extern "C" {
740760
result = to_solver_ref(s)->get_consequences(_assumptions, _variables, _consequences);
741761
}
742762
catch (z3_exception & ex) {
763+
to_solver(s)->set_eh(nullptr);
743764
to_solver_ref(s)->set_reason_unknown(eh);
744765
_assumptions.finalize(); _consequences.finalize(); _variables.finalize();
745766
mk_c(c)->handle_exception(ex);
746767
return Z3_L_UNDEF;
747768
}
769+
catch (...) {
770+
}
748771
}
772+
to_solver(s)->set_eh(nullptr);
749773
if (result == l_undef) {
750774
to_solver_ref(s)->set_reason_unknown(eh);
751775
}
@@ -773,6 +797,7 @@ extern "C" {
773797
unsigned rlimit = to_solver(s)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit());
774798
bool use_ctrl_c = to_solver(s)->m_params.get_bool("ctrl_c", true);
775799
cancel_eh<reslimit> eh(mk_c(c)->m().limit());
800+
to_solver(s)->set_eh(&eh);
776801
api::context::set_interruptable si(*(mk_c(c)), eh);
777802
{
778803
scoped_ctrl_c ctrlc(eh, false, use_ctrl_c);
@@ -782,10 +807,14 @@ extern "C" {
782807
result.append(to_solver_ref(s)->cube(vars, cutoff));
783808
}
784809
catch (z3_exception & ex) {
810+
to_solver(s)->set_eh(nullptr);
785811
mk_c(c)->handle_exception(ex);
786812
return nullptr;
787813
}
814+
catch (...) {
815+
}
788816
}
817+
to_solver(s)->set_eh(nullptr);
789818
Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m());
790819
mk_c(c)->save_object(v);
791820
for (expr* e : result) {

src/api/api_solver.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ Revision History:
2222
#include "solver/solver.h"
2323

2424
struct solver2smt2_pp {
25-
ast_pp_util m_pp_util;
26-
std::ofstream m_out;
25+
ast_pp_util m_pp_util;
26+
std::ofstream m_out;
2727
expr_ref_vector m_tracked;
2828
unsigned_vector m_tracked_lim;
29+
2930
solver2smt2_pp(ast_manager& m, char const* file);
3031
void assert_expr(expr* e);
3132
void assert_expr(expr* e, expr* t);
@@ -34,6 +35,7 @@ struct solver2smt2_pp {
3435
void reset();
3536
void check(unsigned n, expr* const* asms);
3637
void get_consequences(expr_ref_vector const& assumptions, expr_ref_vector const& variables);
38+
3739
};
3840

3941
struct Z3_solver_ref : public api::object {
@@ -42,12 +44,18 @@ struct Z3_solver_ref : public api::object {
4244
params_ref m_params;
4345
symbol m_logic;
4446
scoped_ptr<solver2smt2_pp> m_pp;
47+
std::mutex m_mux;
48+
event_handler* m_eh;
49+
4550
Z3_solver_ref(api::context& c, solver_factory * f):
46-
api::object(c), m_solver_factory(f), m_solver(nullptr), m_logic(symbol::null) {}
51+
api::object(c), m_solver_factory(f), m_solver(nullptr), m_logic(symbol::null), m_eh(nullptr) {}
4752
~Z3_solver_ref() override {}
4853

4954
void assert_expr(expr* e);
5055
void assert_expr(expr* e, expr* t);
56+
void set_eh(event_handler* eh);
57+
void set_cancel();
58+
5159
};
5260

5361
inline Z3_solver_ref * to_solver(Z3_solver s) { return reinterpret_cast<Z3_solver_ref *>(s); }

src/api/z3_api.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6332,6 +6332,18 @@ extern "C" {
63326332
*/
63336333
void Z3_API Z3_solver_dec_ref(Z3_context c, Z3_solver s);
63346334

6335+
/**
6336+
\brief Solver local interrupt.
6337+
Normally you should use Z3_interrupt to cancel solvers because only
6338+
one solver is enabled concurrently per context.
6339+
However, per GitHub issue #1006, there are use cases where
6340+
it is more convenient to cancel a specific solver. Solvers
6341+
that are not selected for interrupts are left alone.
6342+
6343+
def_API('Z3_solver_interrupt', VOID, (_in(CONTEXT), _in(SOLVER)))
6344+
*/
6345+
void Z3_API Z3_solver_interrupt(Z3_context c, Z3_solver s);
6346+
63356347
/**
63366348
\brief Create a backtracking point.
63376349

0 commit comments

Comments
 (0)