add a separate rule for futex.o
[c11tester.git] / execution.cc
index f498efbb8d5250df4d07304802516ea8e7f1573f..d75499f1349a4e24c69a1c01c90aa8bb599240d5 100644 (file)
@@ -28,7 +28,6 @@ struct model_snapshot_members {
                used_sequence_numbers(0),
                bugs(),
                bad_synchronization(false),
-               bad_sc_read(false),
                asserted(false)
        { }
 
@@ -43,21 +42,18 @@ struct model_snapshot_members {
        SnapVector<bug_message *> bugs;
        /** @brief Incorrectly-ordered synchronization was made */
        bool bad_synchronization;
-       bool bad_sc_read;
        bool asserted;
 
        SNAPSHOTALLOC
 };
 
 /** @brief Constructor */
-ModelExecution::ModelExecution(ModelChecker *m,
-                                                                                                                        Scheduler *scheduler,
-                                                                                                                        NodeStack *node_stack) :
+ModelExecution::ModelExecution(ModelChecker *m, Scheduler *scheduler, NodeStack *node_stack) :
        model(m),
        params(NULL),
        scheduler(scheduler),
        action_trace(),
-       thread_map(2),                  /* We'll always need at least 2 threads */
+       thread_map(2),  /* We'll always need at least 2 threads */
        pthread_map(0),
        pthread_counter(0),
        obj_map(),
@@ -113,18 +109,6 @@ static SnapVector<action_list_t> * get_safe_ptr_vect_action(HashTable<void *, Sn
        return tmp;
 }
 
-action_list_t * ModelExecution::get_actions_on_obj(void * obj, thread_id_t tid) const
-{
-       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;
-}
-
 /** @return a thread ID for a new Thread */
 thread_id_t ModelExecution::get_next_id()
 {
@@ -190,13 +174,6 @@ void ModelExecution::set_bad_synchronization()
        priv->bad_synchronization = true;
 }
 
-/** @brief Alert the model-checker that an incorrectly-ordered
- * synchronization was made */
-void ModelExecution::set_bad_sc_read()
-{
-       priv->bad_sc_read = true;
-}
-
 bool ModelExecution::assert_bug(const char *msg)
 {
        priv->bugs.push_back(new bug_message(msg));
@@ -283,8 +260,9 @@ bool ModelExecution::is_complete_execution() const
  * @param rf_set is the set of model actions we can possibly read from
  * @return True if processing this read updates the mo_graph.
  */
-bool ModelExecution::process_read(ModelAction *curr, ModelVector<ModelAction *> * rf_set)
+void ModelExecution::process_read(ModelAction *curr, SnapVector<const ModelAction *> * rf_set)
 {
+       SnapVector<const ModelAction *> * priorset = new SnapVector<const ModelAction *>();
        while(true) {
 
                int index = fuzzer->selectWrite(curr, rf_set);
@@ -292,16 +270,21 @@ bool ModelExecution::process_read(ModelAction *curr, ModelVector<ModelAction *>
 
 
                ASSERT(rf);
-
-               mo_graph->startChanges();
-               bool updated = r_modification_order(curr, rf);
-               if (!is_infeasible()) {
+               bool canprune = false;
+               if (r_modification_order(curr, rf, priorset, &canprune)) {
+                       for(unsigned int i=0;i<priorset->size();i++) {
+                               mo_graph->addEdge((*priorset)[i], rf);
+                       }
                        read_from(curr, rf);
-                       mo_graph->commitChanges();
                        get_thread(curr)->set_return_value(curr->get_return_value());
-                       return updated;
+                       delete priorset;
+                       if (canprune && curr->get_type() == ATOMIC_READ) {
+                               int tid = id_to_int(curr->get_tid());
+                               (*obj_thrd_map.get(curr->get_location()))[tid].pop_back();
+                       }
+                       return;
                }
-               mo_graph->rollbackChanges();
+               priorset->clear();
                (*rf_set)[index] = rf_set->back();
                rf_set->pop_back();
        }
@@ -356,6 +339,8 @@ bool ModelExecution::process_mutex(ModelAction *curr)
        }
        case ATOMIC_WAIT:
        case ATOMIC_UNLOCK: {
+               //TODO: FIX WAIT SITUATION...WAITS CAN SPURIOUSLY FAIL...TIMED WAITS SHOULD PROBABLY JUST BE THE SAME AS NORMAL WAITS...THINK ABOUT PROBABILITIES THOUGH....AS IN TIMED WAIT MUST FAIL TO GUARANTEE PROGRESS...NORMAL WAIT MAY FAIL...SO NEED NORMAL WAIT TO WORK CORRECTLY IN THE CASE IT SPURIOUSLY FAILS AND IN THE CASE IT DOESN'T...  TIMED WAITS MUST EVENMTUALLY RELEASE...
+
                /* wake up the other threads */
                for (unsigned int i = 0;i < get_num_threads();i++) {
                        Thread *t = get_thread(int_to_id(i));
@@ -368,7 +353,7 @@ bool ModelExecution::process_mutex(ModelAction *curr)
                state->locked = NULL;
 
                if (!curr->is_wait())
-                       break;                                                                  /* The rest is only for ATOMIC_WAIT */
+                       break;/* The rest is only for ATOMIC_WAIT */
 
                break;
        }
@@ -383,8 +368,10 @@ bool ModelExecution::process_mutex(ModelAction *curr)
        }
        case ATOMIC_NOTIFY_ONE: {
                action_list_t *waiters = get_safe_ptr_action(&condvar_waiters_map, curr->get_location());
-               Thread * thread = fuzzer->selectNotify(waiters);
-               scheduler->wake(thread);
+               if (waiters->size() != 0) {
+                       Thread * thread = fuzzer->selectNotify(waiters);
+                       scheduler->wake(thread);
+               }
                break;
        }
 
@@ -399,15 +386,13 @@ bool ModelExecution::process_mutex(ModelAction *curr)
  * @param curr The ModelAction to process
  * @return True if the mo_graph was updated or promises were resolved
  */
-bool ModelExecution::process_write(ModelAction *curr)
+void ModelExecution::process_write(ModelAction *curr)
 {
 
-       bool updated_mod_order = w_modification_order(curr);
+       w_modification_order(curr);
 
-       mo_graph->commitChanges();
 
        get_thread(curr)->set_return_value(VALUE_NONE);
-       return updated_mod_order;
 }
 
 /**
@@ -504,15 +489,15 @@ bool ModelExecution::process_thread_action(ModelAction *curr)
                Thread *blocking = curr->get_thread_operand();
                ModelAction *act = get_last_action(blocking->get_id());
                synchronize(act, curr);
-               updated = true;                                                 /* trigger rel-seq checks */
+               updated = true; /* trigger rel-seq checks */
                break;
        }
        case PTHREAD_JOIN: {
                Thread *blocking = curr->get_thread_operand();
                ModelAction *act = get_last_action(blocking->get_id());
                synchronize(act, curr);
-               updated = true;                                                 /* trigger rel-seq checks */
-               break;                                          // WL: to be add (modified)
+               updated = true; /* trigger rel-seq checks */
+               break;  // WL: to be add (modified)
        }
 
        case THREAD_FINISH: {
@@ -525,7 +510,7 @@ bool ModelExecution::process_thread_action(ModelAction *curr)
                                scheduler->wake(waiting);
                }
                th->complete();
-               updated = true;                                                 /* trigger rel-seq checks */
+               updated = true; /* trigger rel-seq checks */
                break;
        }
        case THREAD_START: {
@@ -579,7 +564,7 @@ bool ModelExecution::initialize_curr_action(ModelAction **curr)
                newcurr->create_cv(get_parent_action(newcurr->get_tid()));
 
                *curr = newcurr;
-               return false;                                                   /* Action was explored previously */
+               return false;   /* Action was explored previously */
        } else {
                newcurr = *curr;
 
@@ -589,7 +574,7 @@ bool ModelExecution::initialize_curr_action(ModelAction **curr)
                /* Assign most recent release fence */
                newcurr->set_last_fence_release(get_last_fence_release(newcurr->get_tid()));
 
-               return true;                                            /* This was a new ModelAction */
+               return true;    /* This was a new ModelAction */
        }
 }
 
@@ -693,10 +678,10 @@ ModelAction * ModelExecution::check_current_action(ModelAction *curr)
        wake_up_sleeping_actions(curr);
 
        /* Add the action to lists before any other model-checking tasks */
-       if (!second_part_of_rmw)
+       if (!second_part_of_rmw && curr->get_type() != NOOP)
                add_action_to_lists(curr);
 
-       ModelVector<ModelAction *> * rf_set = NULL;
+       SnapVector<const ModelAction *> * rf_set = NULL;
        /* Build may_read_from set for newly-created actions */
        if (newly_explored && curr->is_read())
                rf_set = build_may_read_from(curr);
@@ -741,12 +726,8 @@ void ModelExecution::print_infeasibility(const char *prefix) const
 {
        char buf[100];
        char *ptr = buf;
-       if (mo_graph->checkForCycles())
-               ptr += sprintf(ptr, "[mo cycle]");
        if (priv->bad_synchronization)
                ptr += sprintf(ptr, "[bad sw ordering]");
-       if (priv->bad_sc_read)
-               ptr += sprintf(ptr, "[bad sc read]");
        if (ptr != buf)
                model_print("%s: %s", prefix ? prefix : "Infeasible", buf);
 }
@@ -759,9 +740,7 @@ void ModelExecution::print_infeasibility(const char *prefix) const
  */
 bool ModelExecution::is_infeasible() const
 {
-       return mo_graph->checkForCycles() ||
-                                priv->bad_synchronization ||
-                                priv->bad_sc_read;
+       return priv->bad_synchronization;
 }
 
 /** Close out a RMWR by converting previous RMWR into a RMW or READ. */
@@ -770,7 +749,6 @@ ModelAction * ModelExecution::process_rmw(ModelAction *act) {
        lastread->process_rmw(act);
        if (act->is_rmw()) {
                mo_graph->addRMWEdge(lastread->get_reads_from(), lastread);
-               mo_graph->commitChanges();
        }
        return lastread;
 }
@@ -791,12 +769,11 @@ ModelAction * ModelExecution::process_rmw(ModelAction *act) {
  * @param rf The ModelAction or Promise that curr reads from. Must be a write.
  * @return True if modification order edges were added; false otherwise
  */
-template <typename rf_type>
-bool ModelExecution::r_modification_order(ModelAction *curr, const rf_type *rf)
+
+bool ModelExecution::r_modification_order(ModelAction *curr, const ModelAction *rf, SnapVector<const ModelAction *> * priorset, bool * canprune)
 {
        SnapVector<action_list_t> *thrd_lists = obj_thrd_map.get(curr->get_location());
        unsigned int i;
-       bool added = false;
        ASSERT(curr->is_read());
 
        /* Last SC fence in the current thread */
@@ -805,20 +782,29 @@ bool ModelExecution::r_modification_order(ModelAction *curr, const rf_type *rf)
        if (curr->is_seqcst())
                last_sc_write = get_last_seq_cst_write(curr);
 
+       int tid = curr->get_tid();
+       ModelAction *prev_same_thread = NULL;
        /* Iterate over all threads */
-       for (i = 0;i < thrd_lists->size();i++) {
-               /* Last SC fence in thread i */
+       for (i = 0;i < thrd_lists->size();i++, tid = (((unsigned int)(tid+1)) == thrd_lists->size()) ? 0 : tid + 1) {
+               /* Last SC fence in thread tid */
                ModelAction *last_sc_fence_thread_local = NULL;
-               if (int_to_id((int)i) != curr->get_tid())
-                       last_sc_fence_thread_local = get_last_seq_cst_fence(int_to_id(i), NULL);
+               if (i != 0)
+                       last_sc_fence_thread_local = get_last_seq_cst_fence(int_to_id(tid), NULL);
 
-               /* Last SC fence in thread i, before last SC fence in current thread */
+               /* Last SC fence in thread tid, before last SC fence in current thread */
                ModelAction *last_sc_fence_thread_before = NULL;
                if (last_sc_fence_local)
-                       last_sc_fence_thread_before = get_last_seq_cst_fence(int_to_id(i), last_sc_fence_local);
+                       last_sc_fence_thread_before = get_last_seq_cst_fence(int_to_id(tid), last_sc_fence_local);
+
+               //Only need to iterate if either hb has changed for thread in question or SC fence after last operation...
+               if (prev_same_thread != NULL &&
+                               (prev_same_thread->get_cv()->getClock(tid) == curr->get_cv()->getClock(tid)) &&
+                               (last_sc_fence_thread_local == NULL || *last_sc_fence_thread_local < *prev_same_thread)) {
+                       continue;
+               }
 
                /* Iterate over actions in thread, starting from most recent */
-               action_list_t *list = &(*thrd_lists)[i];
+               action_list_t *list = &(*thrd_lists)[tid];
                action_list_t::reverse_iterator rit;
                for (rit = list->rbegin();rit != list->rend();rit++) {
                        ModelAction *act = *rit;
@@ -838,19 +824,25 @@ bool ModelExecution::r_modification_order(ModelAction *curr, const rf_type *rf)
                                /* C++, Section 29.3 statement 5 */
                                if (curr->is_seqcst() && last_sc_fence_thread_local &&
                                                *act < *last_sc_fence_thread_local) {
-                                       added = mo_graph->addEdge(act, rf) || added;
+                                       if (mo_graph->checkReachable(rf, act))
+                                               return false;
+                                       priorset->push_back(act);
                                        break;
                                }
                                /* C++, Section 29.3 statement 4 */
                                else if (act->is_seqcst() && last_sc_fence_local &&
                                                                 *act < *last_sc_fence_local) {
-                                       added = mo_graph->addEdge(act, rf) || added;
+                                       if (mo_graph->checkReachable(rf, act))
+                                               return false;
+                                       priorset->push_back(act);
                                        break;
                                }
                                /* C++, Section 29.3 statement 6 */
                                else if (last_sc_fence_thread_before &&
                                                                 *act < *last_sc_fence_thread_before) {
-                                       added = mo_graph->addEdge(act, rf) || added;
+                                       if (mo_graph->checkReachable(rf, act))
+                                               return false;
+                                       priorset->push_back(act);
                                        break;
                                }
                        }
@@ -860,19 +852,34 @@ bool ModelExecution::r_modification_order(ModelAction *curr, const rf_type *rf)
                         * before" curr
                         */
                        if (act->happens_before(curr)) {
+                               if (i==0) {
+                                       if (last_sc_fence_local == NULL ||
+                                                       (*last_sc_fence_local < *prev_same_thread)) {
+                                               prev_same_thread = act;
+                                       }
+                               }
                                if (act->is_write()) {
-                                       added = mo_graph->addEdge(act, rf) || added;
+                                       if (mo_graph->checkReachable(rf, act))
+                                               return false;
+                                       priorset->push_back(act);
                                } else {
                                        const ModelAction *prevrf = act->get_reads_from();
-                                       if (!prevrf->equals(rf))
-                                               added = mo_graph->addEdge(prevrf, rf) || added;
+                                       if (!prevrf->equals(rf)) {
+                                               if (mo_graph->checkReachable(rf, prevrf))
+                                                       return false;
+                                               priorset->push_back(prevrf);
+                                       } else {
+                                               if (act->get_tid() == curr->get_tid()) {
+                                                       //Can prune curr from obj list
+                                                       *canprune = true;
+                                               }
+                                       }
                                }
                                break;
                        }
                }
        }
-
-       return added;
+       return true;
 }
 
 /**
@@ -899,11 +906,10 @@ bool ModelExecution::r_modification_order(ModelAction *curr, const rf_type *rf)
  * value. If NULL, then don't record any future values.
  * @return True if modification order edges were added; false otherwise
  */
-bool ModelExecution::w_modification_order(ModelAction *curr)
+void ModelExecution::w_modification_order(ModelAction *curr)
 {
        SnapVector<action_list_t> *thrd_lists = obj_thrd_map.get(curr->get_location());
        unsigned int i;
-       bool added = false;
        ASSERT(curr->is_write());
 
        if (curr->is_seqcst()) {
@@ -911,7 +917,7 @@ bool ModelExecution::w_modification_order(ModelAction *curr)
                         so we are initialized. */
                ModelAction *last_seq_cst = get_last_seq_cst_write(curr);
                if (last_seq_cst != NULL) {
-                       added = mo_graph->addEdge(last_seq_cst, curr) || added;
+                       mo_graph->addEdge(last_seq_cst, curr);
                }
        }
 
@@ -928,6 +934,7 @@ bool ModelExecution::w_modification_order(ModelAction *curr)
                /* Iterate over actions in thread, starting from most recent */
                action_list_t *list = &(*thrd_lists)[i];
                action_list_t::reverse_iterator rit;
+               bool force_edge = false;
                for (rit = list->rbegin();rit != list->rend();rit++) {
                        ModelAction *act = *rit;
                        if (act == curr) {
@@ -942,6 +949,7 @@ bool ModelExecution::w_modification_order(ModelAction *curr)
                                 * 3) If normal write, we need to look at earlier actions, so
                                 * continue processing list.
                                 */
+                               force_edge = true;
                                if (curr->is_rmw()) {
                                        if (curr->get_reads_from() != NULL)
                                                break;
@@ -954,7 +962,7 @@ bool ModelExecution::w_modification_order(ModelAction *curr)
                        /* C++, Section 29.3 statement 7 */
                        if (last_sc_fence_thread_before && act->is_write() &&
                                        *act < *last_sc_fence_thread_before) {
-                               added = mo_graph->addEdge(act, curr) || added;
+                               mo_graph->addEdge(act, curr, force_edge);
                                break;
                        }
 
@@ -970,10 +978,10 @@ bool ModelExecution::w_modification_order(ModelAction *curr)
                                 *   readfrom(act) --mo--> act
                                 */
                                if (act->is_write())
-                                       added = mo_graph->addEdge(act, curr) || added;
+                                       mo_graph->addEdge(act, curr, force_edge);
                                else if (act->is_read()) {
                                        //if previous read accessed a null, just keep going
-                                       added = mo_graph->addEdge(act->get_reads_from(), curr) || added;
+                                       mo_graph->addEdge(act->get_reads_from(), curr, force_edge);
                                }
                                break;
                        } else if (act->is_read() && !act->could_synchronize_with(curr) &&
@@ -994,8 +1002,6 @@ bool ModelExecution::w_modification_order(ModelAction *curr)
                        }
                }
        }
-
-       return added;
 }
 
 /**
@@ -1055,12 +1061,8 @@ bool ModelExecution::mo_may_allow(const ModelAction *writer, const ModelAction *
  * @return true, if the ModelExecution is certain that release_heads is complete;
  * false otherwise
  */
-bool ModelExecution::release_seq_heads(const ModelAction *rf,
-                                                                                                                                                        rel_heads_list_t *release_heads) const
+bool ModelExecution::release_seq_heads(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;
 
        for ( ;rf != NULL;rf = rf->get_reads_from()) {
                ASSERT(rf->is_write());
@@ -1070,7 +1072,7 @@ bool ModelExecution::release_seq_heads(const ModelAction *rf,
                else if (rf->get_last_fence_release())
                        release_heads->push_back(rf->get_last_fence_release());
                if (!rf->is_rmw())
-                       break;                                                                  /* End of RMW chain */
+                       break;/* End of RMW chain */
 
                /** @todo Need to be smarter here...  In the linux lock
                 * example, this will run to the beginning of the program for
@@ -1081,12 +1083,12 @@ bool ModelExecution::release_seq_heads(const ModelAction *rf,
 
                /* acq_rel RMW is a sufficient stopping condition */
                if (rf->is_acquire() && rf->is_release())
-                       return true;                                                                    /* complete */
+                       return true;/* complete */
        };
-       ASSERT(rf);                             // Needs to be real write
+       ASSERT(rf);     // Needs to be real write
 
        if (rf->is_release())
-               return true;                                            /* complete */
+               return true;/* complete */
 
        /* else relaxed write
         * - check for fence-release in the same thread (29.8, stmt. 3)
@@ -1099,7 +1101,7 @@ bool ModelExecution::release_seq_heads(const ModelAction *rf,
        if (fence_release)
                release_heads->push_back(fence_release);
 
-       return true;                    /* complete */
+       return true;    /* complete */
 }
 
 /**
@@ -1225,7 +1227,7 @@ ModelAction * ModelExecution::get_last_seq_cst_write(ModelAction *curr) const
        action_list_t::reverse_iterator rit;
        for (rit = list->rbegin();(*rit) != curr;rit++)
                ;
-       rit++;                  /* Skip past curr */
+       rit++;  /* Skip past curr */
        for ( ;rit != list->rend();rit++)
                if ((*rit)->is_write() && (*rit)->is_seqcst())
                        return *rit;
@@ -1327,7 +1329,7 @@ bool valequals(uint64_t val1, uint64_t val2, int size) {
  * @param curr is the current ModelAction that we are exploring; it must be a
  * 'read' operation.
  */
-ModelVector<ModelAction *> *  ModelExecution::build_may_read_from(ModelAction *curr)
+SnapVector<const ModelAction *> *  ModelExecution::build_may_read_from(ModelAction *curr)
 {
        SnapVector<action_list_t> *thrd_lists = obj_thrd_map.get(curr->get_location());
        unsigned int i;
@@ -1338,7 +1340,7 @@ ModelVector<ModelAction *> *  ModelExecution::build_may_read_from(ModelAction *c
        if (curr->is_seqcst())
                last_sc_write = get_last_seq_cst_write(curr);
 
-       ModelVector<ModelAction *> * rf_set = new ModelVector<ModelAction *>();
+       SnapVector<const ModelAction *> * rf_set = new SnapVector<const ModelAction *>();
 
        /* Iterate over all threads */
        for (i = 0;i < thrd_lists->size();i++) {
@@ -1346,10 +1348,21 @@ ModelVector<ModelAction *> *  ModelExecution::build_may_read_from(ModelAction *c
                action_list_t *list = &(*thrd_lists)[i];
                action_list_t::reverse_iterator rit;
                for (rit = list->rbegin();rit != list->rend();rit++) {
-                       ModelAction *act = *rit;
+                       const ModelAction *act = *rit;
 
                        /* Only consider 'write' actions */
-                       if (!act->is_write() || act == curr)
+                       if (!act->is_write()) {
+                               if (act != curr && act->is_read() && act->happens_before(curr)) {
+                                       const ModelAction *tmp = act->get_reads_from();
+                                       if (((unsigned int) id_to_int(tmp->get_tid()))==i)
+                                               act = tmp;
+                                       else
+                                               break;
+                               } else
+                                       continue;
+                       }
+
+                       if (act == curr)
                                continue;
 
                        /* Don't consider more than one seq_cst write if we are a seq_cst read. */
@@ -1374,11 +1387,7 @@ ModelVector<ModelAction *> *  ModelExecution::build_may_read_from(ModelAction *c
 
                        if (allow_read) {
                                /* Only add feasible reads */
-                               mo_graph->startChanges();
-                               r_modification_order(curr, act);
-                               if (!is_infeasible())
-                                       rf_set->push_back(act);
-                               mo_graph->rollbackChanges();
+                               rf_set->push_back(act);
                        }
 
                        /* Include at most one act per-thread that "happens before" curr */
@@ -1618,7 +1627,7 @@ Thread * ModelExecution::take_step(ModelAction *curr)
        Thread *curr_thrd = get_thread(curr);
        ASSERT(curr_thrd->get_state() == THREAD_READY);
 
-       ASSERT(check_action_enabled(curr));                             /* May have side effects? */
+       ASSERT(check_action_enabled(curr));     /* May have side effects? */
        curr = check_current_action(curr);
        ASSERT(curr);