action: rename 'node' members to 'treenode'
[model-checker.git] / model.cc
index d878abbc002124d4dcacd2651af3c1990f6c19b9..53411c64199529dcea4e463d1bb058f2ea6898ab 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -1,55 +1,97 @@
 #include <stdio.h>
 
 #include "model.h"
+#include "action.h"
+#include "tree.h"
 #include "schedule.h"
 #include "common.h"
 
 #define INITIAL_THREAD_ID      0
 
+class Backtrack {
+public:
+       Backtrack(ModelAction *d, action_list_t *t) {
+               diverge = d;
+               actionTrace = t;
+               iter = actionTrace->begin();
+       }
+       ModelAction * get_diverge() { return diverge; }
+       action_list_t * get_trace() { return actionTrace; }
+       void advance_state() { iter++; }
+       ModelAction * get_state() {
+               return iter == actionTrace->end() ? NULL : *iter;
+       }
+private:
+       ModelAction *diverge;
+       action_list_t *actionTrace;
+       /* points to position in actionTrace as we replay */
+       action_list_t::iterator iter;
+};
+
 ModelChecker *model;
 
+void free_action_list(action_list_t *list)
+{
+       action_list_t::iterator it;
+       for (it = list->begin(); it != list->end(); it++)
+               delete (*it);
+       delete list;
+}
+
 ModelChecker::ModelChecker()
 {
-       /* First thread created will have id (INITIAL_THREAD_ID + 1) */
-       this->used_thread_id = INITIAL_THREAD_ID;
+       /* First thread created will have id INITIAL_THREAD_ID */
+       next_thread_id = INITIAL_THREAD_ID;
+       used_sequence_numbers = 0;
        /* Initialize default scheduler */
-       this->scheduler = new Scheduler();
+       scheduler = new Scheduler();
 
        num_executions = 0;
-       this->current_action = NULL;
-       this->exploring = NULL;
-       this->nextThread = THREAD_ID_T_NONE;
+       current_action = NULL;
+       exploring = NULL;
+       nextThread = THREAD_ID_T_NONE;
 
-       rootNode = new TreeNode(NULL);
+       rootNode = new TreeNode();
        currentNode = rootNode;
        action_trace = new action_list_t();
 }
 
 ModelChecker::~ModelChecker()
 {
-       delete action_trace;
-       delete this->scheduler;
+       std::map<int, class Thread *>::iterator it;
+       for (it = thread_map.begin(); it != thread_map.end(); it++)
+               delete (*it).second;
+       thread_map.clear();
+
+       free_action_list(action_trace);
+
+       delete scheduler;
        delete rootNode;
 }
 
 void ModelChecker::reset_to_initial_state()
 {
        DEBUG("+++ Resetting to initial state +++\n");
-       std::map<thread_id_t, class Thread *>::iterator it;
-       for (it = thread_map.begin(); it != thread_map.end(); it++) {
+       std::map<int, class Thread *>::iterator it;
+       for (it = thread_map.begin(); it != thread_map.end(); it++)
                delete (*it).second;
-       }
        thread_map.clear();
        action_trace = new action_list_t();
        currentNode = rootNode;
        current_action = NULL;
-       used_thread_id = INITIAL_THREAD_ID;
+       next_thread_id = INITIAL_THREAD_ID;
+       used_sequence_numbers = 0;
        /* scheduler reset ? */
 }
 
-int ModelChecker::get_next_id()
+thread_id_t ModelChecker::get_next_id()
+{
+       return next_thread_id++;
+}
+
+int ModelChecker::get_next_seq_num()
 {
-       return ++used_thread_id;
+       return ++used_sequence_numbers;
 }
 
 Thread * ModelChecker::schedule_next_thread()
@@ -57,9 +99,10 @@ Thread * ModelChecker::schedule_next_thread()
        Thread *t;
        if (nextThread == THREAD_ID_T_NONE)
                return NULL;
-       t = thread_map[nextThread];
-       if (t == NULL)
-               DEBUG("*** error: thread not in thread_map: id = %d\n", nextThread);
+       t = thread_map[id_to_int(nextThread)];
+
+       ASSERT(t != NULL);
+
        return t;
 }
 
