ModelChecker *model;
+/** @brief Constructor */
ModelChecker::ModelChecker()
:
/* Initialize default scheduler */
{
}
+/** @brief Destructor */
ModelChecker::~ModelChecker()
{
std::map<int, class Thread *>::iterator it;
delete scheduler;
}
+/**
+ * Restores user program to initial state and resets all model-checker data
+ * structures.
+ */
void ModelChecker::reset_to_initial_state()
{
DEBUG("+++ Resetting to initial state +++\n");
snapshotObject->backTrackBeforeStep(0);
}
+/** @returns a thread ID for a new Thread */
thread_id_t ModelChecker::get_next_id()
{
return next_thread_id++;
}
+/** @returns the number of user threads created during this execution */
int ModelChecker::get_num_threads()
{
return next_thread_id;
}
+/** @returns a sequence number for a new ModelAction */
int ModelChecker::get_next_seq_num()
{
return ++used_sequence_numbers;
}
+/**
+ * Performs the "scheduling" for the model-checker. That is, it checks if the
+ * model-checker has selected a "next thread to run" and returns it, if
+ * available. This function should be called from the Scheduler routine, where
+ * the Scheduler falls back to a default scheduling routine if needed.
+ *
+ * @return The next thread chosen by the model-checker. If the model-checker
+ * makes no selection, retuns NULL.
+ */
Thread * ModelChecker::schedule_next_thread()
{
Thread *t;
return t;
}
-/*
- * get_next_replay_thread() - Choose the next thread in the replay sequence
+/**
+ * Choose the next thread in the replay sequence.
*
- * If we've reached the 'diverge' point, then we pick a thread from the
- * backtracking set.
- * Otherwise, we simply return the next thread in the sequence.
+ * If the replay sequence has reached the 'diverge' point, returns a thread
+ * from the backtracking set. Otherwise, simply returns the next thread in the
+ * sequence that is being replayed.
*/
thread_id_t ModelChecker::get_next_replay_thread()
{
return tid;
}
+/**
+ * Queries the model-checker for more executions to explore and, if one
+ * exists, resets the model-checker state to execute a new execution.
+ *
+ * @return If there are more executions to explore, return true. Otherwise,
+ * return false.
+ */
bool ModelChecker::next_execution()
{
DBG();
action_list_t::reverse_iterator rit;
for (rit = action_trace->rbegin(); rit != action_trace->rend(); rit++) {
ModelAction *prev = *rit;
- if (act->is_dependent(prev))
+ if (act->is_synchronizing(prev))
return prev;
}
return NULL;
Node *currnode;
ModelAction *curr = this->current_action;
+ ModelAction *tmp;
current_action = NULL;
if (!curr) {
DEBUG("trying to push NULL action...\n");
return;
}
- /* TODO: if get_last_action() is NULL, sync with parent thread */
- curr = node_stack->explore_action(curr, get_last_action(curr->get_tid()));
+ tmp = node_stack->explore_action(curr);
+ if (tmp) {
+ /* Discard duplicate ModelAction */
+ delete curr;
+ curr = tmp;
+ } else {
+ curr->create_cv(get_parent_action(curr->get_tid()));
+ }
+
+ /* Assign 'creation' parent */
+ if (curr->get_type() == THREAD_CREATE) {
+ Thread *th = (Thread *)curr->get_location();
+ th->set_creation(curr);
+ }
+
nextThread = get_next_replay_thread();
currnode = curr->get_node();
next_backtrack = curr;
set_backtracking(curr);
- this->action_trace->push_back(curr);
- std::vector<action_list_t> *vec = &(*obj_thrd_map)[curr->get_location()];
- if (id_to_int(curr->get_tid()) >= (int)vec->size())
+ add_action_to_lists(curr);
+}
+
+
+/**
+ * Adds an action to the per-object, per-thread action vector.
+ * @param act is the ModelAction to add.
+ */
+
+void ModelChecker::add_action_to_lists(ModelAction *act)
+{
+ action_trace->push_back(act);
+
+ std::vector<action_list_t> *vec = &(*obj_thrd_map)[act->get_location()];
+ if (id_to_int(act->get_tid()) >= (int)vec->size())
vec->resize(next_thread_id);
- (*vec)[id_to_int(curr->get_tid())].push_back(curr);
+ (*vec)[id_to_int(act->get_tid())].push_back(act);
- (*thrd_last_action)[id_to_int(curr->get_tid())] = curr;
+ (*thrd_last_action)[id_to_int(act->get_tid())] = act;
}
ModelAction * ModelChecker::get_last_action(thread_id_t tid)
return (*thrd_last_action)[id_to_int(tid)];
}
+ModelAction * ModelChecker::get_parent_action(thread_id_t tid)
+{
+ ModelAction *parent = get_last_action(tid);
+ if (!parent)
+ parent = get_thread(tid)->get_creation();
+ return parent;
+}
+
void ModelChecker::print_summary(void)
{
printf("\n");
printf("Number of executions: %d\n", num_executions);
- printf("Total nodes created: %d\n", Node::get_total_nodes());
+ printf("Total nodes created: %d\n", node_stack->get_total_nodes());
scheduler->print();