model: add too_many_steps()
[model-checker.git] / model.cc
index feda416222de94f460291ee7f6a6ea15a21ddf22..eed548cc0c906b0d50b6c78f89e51e15aa4b4e1b 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -2,6 +2,7 @@
 #include <algorithm>
 #include <mutex>
 #include <new>
+#include <stdarg.h>
 
 #include "model.h"
 #include "action.h"
@@ -15,6 +16,7 @@
 #include "datarace.h"
 #include "threads-model.h"
 #include "output.h"
+#include "traceanalysis.h"
 
 #define INITIAL_THREAD_ID      0
 
@@ -91,6 +93,7 @@ ModelChecker::ModelChecker(struct model_params params) :
        thrd_last_action(new SnapVector<ModelAction *>(1)),
        thrd_last_fence_release(new SnapVector<ModelAction *>()),
        node_stack(new NodeStack()),
+       trace_analyses(new ModelVector<Trace_Analysis *>()),
        priv(new struct model_snapshot_members()),
        mo_graph(new CycleGraph())
 {
@@ -120,6 +123,9 @@ ModelChecker::~ModelChecker()
        delete thrd_last_action;
        delete thrd_last_fence_release;
        delete node_stack;
+       for (unsigned int i = 0; i < trace_analyses->size(); i++)
+               delete (*trace_analyses)[i];
+       delete trace_analyses;
        delete scheduler;
        delete mo_graph;
        delete priv;
@@ -145,6 +151,18 @@ static SnapVector<action_list_t> * get_safe_ptr_vect_action(HashTable<void *, Sn
        return tmp;
 }
 
+action_list_t * ModelChecker::get_actions_on_obj(void * obj, thread_id_t tid) {
+       SnapVector<action_list_t> *wrv=obj_thrd_map->get(obj);
+       if (wrv==NULL)
+               return NULL;
+       unsigned int thread=id_to_int(tid);
+       if (thread < wrv->size())
+               return &(*wrv)[thread];
+       else
+               return NULL;
+}
+
+
 /**
  * Restores user program to initial state and resets all model-checker data
  * structures.
@@ -419,9 +437,16 @@ bool ModelChecker::is_complete_execution() const
  * @param msg Descriptive message for the bug (do not include newline char)
  * @return True if bug is immediately-feasible
  */
-bool ModelChecker::assert_bug(const char *msg)
+bool ModelChecker::assert_bug(const char *msg, ...)
 {
-       priv->bugs.push_back(new bug_message(msg));
+       char str[800];
+
+       va_list ap;
+       va_start(ap, msg);
+       vsnprintf(str, sizeof(str), msg, ap);
+       va_end(ap);
+
+       priv->bugs.push_back(new bug_message(str));
 
        if (isfeasibleprefix()) {
                set_assert();
@@ -545,6 +570,7 @@ bool ModelChecker::next_execution()
                        assert_bug("Deadlock detected");
 
                checkDataRaces();
+               run_trace_analyses();
        }
 
        record_stats();
@@ -570,6 +596,12 @@ bool ModelChecker::next_execution()
        return true;
 }
 
+/** @brief Run trace analyses on complete trace */
+void ModelChecker::run_trace_analyses() {
+       for (unsigned int i = 0; i < trace_analyses->size(); i++)
+               (*trace_analyses)[i]->analyze(action_trace);
+}
+
 /**
  * @brief Find the last fence-related backtracking conflict for a ModelAction
  *
@@ -1492,8 +1524,6 @@ ModelAction * ModelChecker::check_current_action(ModelAction *curr)
        bool newly_explored = initialize_curr_action(&curr);
 
        DBG();
-       if (DBG_ENABLED())
-               curr->print();
 
        wake_up_sleeping_actions(curr);
 
@@ -1790,16 +1820,15 @@ bool ModelChecker::check_recency(ModelAction *curr, const T *rf) const
 }
 
 /**
- * Updates the mo_graph with the constraints imposed from the current
+ * @brief Updates the mo_graph with the constraints imposed from the current
  * read.
  *
  * Basic idea is the following: Go through each other thread and find
  * the last action that happened before our read.  Two cases:
  *
- * (1) The action is a write => that write must either occur before
+ * -# The action is a write: that write must either occur before
  * the write we read from or be the write we read from.
- *
- * (2) The action is a read => the write that that action read from
+ * -# The action is a read: the write that that action read from
  * must occur before the write we read from or be the same write.
  *
  * @param curr The current action. Must be a read.
@@ -3084,6 +3113,12 @@ void user_main_wrapper(void *)
        user_main(model->params.argc, model->params.argv);
 }
 
+/** @return True if the execution has taken too many steps */
+bool ModelChecker::too_many_steps() const
+{
+       return params.bound != 0 && priv->used_sequence_numbers > params.bound;
+}
+
 bool ModelChecker::should_terminate_execution()
 {
        /* Infeasible -> don't take any more steps */
@@ -3094,7 +3129,7 @@ bool ModelChecker::should_terminate_execution()
                return true;
        }
 
-       if (params.bound != 0 && priv->used_sequence_numbers > params.bound)
+       if (too_many_steps())
                return true;
        return false;
 }
@@ -3120,7 +3155,7 @@ void ModelChecker::run()
                                if (!thr->is_model_thread() && !thr->is_complete() && !thr->get_pending()) {
                                        switch_from_master(thr);
                                        if (thr->is_waiting_on(thr))
-                                               assert_bug("Deadlock detected");
+                                               assert_bug("Deadlock detected (thread %u)", i);
                                }
                        }