Complete the transfer of deletions of some actions
[c11tester.git] / execution.cc
index f601145a69ad3b96c5d487962089e406f09c07e5..bfb93278cfa7b2deb8b7e5ad1bed6a38ad76a170 100644 (file)
@@ -51,28 +51,36 @@ ModelExecution::ModelExecution(ModelChecker *m, Scheduler *scheduler) :
        model(m),
        params(NULL),
        scheduler(scheduler),
-       action_trace(),
        thread_map(2),  /* We'll always need at least 2 threads */
        pthread_map(0),
        pthread_counter(1),
+       action_trace(),
        obj_map(),
        condvar_waiters_map(),
        obj_thrd_map(),
+       obj_wr_thrd_map(),
+       obj_last_sc_map(),
        mutex_map(),
+       cond_map(),
        thrd_last_action(1),
        thrd_last_fence_release(),
        priv(new struct model_snapshot_members ()),
        mo_graph(new CycleGraph()),
+#ifdef NEWFUZZER
        fuzzer(new NewFuzzer()),
-       thrd_func_list(),
-       thrd_func_act_lists(),
+#else
+       fuzzer(new Fuzzer()),
+#endif
        isfinished(false)
 {
        /* Initialize a model-checker thread, for special ModelActions */
        model_thread = new Thread(get_next_id());
        add_thread(model_thread);
-       fuzzer->register_engine(m->get_history(), this);
+       fuzzer->register_engine(m, this);
        scheduler->register_engine(this);
+#ifdef TLS
+       pthread_key_create(&pthreadkey, tlsdestructor);
+#endif
 }
 
 /** @brief Destructor */
@@ -128,6 +136,12 @@ modelclock_t ModelExecution::get_next_seq_num()
        return ++priv->used_sequence_numbers;
 }
 
+/** @return a sequence number for a new ModelAction */
+modelclock_t ModelExecution::get_curr_seq_num()
+{
+       return priv->used_sequence_numbers;
+}
+
 /** Restore the last used sequence number when actions of a thread are postponed by Fuzzer */
 void ModelExecution::restore_last_seq_num()
 {
@@ -183,11 +197,10 @@ void ModelExecution::wake_up_sleeping_actions(ModelAction *curr)
        }
 }
 
-bool ModelExecution::assert_bug(const char *msg)
+void ModelExecution::assert_bug(const char *msg)
 {
        priv->bugs.push_back(new bug_message(msg));
-
-       return false;
+       set_assert();
 }
 
 /** @return True, if any bugs have been reported for this execution */
@@ -269,7 +282,9 @@ ModelAction * ModelExecution::convertNonAtomicStore(void * location) {
        add_normal_write_to_lists(act);
        add_write_to_lists(act);
        w_modification_order(act);
-//     model->get_history()->process_action(act, act->get_tid());
+#ifdef NEWFUZZER
+       model->get_history()->process_action(act, act->get_tid());
+#endif
        return act;
 }
 
