@@ -32,6 +32,7 @@ Module Name:
3232#include  " solver/mus.h" 
3333#include  " solver/parallel_tactical.h" 
3434#include  " solver/parallel_params.hpp" 
35+ #include  < mutex> 
3536
3637typedef  obj_map<expr, expr *> expr2expr_map;
3738
@@ -43,11 +44,12 @@ class smt_tactic : public tactic {
4344    expr_ref_vector              m_vars;
4445    vector<std::pair<expr_ref, expr_ref>> m_values;
4546    statistics                   m_stats;
46-     smt::kernel*                  m_ctx = nullptr ;
47+     std::atomic< smt::kernel*>     m_ctx = nullptr ;
4748    symbol                       m_logic;
4849    progress_callback*           m_callback = nullptr ;
4950    bool                          m_candidate_models = false ;
5051    bool                          m_fail_if_inconclusive = false ;
52+     mutable  std::mutex           m_mutex;
5153
5254public: 
5355    smt_tactic (ast_manager& m, params_ref const  & p):
@@ -63,7 +65,7 @@ class smt_tactic : public tactic {
6365    }
6466
6567    ~smt_tactic () override  {
66-         SASSERT (m_ctx == nullptr );
68+         SASSERT (m_ctx. load ()  == nullptr );
6769    }
6870
6971    char  const * name () const  override  { return  " smt"  ; }
@@ -88,8 +90,8 @@ class smt_tactic : public tactic {
8890        fparams ().updt_params (p);
8991        m_params_ref.copy (p);
9092        m_logic = p.get_sym (symbol (" logic"  ), m_logic);
91-         if  (m_logic != symbol::null && m_ctx) {
92-             m_ctx->set_logic (m_logic);
93+         if  (m_logic != symbol::null && m_ctx. load () ) {
94+             m_ctx. load () ->set_logic (m_logic);
9395        }
9496        SASSERT (p.get_bool (" auto_config"  , fparams ().m_auto_config ) == fparams ().m_auto_config );
9597    }
@@ -99,12 +101,15 @@ class smt_tactic : public tactic {
99101        smt_params_helper::collect_param_descrs (r);
100102    }
101103
102- 
103104    void  collect_statistics (statistics & st) const  override  {
104-         if  (m_ctx)
105-             m_ctx->collect_statistics (st); //  ctx is still running...
106-         else 
107-             st.copy (m_stats);
105+         if  (m_ctx.load ()) {
106+             std::scoped_lock lock (m_mutex);
107+             if  (m_ctx.load ()) {
108+                 m_ctx.load ()->collect_statistics (st); //  ctx is still running...
109+                 return ;
110+             }
111+         }
112+         st.copy (m_stats);
108113    }
109114
110115    void  cleanup () override  {
@@ -141,10 +146,13 @@ class smt_tactic : public tactic {
141146        }
142147
143148        ~scoped_init_ctx () {
144-             smt::kernel * d = m_owner.m_ctx ;
145-             m_owner.m_ctx  = nullptr ;
146-             m_owner.m_user_ctx  = nullptr ;
147- 
149+             smt::kernel* d = nullptr ;
150+             {
151+                 std::scoped_lock lock (m_owner.m_mutex );
152+                 d = m_owner.m_ctx .load ();
153+                 m_owner.m_ctx  = nullptr ;
154+                 m_owner.m_user_ctx  = nullptr ;
155+             }
148156            if  (d)
149157                dealloc (d);
150158        }
@@ -169,7 +177,7 @@ class smt_tactic : public tactic {
169177            TRACE (smt_tactic_detail, in->display (tout););
170178            TRACE (smt_tactic_memory, tout << " wasted_size: "   << m.get_allocator ().get_wasted_size () << " \n "  ;);
171179            scoped_init_ctx  init (*this , m);
172-             SASSERT (m_ctx);
180+             SASSERT (m_ctx. load () );
173181
174182            expr_ref_vector clauses (m);
175183            expr2expr_map               bool2dep;
@@ -182,41 +190,40 @@ class smt_tactic : public tactic {
182190                if  (in->proofs_enabled () && !assumptions.empty ())
183191                    throw  tactic_exception (" smt tactic does not support simultaneous generation of proofs and unsat cores"  );
184192                for  (unsigned  i = 0 ; i < clauses.size (); ++i) {
185-                     m_ctx->assert_expr (clauses[i].get ());
193+                     m_ctx. load () ->assert_expr (clauses[i].get ());
186194                }
187195            }
188196            else  if  (in->proofs_enabled ()) {
189197                unsigned  sz = in->size ();
190198                for  (unsigned  i = 0 ; i < sz; i++) {
191-                     m_ctx->assert_expr (in->form (i), in->pr (i));
199+                     m_ctx. load () ->assert_expr (in->form (i), in->pr (i));
192200                }
193201            }
194202            else  {
195203                unsigned  sz = in->size ();
196204                for  (unsigned  i = 0 ; i < sz; i++) {
197-                     m_ctx->assert_expr (in->form (i));
205+                     m_ctx. load () ->assert_expr (in->form (i));
198206                }
199207            }
200-             if  (m_ctx->canceled ()) {                 
208+             if  (m_ctx. load () ->canceled ()) {
201209                throw  tactic_exception (Z3_CANCELED_MSG);
202210            }
203211            user_propagate_delay_init ();
204212
205213            lbool r;
206214            try  {
207215                if  (assumptions.empty () && !m_user_ctx)
208-                     r = m_ctx->setup_and_check ();
216+                     r = m_ctx. load () ->setup_and_check ();
209217                else 
210-                     r = m_ctx->check (assumptions.size (), assumptions.data ());
218+                     r = m_ctx. load () ->check (assumptions.size (), assumptions.data ());
211219            }
212220            catch (...) {
213221                TRACE (smt_tactic, tout << " exception\n "  ;);
214-                 m_ctx->collect_statistics (m_stats);
222+                 m_ctx. load () ->collect_statistics (m_stats);
215223                throw ;
216224            }
217-             SASSERT (m_ctx);
218-             m_ctx->collect_statistics (m_stats);
219-             proof_ref pr (m_ctx->get_proof (), m);
225+             m_ctx.load ()->collect_statistics (m_stats);
226+             proof_ref pr (m_ctx.load ()->get_proof (), m);
220227            TRACE (smt_tactic, tout << r << "  "   << pr << " \n "  ;);
221228            switch  (r) {
222229            case  l_true: {
@@ -228,17 +235,17 @@ class smt_tactic : public tactic {
228235                //  store the model in a no-op model converter, and filter fresh Booleans
229236                if  (in->models_enabled ()) {
230237                    model_ref md;
231-                     m_ctx->get_model (md);
238+                     m_ctx. load () ->get_model (md);
232239                    buffer<symbol> r;
233-                     m_ctx->get_relevant_labels (nullptr , r);
240+                     m_ctx. load () ->get_relevant_labels (nullptr , r);
234241                    labels_vec rv;
235242                    rv.append (r.size (), r.data ());
236243                    model_converter_ref mc;
237244                    mc = model_and_labels2model_converter (md.get (), rv);
238245                    mc = concat (fmc.get (), mc.get ());
239246                    in->add (mc.get ());
240247                }
241-                 if  (m_ctx->canceled ()) 
248+                 if  (m_ctx. load () ->canceled ()) 
242249                    throw  tactic_exception (Z3_CANCELED_MSG);                
243250                return ;
244251            }
@@ -251,9 +258,9 @@ class smt_tactic : public tactic {
251258                in->reset ();
252259                expr_dependency * lcore = nullptr ;
253260                if  (in->unsat_core_enabled ()) {
254-                     unsigned  sz = m_ctx->get_unsat_core_size ();
261+                     unsigned  sz = m_ctx. load () ->get_unsat_core_size ();
255262                    for  (unsigned  i = 0 ; i < sz; i++) {
256-                         expr * b = m_ctx->get_unsat_core_expr (i);
263+                         expr * b = m_ctx. load () ->get_unsat_core_expr (i);
257264                        SASSERT (is_uninterp_const (b) && m.is_bool (b));
258265                        expr * d = bool2dep.find (b);
259266                        lcore = m.mk_join (lcore, m.mk_leaf (d));
@@ -269,13 +276,13 @@ class smt_tactic : public tactic {
269276            }
270277            case  l_undef:
271278
272-                 if  (m_ctx->canceled () && !pr) {
279+                 if  (m_ctx. load () ->canceled () && !pr) {
273280                    throw  tactic_exception (Z3_CANCELED_MSG);
274281                }
275282
276283                if  (m_fail_if_inconclusive && !m_candidate_models && !pr) {
277284                    std::stringstream strm;
278-                     strm << " smt tactic failed to show goal to be sat/unsat "   << m_ctx->last_failure_as_string ();
285+                     strm << " smt tactic failed to show goal to be sat/unsat "   << m_ctx. load () ->last_failure_as_string ();
279286                    throw  tactic_exception (strm.str ());
280287                }
281288                result.push_back (in.get ());
@@ -285,15 +292,15 @@ class smt_tactic : public tactic {
285292                    in->updt_prec (goal::UNDER_OVER);
286293                }
287294                if  (m_candidate_models) {
288-                     switch  (m_ctx->last_failure ()) {
295+                     switch  (m_ctx. load () ->last_failure ()) {
289296                    case  smt::NUM_CONFLICTS:
290297                    case  smt::THEORY:
291298                    case  smt::QUANTIFIERS:
292299                        if  (in->models_enabled ()) {
293300                            model_ref md;
294-                             m_ctx->get_model (md);
301+                             m_ctx. load () ->get_model (md);
295302                            buffer<symbol> r;
296-                             m_ctx->get_relevant_labels (nullptr , r);
303+                             m_ctx. load () ->get_relevant_labels (nullptr , r);
297304                            labels_vec rv;
298305                            rv.append (r.size (), r.data ());
299306                            in->add (model_and_labels2model_converter (md.get (), rv));
@@ -306,7 +313,7 @@ class smt_tactic : public tactic {
306313                if  (pr) {
307314                    return ;
308315                }
309-                 throw  tactic_exception (m_ctx->last_failure_as_string ());
316+                 throw  tactic_exception (m_ctx. load () ->last_failure_as_string ());
310317            }
311318        }
312319        catch  (rewriter_exception & ex) {
@@ -329,24 +336,24 @@ class smt_tactic : public tactic {
329336
330337    void  on_clause_delay_init () {
331338        if  (m_on_clause_eh)
332-             m_ctx->register_on_clause (m_on_clause_ctx, m_on_clause_eh);
339+             m_ctx. load () ->register_on_clause (m_on_clause_ctx, m_on_clause_eh);
333340    }
334341
335342    void  user_propagate_delay_init () {
336343        if  (!m_user_ctx)
337344            return ;
338-         m_ctx->user_propagate_init (m_user_ctx, m_push_eh, m_pop_eh, m_fresh_eh);
339-         if  (m_fixed_eh)   m_ctx->user_propagate_register_fixed (m_fixed_eh);
340-         if  (m_final_eh)   m_ctx->user_propagate_register_final (m_final_eh);
341-         if  (m_eq_eh)      m_ctx->user_propagate_register_eq (m_eq_eh);
342-         if  (m_diseq_eh)   m_ctx->user_propagate_register_diseq (m_diseq_eh);
343-         if  (m_created_eh) m_ctx->user_propagate_register_created (m_created_eh);
344-         if  (m_decide_eh) m_ctx->user_propagate_register_decide (m_decide_eh);
345+         m_ctx. load () ->user_propagate_init (m_user_ctx, m_push_eh, m_pop_eh, m_fresh_eh);
346+         if  (m_fixed_eh)   m_ctx. load () ->user_propagate_register_fixed (m_fixed_eh);
347+         if  (m_final_eh)   m_ctx. load () ->user_propagate_register_final (m_final_eh);
348+         if  (m_eq_eh)      m_ctx. load () ->user_propagate_register_eq (m_eq_eh);
349+         if  (m_diseq_eh)   m_ctx. load () ->user_propagate_register_diseq (m_diseq_eh);
350+         if  (m_created_eh) m_ctx. load () ->user_propagate_register_created (m_created_eh);
351+         if  (m_decide_eh) m_ctx. load () ->user_propagate_register_decide (m_decide_eh);
345352
346353        for  (expr* v : m_vars) 
347-             m_ctx->user_propagate_register_expr (v);
354+             m_ctx. load () ->user_propagate_register_expr (v);
348355        for  (auto & [var, value] : m_values)
349-             m_ctx->user_propagate_initialize_value (var, value);
356+             m_ctx. load () ->user_propagate_initialize_value (var, value);
350357    }
351358
352359    void  user_propagate_clear () override  {
0 commit comments