model: always re-calculate clock vectors
[c11tester.git] / model.cc
index 2b902ba809106795e77791bde5d500653934ed43..c4bc693ef5560f646684b3a2cb002e685f4be848 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -38,7 +38,8 @@ ModelChecker::ModelChecker(struct model_params params) :
        mo_graph(new CycleGraph()),
        failed_promise(false),
        too_many_reads(false),
-       asserted(false)
+       asserted(false),
+       bad_synchronization(false)
 {
        /* Allocate this "size" on the snapshotting heap */
        priv = (struct model_snapshot_members *)calloc(1, sizeof(*priv));
@@ -80,6 +81,7 @@ void ModelChecker::reset_to_initial_state()
        node_stack->reset_execution();
        failed_promise = false;
        too_many_reads = false;
+       bad_synchronization = false;
        reset_asserted();
        snapshotObject->backTrackBeforeStep(0);
 }
@@ -334,7 +336,7 @@ bool ModelChecker::process_read(ModelAction *curr, bool second_part_of_rmw)
                        bool r_status = false;
 
                        if (!second_part_of_rmw) {
-                               check_recency(curr);
+                               check_recency(curr, reads_from);
                                r_status = r_modification_order(curr, reads_from);
                        }
 
@@ -523,7 +525,9 @@ ModelAction * ModelChecker::initialize_curr_action(ModelAction *curr)
        if (curr->is_rmwc() || curr->is_rmw()) {
                newcurr = process_rmw(curr);
                delete curr;
-               compute_promises(newcurr);
+
+               if (newcurr->is_rmw())
+                       compute_promises(newcurr);
                return newcurr;
        }
 
@@ -539,9 +543,7 @@ ModelAction * ModelChecker::initialize_curr_action(ModelAction *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()));
+               newcurr->create_cv(get_parent_action(newcurr->get_tid()));
        } else {
                newcurr = curr;
                /*
@@ -626,7 +628,8 @@ Thread * ModelChecker::check_current_action(ModelAction *curr)
                        bool update = false; /* update this location's release seq's */
                        bool update_all = false; /* update all release seq's */
 
-                       process_thread_action(curr);
+                       if (process_thread_action(curr))
+                               update_all = true;
 
                        if (act->is_read() && process_read(act, second_part_of_rmw))
                                update = true;
@@ -659,6 +662,7 @@ Thread * ModelChecker::check_current_action(ModelAction *curr)
                                if (w_modification_order(act))
                                        updated = true;
                        }
+                       mo_graph->commitChanges();
 
                        if (updated)
                                work_queue.push_back(CheckRelSeqWorkEntry(act->get_location()));
@@ -722,6 +726,9 @@ bool ModelChecker::isfeasibleprefix() {
 
 /** @return whether the current partial trace is feasible. */
 bool ModelChecker::isfeasible() {
+       if (DBG_ENABLED() && mo_graph->checkForRMWViolation())
+               DEBUG("Infeasible: RMW violation\n");
+
        return !mo_graph->checkForRMWViolation() && isfeasibleotherthanRMW();
 }
 
@@ -735,10 +742,12 @@ bool ModelChecker::isfeasibleotherthanRMW() {
                        DEBUG("Infeasible: failed promise\n");
                if (too_many_reads)
                        DEBUG("Infeasible: too many reads\n");
+               if (bad_synchronization)
+                       DEBUG("Infeasible: bad synchronization ordering\n");
                if (promises_expired())
                        DEBUG("Infeasible: promises expired\n");
        }
-       return !mo_graph->checkForCycles() && !failed_promise && !too_many_reads && !promises_expired();
+       return !mo_graph->checkForCycles() && !failed_promise && !too_many_reads && !bad_synchronization && !promises_expired();
 }
 
 /** Returns whether the current completed trace is feasible. */