@@ -78,7 +121,7 @@ thread_id_t ModelChecker::get_next_replay_thread()
        next = exploring->get_state();
 
        if (next == exploring->get_diverge()) {
-               TreeNode *node = next->get_node();
+               TreeNode *node = next->get_treenode();
 
                /* Reached divergence point; discard our current 'exploring' */
                DEBUG("*** Discard 'Backtrack' object ***\n");
@@ -100,18 +143,27 @@ thread_id_t ModelChecker::advance_backtracking_state()
 
        /* Else, we are trying to replay an execution */
        exploring->advance_state();
-       if (exploring->get_state() == NULL)
-               DEBUG("*** error: reached end of backtrack trace\n");
+
+       ASSERT(exploring->get_state() != NULL);
 
        return get_next_replay_thread();
 }
 
 bool ModelChecker::next_execution()
 {
+       DBG();
+
        num_executions++;
        print_summary();
        if ((exploring = model->get_next_backtrack()) == NULL)
                return false;
+
+       if (DBG_ENABLED()) {
+               printf("Next execution will diverge at:\n");
+               exploring->get_diverge()->print();
+               print_list(exploring->get_trace());
+       }
+
        model->reset_to_initial_state();
        nextThread = get_next_replay_thread();
        return true;
@@ -119,9 +171,7 @@ bool ModelChecker::next_execution()
 
 ModelAction * ModelChecker::get_last_conflict(ModelAction *act)
 {
-       void *loc = act->get_location();
        action_type type = act->get_type();
-       thread_id_t id = act->get_tid();
 
        switch (type) {
                case THREAD_CREATE:
@@ -137,14 +187,8 @@ ModelAction * ModelChecker::get_last_conflict(ModelAction *act)
        action_list_t::reverse_iterator rit;
        for (rit = action_trace->rbegin(); rit != action_trace->rend(); rit++) {
                ModelAction *prev = *rit;
-               if (prev->get_location() != loc)
-                       continue;
-               if (type == ATOMIC_READ && prev->get_type() != ATOMIC_WRITE)
-                       continue;
-               /* Conflict from the same thread is not really a conflict */
-               if (id == prev->get_tid())
-                       continue;
-               return prev;
+               if (act->is_dependent(prev))
+                       return prev;
        }
        return NULL;
 }
@@ -153,22 +197,26 @@ void ModelChecker::set_backtracking(ModelAction *act)
 {
        ModelAction *prev;
        TreeNode *node;
+       Thread *t = get_thread(act->get_tid());
 
        prev = get_last_conflict(act);
        if (prev == NULL)
                return;
 
-       node = prev->get_node();
+       node = prev->get_treenode();
+
+       while (t && !node->is_enabled(t))
+               t = t->get_parent();
 
        /* Check if this has been explored already */
-       if (node->hasBeenExplored(act->get_tid()))
+       if (node->hasBeenExplored(t->get_id()))
                return;
        /* If this is a new backtracking point, mark the tree */
-       if (node->setBacktrack(act->get_tid()) != 0)
+       if (node->setBacktrack(t->get_id()) != 0)
                return;
 
        DEBUG("Setting backtrack: conflict = %d, instead tid = %d\n",
-                       prev->get_tid(), act->get_tid());
+                       prev->get_tid(), t->get_id());
        if (DBG_ENABLED()) {
                prev->print();
                act->print();
@@ -200,25 +248,31 @@ void ModelChecker::check_current_action(void)
        nextThread = advance_backtracking_state();
        next->set_node(currentNode);
        set_backtracking(next);
-       currentNode = currentNode->exploreChild(next->get_tid());
+       currentNode = currentNode->explore_child(next);
        this->action_trace->push_back(next);
 }
 
 void ModelChecker::print_summary(void)
 {
-       action_list_t::iterator it;
-
        printf("\n");
-       printf("---------------------------------------------------------------------\n");
        printf("Number of executions: %d\n", num_executions);
-       printf("Total nodes created: %d\n\n", TreeNode::getTotalNodes());
+       printf("Total nodes created: %d\n", TreeNode::getTotalNodes());
 
        scheduler->print();
 
-       printf("Trace:\n\n");
+       print_list(action_trace);
+       printf("\n");
+
+}
+
+void ModelChecker::print_list(action_list_t *list)
+{
+       action_list_t::iterator it;
+
+       printf("---------------------------------------------------------------------\n");
+       printf("Trace:\n");
 
-       for (it = action_trace->begin(); it != action_trace->end(); it++) {
-               DBG();
+       for (it = list->begin(); it != list->end(); it++) {
                (*it)->print();
        }
        printf("---------------------------------------------------------------------\n");
@@ -226,7 +280,7 @@ void ModelChecker::print_summary(void)
 
 int ModelChecker::add_thread(Thread *t)
 {
-       thread_map[t->get_id()] = t;
+       thread_map[id_to_int(t->get_id())] = t;
        scheduler->add_thread(t);
        return 0;
 }
@@ -246,41 +300,3 @@ int ModelChecker::switch_to_master(ModelAction *act)
        old->set_state(THREAD_READY);
        return Thread::swap(old, get_system_context());
 }
-
-ModelAction::ModelAction(action_type_t type, memory_order order, void *loc, int value)
-{
-       Thread *t = thread_current();
-       ModelAction *act = this;
-
-       act->type = type;
-       act->order = order;
-       act->location = loc;
-       act->tid = t->get_id();
-       act->value = value;
-}
-
-void ModelAction::print(void)
-{
-       const char *type_str;
-       switch (this->type) {
-       case THREAD_CREATE:
-               type_str = "thread create";
-               break;
-       case THREAD_YIELD:
-               type_str = "thread yield";
-               break;
-       case THREAD_JOIN:
-               type_str = "thread join";
-               break;
-       case ATOMIC_READ:
-               type_str = "atomic read";
-               break;
-       case ATOMIC_WRITE:
-               type_str = "atomic write";
-               break;
-       default:
-               type_str = "unknown type";
-       }
-
-       printf("Thread: %d\tAction: %s\tMO: %d\tLoc: %#014zx\tValue: %d\n", tid, type_str, order, (size_t)location, value);
-}