@@ -277,11 +292,11 @@ ModelAction * ModelExecution::convertNonAtomicStore(void * location) {
  * Processes a read model action.
  * @param curr is the read model action to process.
  * @param rf_set is the set of model actions we can possibly read from
- * @return True if processing this read updates the mo_graph.
+ * @return True if the read can be pruned from the thread map list.
  */
 bool ModelExecution::process_read(ModelAction *curr, SnapVector<ModelAction *> * rf_set)
 {
-       SnapVector<const ModelAction *> * priorset = new SnapVector<const ModelAction *>();
+       SnapVector<ModelAction *> * priorset = new SnapVector<ModelAction *>();
        bool hasnonatomicstore = hasNonAtomicStore(curr->get_location());
        if (hasnonatomicstore) {
                ModelAction * nonatomicstore = convertNonAtomicStore(curr->get_location());
@@ -290,18 +305,18 @@ bool ModelExecution::process_read(ModelAction *curr, SnapVector<ModelAction *> *
 
        // Remove writes that violate read modification order
        /*
-          for (uint i = 0; i < rf_set->size(); i++) {
+          uint i = 0;
+          while (i < rf_set->size()) {
                ModelAction * rf = (*rf_set)[i];
                if (!r_modification_order(curr, rf, NULL, NULL, true)) {
                        (*rf_set)[i] = rf_set->back();
                        rf_set->pop_back();
-               }
+               } else
+                       i++;
           }*/
 
        while(true) {
                int index = fuzzer->selectWrite(curr, rf_set);
-               if (index == -1)// no feasible write exists
-                       return false;
 
                ModelAction *rf = (*rf_set)[index];
 
@@ -314,11 +329,7 @@ bool ModelExecution::process_read(ModelAction *curr, SnapVector<ModelAction *> *
                        read_from(curr, rf);
                        get_thread(curr)->set_return_value(curr->get_return_value());
                        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 true;
+                       return canprune && (curr->get_type() == ATOMIC_READ);
                }
                priorset->clear();
                (*rf_set)[index] = rf_set->back();
@@ -375,18 +386,19 @@ bool ModelExecution::process_mutex(ModelAction *curr)
                break;
        }
        case ATOMIC_WAIT: {
-               /* wake up the other threads */
-               for (unsigned int i = 0;i < get_num_threads();i++) {
-                       Thread *t = get_thread(int_to_id(i));
-                       Thread *curr_thrd = get_thread(curr);
-                       if (t->waiting_on() == curr_thrd && t->get_pending()->is_lock())
-                               scheduler->wake(t);
-               }
+               //TODO: DOESN'T REALLY IMPLEMENT SPURIOUS WAKEUPS CORRECTLY
+               if (fuzzer->shouldWait(curr)) {
+                       /* wake up the other threads */
+                       for (unsigned int i = 0;i < get_num_threads();i++) {
+                               Thread *t = get_thread(int_to_id(i));
+                               Thread *curr_thrd = get_thread(curr);
+                               if (t->waiting_on() == curr_thrd && t->get_pending()->is_lock())
+                                       scheduler->wake(t);
+                       }
 
-               /* unlock the lock - after checking who was waiting on it */
-               state->locked = NULL;
+                       /* unlock the lock - after checking who was waiting on it */
+                       state->locked = NULL;
 
-               if (fuzzer->shouldWait(curr)) {
                        /* disable this thread */
                        get_safe_ptr_action(&condvar_waiters_map, curr->get_location())->push_back(curr);
                        scheduler->sleep(get_thread(curr));
@@ -396,7 +408,14 @@ bool ModelExecution::process_mutex(ModelAction *curr)
        }
        case ATOMIC_TIMEDWAIT:
        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...
+               //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++) {
@@ -708,30 +727,22 @@ ModelAction * ModelExecution::check_current_action(ModelAction *curr)
 
        wake_up_sleeping_actions(curr);
 
-       /* Add uninitialized actions to lists */
-       if (!second_part_of_rmw)
-               add_uninit_action_to_lists(curr);
-
        SnapVector<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);
 
+       bool canprune = false;
+
        if (curr->is_read() && !second_part_of_rmw) {
-               process_read(curr, rf_set);
+               canprune = process_read(curr, rf_set);
                delete rf_set;
-
-/*             bool success = process_read(curr, rf_set);
-                delete rf_set;
-                if (!success)
-                        return curr;   // Do not add action to lists
- */
        } else
                ASSERT(rf_set == NULL);
 
        /* Add the action to lists */
        if (!second_part_of_rmw)
-               add_action_to_lists(curr);
+               add_action_to_lists(curr, canprune);
 
        if (curr->is_write())
                add_write_to_lists(curr);
@@ -781,19 +792,27 @@ ModelAction * ModelExecution::process_rmw(ModelAction *act) {
  */
 
 bool ModelExecution::r_modification_order(ModelAction *curr, const ModelAction *rf,
-                                                                                                                                                                       SnapVector<const ModelAction *> * priorset, bool * canprune, bool check_only)
+                                                                                                                                                                       SnapVector<ModelAction *> * priorset, bool * canprune, bool check_only)
 {
        SnapVector<action_list_t> *thrd_lists = obj_thrd_map.get(curr->get_location());
-       unsigned int i;
        ASSERT(curr->is_read());
 
        /* Last SC fence in the current thread */
        ModelAction *last_sc_fence_local = get_last_seq_cst_fence(curr->get_tid(), NULL);
 
        int tid = curr->get_tid();
+
+       /* Need to ensure thrd_lists is big enough because we have not added the curr actions yet.  */
+       if ((int)thrd_lists->size() <= tid) {
+               uint oldsize = thrd_lists->size();
+               thrd_lists->resize(priv->next_thread_id);
+               for(uint i = oldsize;i < priv->next_thread_id;i++)
+                       new (&(*thrd_lists)[i]) action_list_t();
+       }
+
        ModelAction *prev_same_thread = NULL;
        /* Iterate over all threads */
-       for (i = 0;i < thrd_lists->size();i++, tid = (((unsigned int)(tid+1)) == thrd_lists->size()) ? 0 : tid + 1) {
+       for (unsigned int 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 (i != 0)
@@ -875,7 +894,7 @@ bool ModelExecution::r_modification_order(ModelAction *curr, const ModelAction *
                                        if (!check_only)
                                                priorset->push_back(act);
                                } else {
-                                       const ModelAction *prevrf = act->get_reads_from();
+                                       ModelAction *prevrf = act->get_reads_from();
                                        if (!prevrf->equals(rf)) {
                                                if (mo_graph->checkReachable(rf, prevrf))
                                                        return false;
@@ -1098,59 +1117,6 @@ ClockVector * ModelExecution::get_hb_from_write(ModelAction *rf) const {
        return vec;
 }
 
-/**
- * Performs various bookkeeping operations for the current ModelAction when it is
- * the first atomic action occurred at its memory location.
- *
- * For instance, adds uninitialized action to the per-object, per-thread action vector
- * and to the action trace list of all thread actions.
- *
- * @param act is the ModelAction to process.
- */
-void ModelExecution::add_uninit_action_to_lists(ModelAction *act)
-{
-       int tid = id_to_int(act->get_tid());
-       ModelAction *uninit = NULL;
-       int uninit_id = -1;
-       action_list_t *list = get_safe_ptr_action(&obj_map, act->get_location());
-       if (list->empty() && act->is_atomic_var()) {
-               uninit = get_uninitialized_action(act);
-               uninit_id = id_to_int(uninit->get_tid());
-               list->push_front(uninit);
-               SnapVector<action_list_t> *vec = get_safe_ptr_vect_action(&obj_wr_thrd_map, act->get_location());
-               if ((int)vec->size() <= uninit_id) {
-                       int oldsize = (int) vec->size();
-                       vec->resize(uninit_id + 1);
-                       for(int i = oldsize;i < uninit_id + 1;i++) {
-                               new (&(*vec)[i]) action_list_t();
-                       }
-               }
-               (*vec)[uninit_id].push_front(uninit);
-       }
-
-       // Update action trace, a total order of all actions
-       if (uninit)
-               action_trace.push_front(uninit);
-
-       // Update obj_thrd_map, a per location, per thread, order of actions
-       SnapVector<action_list_t> *vec = get_safe_ptr_vect_action(&obj_thrd_map, act->get_location());
-       if ((int)vec->size() <= tid) {
-               uint oldsize = vec->size();
-               vec->resize(priv->next_thread_id);
-               for(uint i = oldsize;i < priv->next_thread_id;i++)
-                       new (&(*vec)[i]) action_list_t();
-       }
-       if (uninit)
-               (*vec)[uninit_id].push_front(uninit);
-
-       // Update thrd_last_action, the last action taken by each thrad
-       if ((int)thrd_last_action.size() <= tid)
-               thrd_last_action.resize(get_num_threads());
-       if (uninit)
-               thrd_last_action[uninit_id] = uninit;
-}
-
-
 /**
  * Performs various bookkeeping operations for the current ModelAction. For
  * instance, adds action to the per-object, per-thread action vector and to the
@@ -1158,14 +1124,17 @@ void ModelExecution::add_uninit_action_to_lists(ModelAction *act)
  *
  * @param act is the ModelAction to add.
  */
-void ModelExecution::add_action_to_lists(ModelAction *act)
+void ModelExecution::add_action_to_lists(ModelAction *act, bool canprune)
 {
        int tid = id_to_int(act->get_tid());
-       action_list_t *list = get_safe_ptr_action(&obj_map, act->get_location());
-       list->push_back(act);
+       if ((act->is_fence() && act->is_seqcst()) || act->is_unlock()) {
+               action_list_t *list = get_safe_ptr_action(&obj_map, act->get_location());
+               act->setActionRef(list->add_back(act));
+       }
 
        // Update action trace, a total order of all actions
-       action_trace.push_back(act);
+       act->setTraceRef(action_trace.add_back(act));
+
 
        // Update obj_thrd_map, a per location, per thread, order of actions
        SnapVector<action_list_t> *vec = get_safe_ptr_vect_action(&obj_thrd_map, act->get_location());
@@ -1175,9 +1144,10 @@ void ModelExecution::add_action_to_lists(ModelAction *act)
                for(uint i = oldsize;i < priv->next_thread_id;i++)
                        new (&(*vec)[i]) action_list_t();
        }
-       (*vec)[tid].push_back(act);
+       if (!canprune && (act->is_read() || act->is_write()))
+               act->setThrdMapRef((*vec)[tid].add_back(act));
 
-       // Update thrd_last_action, the last action taken by each thrad
+       // Update thrd_last_action, the last action taken by each thread
        if ((int)thrd_last_action.size() <= tid)
                thrd_last_action.resize(get_num_threads());
        thrd_last_action[tid] = act;
@@ -1191,50 +1161,42 @@ void ModelExecution::add_action_to_lists(ModelAction *act)
 
        if (act->is_wait()) {
                void *mutex_loc = (void *) act->get_value();
-               get_safe_ptr_action(&obj_map, mutex_loc)->push_back(act);
-
-               SnapVector<action_list_t> *vec = get_safe_ptr_vect_action(&obj_thrd_map, mutex_loc);
-               if ((int)vec->size() <= tid) {
-                       uint oldsize = vec->size();
-                       vec->resize(priv->next_thread_id);
-                       for(uint i = oldsize;i < priv->next_thread_id;i++)
-                               new (&(*vec)[i]) action_list_t();
-               }
-               (*vec)[tid].push_back(act);
+               act->setActionRef(get_safe_ptr_action(&obj_map, mutex_loc)->add_back(act));
        }
 }
 
-void insertIntoActionList(action_list_t *list, ModelAction *act) {
+sllnode<ModelAction *>* insertIntoActionList(action_list_t *list, ModelAction *act) {
        sllnode<ModelAction*> * rit = list->end();
        modelclock_t next_seq = act->get_seq_number();
-       if (rit == NULL || (rit->getVal()->get_seq_number() == next_seq))
-               list->push_back(act);
+       if (rit == NULL || (rit->getVal()->get_seq_number() <= next_seq))
+               return list->add_back(act);
        else {
                for(;rit != NULL;rit=rit->getPrev()) {
-                       if (rit->getVal()->get_seq_number() == next_seq) {
-                               list->insertAfter(rit, act);
-                               break;
+                       if (rit->getVal()->get_seq_number() <= next_seq) {
+                               return list->insertAfter(rit, act);
                        }
                }
+               return list->add_front(act);
        }
 }
 
-void insertIntoActionListAndSetCV(action_list_t *list, ModelAction *act) {
+sllnode<ModelAction *>* insertIntoActionListAndSetCV(action_list_t *list, ModelAction *act) {
        sllnode<ModelAction*> * rit = list->end();
        modelclock_t next_seq = act->get_seq_number();
        if (rit == NULL) {
                act->create_cv(NULL);
-       } else if (rit->getVal()->get_seq_number() == next_seq) {
+               return list->add_back(act);
+       } else if (rit->getVal()->get_seq_number() <= next_seq) {
                act->create_cv(rit->getVal());
-               list->push_back(act);
+               return list->add_back(act);
        } else {
                for(;rit != NULL;rit=rit->getPrev()) {
-                       if (rit->getVal()->get_seq_number() == next_seq) {
+                       if (rit->getVal()->get_seq_number() <= next_seq) {
                                act->create_cv(rit->getVal());
-                               list->insertAfter(rit, act);
-                               break;
+                               return list->insertAfter(rit, act);
                        }
                }
+               return list->add_front(act);
        }
 }
 
@@ -1249,10 +1211,7 @@ void insertIntoActionListAndSetCV(action_list_t *list, ModelAction *act) {
 void ModelExecution::add_normal_write_to_lists(ModelAction *act)
 {
        int tid = id_to_int(act->get_tid());
-       insertIntoActionListAndSetCV(&action_trace, act);
-
-       action_list_t *list = get_safe_ptr_action(&obj_map, act->get_location());
-       insertIntoActionList(list, act);
+       act->setTraceRef(insertIntoActionListAndSetCV(&action_trace, act));
 
        // Update obj_thrd_map, a per location, per thread, order of actions
        SnapVector<action_list_t> *vec = get_safe_ptr_vect_action(&obj_thrd_map, act->get_location());
@@ -1262,10 +1221,11 @@ void ModelExecution::add_normal_write_to_lists(ModelAction *act)
                for(uint i=oldsize;i<priv->next_thread_id;i++)
                        new (&(*vec)[i]) action_list_t();
        }
-       insertIntoActionList(&(*vec)[tid],act);
+       act->setThrdMapRef(insertIntoActionList(&(*vec)[tid],act));
 
+       ModelAction * lastact = thrd_last_action[tid];
        // Update thrd_last_action, the last action taken by each thrad
-       if (thrd_last_action[tid]->get_seq_number() == act->get_seq_number())
+       if (lastact == NULL || lastact->get_seq_number() == act->get_seq_number())
                thrd_last_action[tid] = act;
 }
 
@@ -1279,7 +1239,7 @@ void ModelExecution::add_write_to_lists(ModelAction *write) {
                for(uint i=oldsize;i<priv->next_thread_id;i++)
                        new (&(*vec)[i]) action_list_t();
        }
-       (*vec)[tid].push_back(write);
+       write->setActionRef((*vec)[tid].add_back(write));
 }
 
 /**
@@ -1372,6 +1332,9 @@ ModelAction * ModelExecution::get_last_unlock(ModelAction *curr) const
        void *location = curr->get_location();
 
        action_list_t *list = obj_map.get(location);
+       if (list == NULL)
+               return NULL;
+
        /* Find: max({i in dom(S) | isUnlock(t_i) && samevar(t_i, t)}) */
        sllnode<ModelAction*>* rit;
        for (rit = list->end();rit != NULL;rit=rit->getPrev())
@@ -1436,46 +1399,47 @@ SnapVector<ModelAction *> *  ModelExecution::build_may_read_from(ModelAction *cu
        SnapVector<ModelAction *> * rf_set = new SnapVector<ModelAction *>();
 
        /* Iterate over all threads */
-       for (i = 0;i < thrd_lists->size();i++) {
-               /* Iterate over actions in thread, starting from most recent */
-               action_list_t *list = &(*thrd_lists)[i];
-               sllnode<ModelAction *> * rit;
-               for (rit = list->end();rit != NULL;rit=rit->getPrev()) {
-                       ModelAction *act = rit->getVal();
-
-                       if (act == curr)
-                               continue;
+       if (thrd_lists != NULL)
+               for (i = 0;i < thrd_lists->size();i++) {
+                       /* Iterate over actions in thread, starting from most recent */
+                       action_list_t *list = &(*thrd_lists)[i];
+                       sllnode<ModelAction *> * rit;
+                       for (rit = list->end();rit != NULL;rit=rit->getPrev()) {
+                               ModelAction *act = rit->getVal();
+
+                               if (act == curr)
+                                       continue;
 
-                       /* Don't consider more than one seq_cst write if we are a seq_cst read. */
-                       bool allow_read = true;
-
-                       if (curr->is_seqcst() && (act->is_seqcst() || (last_sc_write != NULL && act->happens_before(last_sc_write))) && act != last_sc_write)
-                               allow_read = false;
-
-                       /* Need to check whether we will have two RMW reading from the same value */
-                       if (curr->is_rmwr()) {
-                               /* It is okay if we have a failing CAS */
-                               if (!curr->is_rmwrcas() ||
-                                               valequals(curr->get_value(), act->get_value(), curr->getSize())) {
-                                       //Need to make sure we aren't the second RMW
-                                       CycleNode * node = mo_graph->getNode_noCreate(act);
-                                       if (node != NULL && node->getRMW() != NULL) {
-                                               //we are the second RMW
-                                               allow_read = false;
+                               /* Don't consider more than one seq_cst write if we are a seq_cst read. */
+                               bool allow_read = true;
+
+                               if (curr->is_seqcst() && (act->is_seqcst() || (last_sc_write != NULL && act->happens_before(last_sc_write))) && act != last_sc_write)
+                                       allow_read = false;
+
+                               /* Need to check whether we will have two RMW reading from the same value */
+                               if (curr->is_rmwr()) {
+                                       /* It is okay if we have a failing CAS */
+                                       if (!curr->is_rmwrcas() ||
+                                                       valequals(curr->get_value(), act->get_value(), curr->getSize())) {
+                                               //Need to make sure we aren't the second RMW
+                                               CycleNode * node = mo_graph->getNode_noCreate(act);
+                                               if (node != NULL && node->getRMW() != NULL) {
+                                                       //we are the second RMW
+                                                       allow_read = false;
+                                               }
                                        }
                                }
-                       }
 
-                       if (allow_read) {
-                               /* Only add feasible reads */
-                               rf_set->push_back(act);
-                       }
+                               if (allow_read) {
+                                       /* Only add feasible reads */
+                                       rf_set->push_back(act);
+                               }
 
-                       /* Include at most one act per-thread that "happens before" curr */
-                       if (act->happens_before(curr))
-                               break;
+                               /* Include at most one act per-thread that "happens before" curr */
+                               if (act->happens_before(curr))
+                                       break;
+                       }
                }
-       }
 
        if (DBG_ENABLED()) {
                model_print("Reached read action:\n");
@@ -1485,25 +1449,6 @@ SnapVector<ModelAction *> *  ModelExecution::build_may_read_from(ModelAction *cu
        return rf_set;
 }
 
-/**
- * @brief Get an action representing an uninitialized atomic
- *
- * This function may create a new one.
- *
- * @param curr The current action, which prompts the creation of an UNINIT action
- * @return A pointer to the UNINIT ModelAction
- */
-ModelAction * ModelExecution::get_uninitialized_action(ModelAction *curr) const
-{
-       ModelAction *act = curr->get_uninit_action();
-       if (!act) {
-               act = new ModelAction(ATOMIC_UNINIT, std::memory_order_relaxed, curr->get_location(), params->uninitvalue, model_thread);
-               curr->set_uninit_action(act);
-       }
-       act->create_cv(NULL);
-       return act;
-}
-
 static void print_list(action_list_t *list)
 {
        sllnode<ModelAction*> *it;
@@ -1670,7 +1615,7 @@ bool ModelExecution::is_enabled(thread_id_t tid) const
 Thread * ModelExecution::action_select_next_thread(const ModelAction *curr) const
 {
        /* Do not split atomic RMW */
-       if (curr->is_rmwr() && !paused_by_fuzzer(curr))
+       if (curr->is_rmwr())
                return get_thread(curr);
        /* Follow CREATE with the created thread */
        /* which is not needed, because model.cc takes care of this */
@@ -1682,15 +1627,6 @@ Thread * ModelExecution::action_select_next_thread(const ModelAction *curr) cons
        return NULL;
 }
 
-/** @param act A read atomic action */
-bool ModelExecution::paused_by_fuzzer(const ModelAction * act) const
-{
-       ASSERT(act->is_read());
-
-       // Actions paused by fuzzer have their sequence number reset to 0
-       return act->get_seq_number() == 0;
-}
-
 /**
  * Takes the next step in the execution, if possible.
  * @param curr The current step to take
@@ -1707,14 +1643,303 @@ Thread * ModelExecution::take_step(ModelAction *curr)
        ASSERT(curr);
 
        /* Process this action in ModelHistory for records */
-//     model->get_history()->process_action( curr, curr->get_tid() );
-
+#ifdef NEWFUZZER
+       model->get_history()->process_action( curr, curr->get_tid() );
+#endif
        if (curr_thrd->is_blocked() || curr_thrd->is_complete())
                scheduler->remove_thread(curr_thrd);
 
        return action_select_next_thread(curr);
 }
 
+/** This method removes references to an Action before we delete it. */
+
+void ModelExecution::removeAction(ModelAction *act) {
+       {
+               sllnode<ModelAction *> * listref = act->getTraceRef();
+               if (listref != NULL) {
+                       action_trace.erase(listref);
+               }
+       }
+       {
+               sllnode<ModelAction *> * listref = act->getThrdMapRef();
+               if (listref != NULL) {
+                       SnapVector<action_list_t> *vec = get_safe_ptr_vect_action(&obj_thrd_map, act->get_location());
+                       (*vec)[act->get_tid()].erase(listref);
+               }
+       }
+       if ((act->is_fence() && act->is_seqcst()) || act->is_unlock()) {
+               sllnode<ModelAction *> * listref = act->getActionRef();
+               if (listref != NULL) {
+                       action_list_t *list = get_safe_ptr_action(&obj_map, act->get_location());
+                       list->erase(listref);
+               }
+       } else if (act->is_wait()) {
+               sllnode<ModelAction *> * listref = act->getActionRef();
+               if (listref != NULL) {
+                       void *mutex_loc = (void *) act->get_value();
+                       get_safe_ptr_action(&obj_map, mutex_loc)->erase(listref);
+               }
+       } else if (act->is_free()) {
+               sllnode<ModelAction *> * listref = act->getActionRef();
+               if (listref != NULL) {
+                       SnapVector<action_list_t> *vec = get_safe_ptr_vect_action(&obj_wr_thrd_map, act->get_location());
+                       (*vec)[act->get_tid()].erase(listref);
+               }
+               //Clear it from last_sc_map
+               if (obj_last_sc_map.get(act->get_location()) == act) {
+                       obj_last_sc_map.remove(act->get_location());
+               }
+
+               //Remove from Cyclegraph
+               mo_graph->freeAction(act);
+       }
+}
+
+/** Computes clock vector that all running threads have already synchronized to.  */
+
+ClockVector * ModelExecution::computeMinimalCV() {
+       ClockVector *cvmin = NULL;
+       //Thread 0 isn't a real thread, so skip it..
+       for(unsigned int i = 1;i < thread_map.size();i++) {
+               Thread * t = thread_map[i];
+               if (t->get_state() == THREAD_COMPLETED)
+                       continue;
+               thread_id_t tid = int_to_id(i);
+               ClockVector * cv = get_cv(tid);
+               if (cvmin == NULL)
+                       cvmin = new ClockVector(cv, NULL);
+               else
+                       cvmin->minmerge(cv);
+       }
+       return cvmin;
+}
+
+
+/** Sometimes we need to remove an action that is the most recent in the thread.  This happens if it is mo before action in other threads.  In that case we need to create a replacement latest ModelAction */
+
+void ModelExecution::fixupLastAct(ModelAction *act) {
+       ModelAction *newact = new ModelAction(ATOMIC_NOP, std::memory_order_seq_cst, NULL, VALUE_NONE, get_thread(act->get_tid()));
+       newact->set_seq_number(get_next_seq_num());
+       newact->create_cv(act);
+       newact->set_last_fence_release(act->get_last_fence_release());
+       add_action_to_lists(newact, false);
+}
+
+/** Compute which actions to free.  */
+
+void ModelExecution::collectActions() {
+       if (priv->used_sequence_numbers < params->traceminsize)
+               return;
+
+       //Compute minimal clock vector for all live threads
+       ClockVector *cvmin = computeMinimalCV();
+       SnapVector<CycleNode *> * queue = new SnapVector<CycleNode *>();
+       modelclock_t maxtofree = priv->used_sequence_numbers - params->traceminsize;
+
+       //Next walk action trace...  When we hit an action, see if it is
+       //invisible (e.g., earlier than the first before the minimum
+       //clock for the thread...  if so erase it and all previous
+       //actions in cyclegraph
+       sllnode<ModelAction*> * it;
+       for (it = action_trace.begin();it != NULL;it=it->getNext()) {
+               ModelAction *act = it->getVal();
+               modelclock_t actseq = act->get_seq_number();
+
+               //See if we are done
+               if (actseq > maxtofree)
+                       break;
+
+               thread_id_t act_tid = act->get_tid();
+               modelclock_t tid_clock = cvmin->getClock(act_tid);
+
+               //Free if it is invisible or we have set a flag to remove visible actions.
+               if (actseq <= tid_clock || params->removevisible) {
+                       ModelAction * write;
+                       if (act->is_write()) {
+                               write = act;
+                       } else if (act->is_read()) {
+                               write = act->get_reads_from();
+                       } else
+                               continue;
+
+                       //Mark everything earlier in MO graph to be freed
+                       CycleNode * cn = mo_graph->getNode_noCreate(write);
+                       if (cn != NULL) {
+                               queue->push_back(cn);
+                               while(!queue->empty()) {
+                                       CycleNode * node = queue->back();
+                                       queue->pop_back();
+                                       for(unsigned int i=0;i<node->getNumInEdges();i++) {
+                                               CycleNode * prevnode = node->getInEdge(i);
+                                               ModelAction * prevact = prevnode->getAction();
+                                               if (prevact->get_type() != READY_FREE) {
+                                                       // Save the original action type
+                                                       prevact->set_original_type(prevact->get_type());
+                                                       prevact->set_free();
+                                                       queue->push_back(prevnode);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       //We may need to remove read actions in the window we don't delete to preserve correctness.
+
+       for (sllnode<ModelAction*> * it2 = action_trace.end();it2 != it;) {
+               ModelAction *act = it2->getVal();
+               //Do iteration early in case we delete the act
+               it2=it2->getPrev();
+               bool islastact = false;
+               ModelAction *lastact = get_last_action(act->get_tid());
+               if (act == lastact) {
+                       Thread * th = get_thread(act);
+                       islastact = !th->is_complete();
+               }
+
+               if (act->is_read()) {
+                       if (act->get_reads_from()->is_free()) {
+                               if (act->is_rmw()) {
+                                       // Save the original action type
+                                       act->set_original_type(act->get_type());
+                                       //Weaken a RMW from a freed store to a write
+                                       act->set_type(ATOMIC_WRITE);
+                               } else {
+                                       removeAction(act);
+                                       if (islastact) {
+                                               fixupLastAct(act);
+                                       }
+
+                                       // Only delete this action if not being using by ModelHistory.
+                                       // Otherwise, the deletion of action is deferred.
+                                       if (act->get_func_ref_count() == 0) {
+                                               delete act;
+                                               continue;
+                                       }
+                               }
+                       }
+               }
+               //If we don't delete the action, we should remove references to release fences
+
+               const ModelAction *rel_fence =act->get_last_fence_release();
+               if (rel_fence != NULL) {
+                       modelclock_t relfenceseq = rel_fence->get_seq_number();
+                       thread_id_t relfence_tid = rel_fence->get_tid();
+                       modelclock_t tid_clock = cvmin->getClock(relfence_tid);
+                       //Remove references to irrelevant release fences
+                       if (relfenceseq <= tid_clock)
+                               act->set_last_fence_release(NULL);
+               }
+       }
+       //Now we are in the window of old actions that we remove if possible
+       for (;it != NULL;) {
+               ModelAction *act = it->getVal();
+               //Do iteration early since we may delete node...
+               it=it->getPrev();
+               bool islastact = false;
+               ModelAction *lastact = get_last_action(act->get_tid());
+               if (act == lastact) {
+                       Thread * th = get_thread(act);
+                       islastact = !th->is_complete();
+               }
+
+               if (act->is_read()) {
+                       if (act->get_reads_from()->is_free()) {
+                               if (act->is_rmw()) {
+                                       // Save the original action type
+                                       act->set_original_type(act->get_type());
+                                       act->set_type(ATOMIC_WRITE);
+                               } else {
+                                       removeAction(act);
+                                       if (islastact) {
+                                               fixupLastAct(act);
+                                       }
+                                       if (act->get_func_ref_count() == 0) {
+                                               delete act;
+                                               continue;
+                                       }
+                               }
+                       }
+               } else if (act->is_free()) {
+                       removeAction(act);
+                       if (islastact) {
+                               fixupLastAct(act);
+                       }
+                       if (act->get_func_ref_count() == 0) {
+                               delete act;
+                               continue;
+                       }
+               } else if (act->is_write()) {
+                       //Do nothing with write that hasn't been marked to be freed
+               } else if (islastact) {
+                       //Keep the last action for non-read/write actions
+               } else if (act->is_fence()) {
+                       //Note that acquire fences can always be safely
+                       //removed, but could incur extra overheads in
+                       //traversals.  Removing them before the cvmin seems
+                       //like a good compromise.
+
+                       //Release fences before the cvmin don't do anything
+                       //because everyone has already synchronized.
+
+                       //Sequentially fences before cvmin are redundant
+                       //because happens-before will enforce same
+                       //orderings.
+
+                       modelclock_t actseq = act->get_seq_number();
+                       thread_id_t act_tid = act->get_tid();
+                       modelclock_t tid_clock = cvmin->getClock(act_tid);
+                       if (actseq <= tid_clock) {
+                               removeAction(act);
+                               // Remove reference to act from thrd_last_fence_release
+                               int thread_id = id_to_int( act->get_tid() );
+                               if (thrd_last_fence_release[thread_id] == act) {
+                                       thrd_last_fence_release[thread_id] = NULL;
+                               }
+                               delete act;
+                               continue;
+                       }
+               } else {
+                       //need to deal with lock, annotation, wait, notify, thread create, start, join, yield, finish, nops
+                       //lock, notify thread create, thread finish, yield, finish are dead as soon as they are in the trace
+                       //need to keep most recent unlock/wait for each lock
+                       if(act->is_unlock() || act->is_wait()) {
+                               ModelAction * lastlock = get_last_unlock(act);
+                               if (lastlock != act) {
+                                       removeAction(act);
+                                       delete act;
+                                       continue;
+                               }
+                       } else if (act->is_create()) {
+                               if (act->get_thread_operand()->is_complete()) {
+                                       removeAction(act);
+                                       delete act;
+                                       continue;
+                               }
+                       } else {
+                               removeAction(act);
+                               delete act;
+                               continue;
+                       }
+               }
+
+               //If we don't delete the action, we should remove references to release fences
+               const ModelAction *rel_fence =act->get_last_fence_release();
+               if (rel_fence != NULL) {
+                       modelclock_t relfenceseq = rel_fence->get_seq_number();
+                       thread_id_t relfence_tid = rel_fence->get_tid();
+                       modelclock_t tid_clock = cvmin->getClock(relfence_tid);
+                       //Remove references to irrelevant release fences
+                       if (relfenceseq <= tid_clock)
+                               act->set_last_fence_release(NULL);
+               }
+       }
+
+       delete cvmin;
+       delete queue;
+}
+
 Fuzzer * ModelExecution::getFuzzer() {
        return fuzzer;
 }