@@ -772,23 +781,21 @@ ModelAction * ModelChecker::process_rmw(ModelAction *act) {
  *
  * If so, we decide that the execution is no longer feasible.
  */
-void ModelChecker::check_recency(ModelAction *curr) {
+void ModelChecker::check_recency(ModelAction *curr, const ModelAction *rf) {
        if (params.maxreads != 0) {
+
                if (curr->get_node()->get_read_from_size() <= 1)
                        return;
-
                //Must make sure that execution is currently feasible...  We could
                //accidentally clear by rolling back
                if (!isfeasible())
                        return;
-
                std::vector<action_list_t> *thrd_lists = obj_thrd_map->get_safe_ptr(curr->get_location());
                int tid = id_to_int(curr->get_tid());
 
                /* Skip checks */
                if ((int)thrd_lists->size() <= tid)
                        return;
-
                action_list_t *list = &(*thrd_lists)[tid];
 
                action_list_t::reverse_iterator rit = list->rbegin();
@@ -807,17 +814,18 @@ void ModelChecker::check_recency(ModelAction *curr) {
                        ModelAction *act = *rit;
                        if (!act->is_read())
                                return;
-                       if (act->get_reads_from() != curr->get_reads_from())
+                       
+                       if (act->get_reads_from() != rf)
                                return;
                        if (act->get_node()->get_read_from_size() <= 1)
                                return;
                }
-
                for (int i = 0; i<curr->get_node()->get_read_from_size(); i++) {
                        //Get write
                        const ModelAction * write = curr->get_node()->get_read_from_at(i);
+
                        //Need a different write
-                       if (write==curr->get_reads_from())
+                       if (write==rf)
                                continue;
 
                        /* Test to see whether this is a feasible write to read from*/
@@ -940,10 +948,10 @@ void ModelChecker::post_r_modification_order(ModelAction *curr, const ModelActio
                action_list_t::reverse_iterator rit;
                ModelAction *lastact = NULL;
 
-               /* Find last action that happens after curr */
+               /* Find last action that happens after curr that is either not curr or a rmw */
                for (rit = list->rbegin(); rit != list->rend(); rit++) {
                        ModelAction *act = *rit;
-                       if (curr->happens_before(act)) {
+                       if (curr->happens_before(act) && (curr != act || curr->is_rmw())) {
                                lastact = act;
                        } else
                                break;
@@ -951,12 +959,25 @@ void ModelChecker::post_r_modification_order(ModelAction *curr, const ModelActio
 
                        /* Include at most one act per-thread that "happens before" curr */
                if (lastact != NULL) {
-                       if (lastact->is_read()) {
+                       if (lastact==curr) {
+                               //Case 1: The resolved read is a RMW, and we need to make sure
+                               //that the write portion of the RMW mod order after rf
+
+                               mo_graph->addEdge(rf, lastact);
+                       } else if (lastact->is_read()) {
+                               //Case 2: The resolved read is a normal read and the next
+                               //operation is a read, and we need to make sure the value read
+                               //is mod ordered after rf
+
                                const ModelAction *postreadfrom = lastact->get_reads_from();
                                if (postreadfrom != NULL&&rf != postreadfrom)
                                        mo_graph->addEdge(rf, postreadfrom);
-                       } else if (rf != lastact) {
-                               mo_graph->addEdge(rf, lastact);
+                       } else {
+                               //Case 3: The resolved read is a normal read and the next
+                               //operation is a write, and we need to make sure that the
+                               //write is mod ordered after rf
+                               if (lastact!=rf)
+                                       mo_graph->addEdge(rf, lastact);
                        }
                        break;
                }
@@ -1107,6 +1128,10 @@ bool ModelChecker::thin_air_constraint_may_allow(const ModelAction * writer, con
  */
 bool ModelChecker::release_seq_head(const ModelAction *rf, rel_heads_list_t *release_heads) const
 {
+       /* Only check for release sequences if there are no cycles */
+       if (mo_graph->checkForCycles())
+               return false;
+
        while (rf) {
                ASSERT(rf->is_write());
 
@@ -1268,8 +1293,10 @@ bool ModelChecker::resolve_release_sequences(void *location, work_queue_t *work_
                complete = release_seq_head(rf, &release_heads);
                for (unsigned int i = 0; i < release_heads.size(); i++) {
                        if (!act->has_synchronized_with(release_heads[i])) {
-                               updated = true;
-                               act->synchronize_with(release_heads[i]);
+                               if (act->synchronize_with(release_heads[i]))
+                                       updated = true;
+                               else
+                                       set_bad_synchronization();
                        }
                }
 
@@ -1278,9 +1305,9 @@ bool ModelChecker::resolve_release_sequences(void *location, work_queue_t *work_
                        work_queue->push_back(MOEdgeWorkEntry(act));
 
                        /* propagate synchronization to later actions */
-                       action_list_t::reverse_iterator it = action_trace->rbegin();
-                       for (; (*it) != act; it++) {
-                               ModelAction *propagate = *it;
+                       action_list_t::reverse_iterator rit = action_trace->rbegin();
+                       for (; (*rit) != act; rit++) {
+                               ModelAction *propagate = *rit;
                                if (act->happens_before(propagate)) {
                                        propagate->synchronize_with(act);
                                        /* Re-check 'propagate' for mo_graph edges */
@@ -1412,16 +1439,19 @@ bool ModelChecker::resolve_promises(ModelAction *write)
                Promise *promise = (*promises)[promise_index];
                if (write->get_node()->get_promise(i)) {
                        ModelAction *read = promise->get_action();
-                       read->read_from(write);
                        if (read->is_rmw()) {
                                mo_graph->addRMWEdge(write, read);
                        }
+                       read->read_from(write);
                        //First fix up the modification order for actions that happened
                        //before the read
                        r_modification_order(read, write);
                        //Next fix up the modification order for actions that happened
                        //after the read.
                        post_r_modification_order(read, write);
+                       //Make sure the promise's value matches the write's value
+                       ASSERT(promise->get_value() == write->get_value());
+
                        promises->erase(promises->begin() + promise_index);
                        resolved = true;
                } else
@@ -1627,6 +1657,7 @@ bool ModelChecker::take_step() {
 
                        priv->nextThread = check_current_action(priv->current_action);
                        priv->current_action = NULL;
+
                        if (curr->is_blocked() || curr->is_complete())
                                scheduler->remove_thread(curr);
                } else {