model: proactively build/prune is_enabled() set
[model-checker.git] / model.cc
index f385e560f085cc9af3aec101207f732a7a3ef8e3..feda416222de94f460291ee7f6a6ea15a21ddf22 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -1489,15 +1489,6 @@ ModelAction * ModelChecker::check_current_action(ModelAction *curr)
 {
        ASSERT(curr);
        bool second_part_of_rmw = curr->is_rmwc() || curr->is_rmw();
-
-       if (!check_action_enabled(curr)) {
-               /* Make the execution look like we chose to run this action
-                * much later, when a lock/join can succeed */
-               get_thread(curr)->set_pending(curr);
-               scheduler->sleep(get_thread(curr));
-               return NULL;
-       }
-
        bool newly_explored = initialize_curr_action(&curr);
 
        DBG();
@@ -3077,32 +3068,14 @@ Thread * ModelChecker::take_step(ModelAction *curr)
        Thread *curr_thrd = get_thread(curr);
        ASSERT(curr_thrd->get_state() == THREAD_READY);
 
+       ASSERT(check_action_enabled(curr)); /* May have side effects? */
        curr = check_current_action(curr);
-
-       /* Infeasible -> don't take any more steps */
-       if (is_infeasible())
-               return NULL;
-       else if (isfeasibleprefix() && have_bug_reports()) {
-               set_assert();
-               return NULL;
-       }
-
-       if (params.bound != 0 && priv->used_sequence_numbers > params.bound)
-               return NULL;
+       ASSERT(curr);
 
        if (curr_thrd->is_blocked() || curr_thrd->is_complete())
                scheduler->remove_thread(curr_thrd);
 
-       Thread *next_thrd = NULL;
-       if (curr)
-               next_thrd = action_select_next_thread(curr);
-       if (!next_thrd)
-               next_thrd = get_next_thread();
-
-       DEBUG("(%d, %d)\n", curr_thrd ? id_to_int(curr_thrd->get_id()) : -1,
-                       next_thrd ? id_to_int(next_thrd->get_id()) : -1);
-
-       return next_thrd;
+       return action_select_next_thread(curr);
 }
 
 /** Wrapper to run the user's main function, with appropriate arguments */
@@ -3111,6 +3084,21 @@ void user_main_wrapper(void *)
        user_main(model->params.argc, model->params.argv);
 }
 
+bool ModelChecker::should_terminate_execution()
+{
+       /* Infeasible -> don't take any more steps */
+       if (is_infeasible())
+               return true;
+       else if (isfeasibleprefix() && have_bug_reports()) {
+               set_assert();
+               return true;
+       }
+
+       if (params.bound != 0 && priv->used_sequence_numbers > params.bound)
+               return true;
+       return false;
+}
+
 /** @brief Run ModelChecker for the user program */
 void ModelChecker::run()
 {
@@ -3136,16 +3124,30 @@ void ModelChecker::run()
                                }
                        }
 
+                       /* Don't schedule threads which should be disabled */
+                       for (unsigned int i = 0; i < get_num_threads(); i++) {
+                               Thread *th = get_thread(int_to_id(i));
+                               ModelAction *act = th->get_pending();
+                               if (act && is_enabled(th) && !check_action_enabled(act)) {
+                                       scheduler->sleep(th);
+                               }
+                       }
+
                        /* Catch assertions from prior take_step or from
                         * between-ModelAction bugs (e.g., data races) */
                        if (has_asserted())
                                break;
 
+                       if (!t)
+                               t = get_next_thread();
+                       if (!t || t->is_model_thread())
+                               break;
+
                        /* Consume the next action for a Thread */
                        ModelAction *curr = t->get_pending();
                        t->set_pending(NULL);
                        t = take_step(curr);
-               } while (t && !t->is_model_thread());
+               } while (!should_terminate_execution());
 
                /*
                 * Launch end-of-execution release sequence fixups only when