return updated_mod_order || updated_promises;
}
+ModelAction * ModelChecker::initialize_curr_action(ModelAction *curr)
+{
+ ModelAction *newcurr;
+
+ if (curr->is_rmwc() || curr->is_rmw()) {
+ newcurr = process_rmw(curr);
+ delete curr;
+ compute_promises(newcurr);
+ return newcurr;
+ }
+
+ newcurr = node_stack->explore_action(curr);
+ if (newcurr) {
+ /* First restore type and order in case of RMW operation */
+ if (curr->is_rmwr())
+ newcurr->copy_typeandorder(curr);
+
+ /* Discard duplicate ModelAction; use action from NodeStack */
+ delete curr;
+
+ /* If we have diverged, we need to reset the clock vector. */
+ if (diverge == NULL)
+ newcurr->create_cv(get_parent_action(newcurr->get_tid()));
+ } else {
+ newcurr = curr;
+ /*
+ * Perform one-time actions when pushing new ModelAction onto
+ * NodeStack
+ */
+ curr->create_cv(get_parent_action(curr->get_tid()));
+ if (curr->is_write())
+ compute_promises(curr);
+ }
+ return newcurr;
+}
+
/**
* This is the heart of the model checker routine. It performs model-checking
* actions corresponding to a given "current action." Among other processes, it
*/
Thread * ModelChecker::check_current_action(ModelAction *curr)
{
- bool second_part_of_rmw = false;
-
ASSERT(curr);
- if (curr->is_rmwc() || curr->is_rmw()) {
- ModelAction *tmp = process_rmw(curr);
- second_part_of_rmw = true;
- delete curr;
- curr = tmp;
- compute_promises(curr);
- } else {
- ModelAction *tmp = node_stack->explore_action(curr);
- if (tmp) {
- /* Discard duplicate ModelAction; use action from NodeStack */
- /* First restore type and order in case of RMW operation */
- if (curr->is_rmwr())
- tmp->copy_typeandorder(curr);
-
- /* If we have diverged, we need to reset the clock vector. */
- if (diverge == NULL)
- tmp->create_cv(get_parent_action(tmp->get_tid()));
-
- delete curr;
- curr = tmp;
- } else {
- /*
- * Perform one-time actions when pushing new ModelAction onto
- * NodeStack
- */
- curr->create_cv(get_parent_action(curr->get_tid()));
- /* Build may_read_from set */
- if (curr->is_read())
- build_reads_from_past(curr);
- if (curr->is_write())
- compute_promises(curr);
- }
- }
+ bool second_part_of_rmw = curr->is_rmwc() || curr->is_rmw();
+
+ ModelAction *newcurr = initialize_curr_action(curr);
+
+ /* Build may_read_from set for newly-created actions */
+ if (curr == newcurr && curr->is_read())
+ build_reads_from_past(curr);
+ curr = newcurr;
/* Thread specific actions */
switch (curr->get_type()) {
case WORK_CHECK_RELEASE_SEQ:
resolve_release_sequences(work.location, &work_queue);
break;
- case WORK_CHECK_MO_EDGES:
- /** @todo Perform follow-up mo_graph checks */
+ case WORK_CHECK_MO_EDGES: {
+ /** @todo Complete verification of work_queue */
+ ModelAction *act = work.action;
+ bool updated = false;
+
+ if (act->is_read()) {
+ if (r_modification_order(act, act->get_reads_from()))
+ updated = true;
+ }
+ if (act->is_write()) {
+ if (w_modification_order(act))
+ updated = true;
+ }
+
+ if (updated)
+ work_queue.push_back(CheckRelSeqWorkEntry(act->get_location()));
+ break;
+ }
default:
ASSERT(false);
break;
/** @returns whether the current partial trace is feasible other than
* multiple RMW reading from the same store. */
bool ModelChecker::isfeasibleotherthanRMW() {
+ if (DBG_ENABLED()) {
+ if (mo_graph->checkForCycles())
+ DEBUG("Infeasible: modification order cycles\n");
+ if (failed_promise)
+ DEBUG("Infeasible: failed promise\n");
+ if (too_many_reads)
+ DEBUG("Infeasible: too many reads\n");
+ if (promises_expired())
+ DEBUG("Infeasible: promises expired\n");
+ }
return !mo_graph->checkForCycles() && !failed_promise && !too_many_reads && !promises_expired();
}
/** Returns whether the current completed trace is feasible. */
bool ModelChecker::isfinalfeasible() {
+ if (DBG_ENABLED() && promises->size() != 0)
+ DEBUG("Infeasible: unrevolved promises\n");
+
return isfeasible() && promises->size() == 0;
}
*/
if (act->happens_before(curr) && act != curr) {
if (act->is_write()) {
- if (rf != act && act != curr) {
+ if (rf != act) {
mo_graph->addEdge(act, rf);
added = true;
}
added = true;
}
}
-
break;
}
}
action_list_t::reverse_iterator rit;
for (rit = list->rbegin(); rit != list->rend(); rit++) {
ModelAction *act = *rit;
+ if (act == curr) {
+ /*
+ * If RMW, we already have all relevant edges,
+ * so just skip to next thread.
+ * If normal write, we need to look at earlier
+ * actions, so continue processing list.
+ */
+ if (curr->is_rmw())
+ break;
+ else
+ continue;
+ }
/*
* Include at most one act per-thread that "happens
- * before" curr. Only consider reflexively if curr is
- * RMW.
+ * before" curr
*/
- if (act->happens_before(curr) && (act != curr || curr->is_rmw())) {
+ if (act->happens_before(curr)) {
/*
* Note: if act is RMW, just add edge:
* act --mo--> curr
* The following edge should be handled elsewhere:
* readfrom(act) --mo--> act
*/
- if (act->is_write()) {
- //RMW shouldn't have an edge to themselves
- if (act!=curr)
- mo_graph->addEdge(act, curr);
- } else if (act->is_read() && act->get_reads_from() != NULL)
+ if (act->is_write())
+ mo_graph->addEdge(act, curr);
+ else if (act->is_read() && act->get_reads_from() != NULL)
mo_graph->addEdge(act->get_reads_from(), curr);
added = true;
break;
ModelAction *act = *rit;
/* Only consider 'write' actions */
- if (!act->is_write())
+ if (!act->is_write() || act == curr)
continue;
/* Don't consider more than one seq_cst write if we are a seq_cst read. */