Modified the implementation of usleep and make ModelExecution process "THREAD SLEEP...
[c11tester.git] / execution.cc
index cfb0b0bc781be4e334f3549e0dae6ba91173f330..870dcb1a9d06bd25614e4d872f6e6c9ae80045a4 100644 (file)
@@ -15,6 +15,7 @@
 #include "bugmessage.h"
 #include "history.h"
 #include "fuzzer.h"
+#include "newfuzzer.h"
 
 #define INITIAL_THREAD_ID       0
 
@@ -64,15 +65,16 @@ ModelExecution::ModelExecution(ModelChecker *m, Scheduler *scheduler) :
        thrd_last_fence_release(),
        priv(new struct model_snapshot_members ()),
        mo_graph(new CycleGraph()),
-       fuzzer(new Fuzzer()),
+       fuzzer(new NewFuzzer()),
        thrd_func_list(),
-       thrd_func_inst_lists(),
+       thrd_func_act_lists(),
        isfinished(false)
 {
        /* Initialize a model-checker thread, for special ModelActions */
        model_thread = new Thread(get_next_id());
        add_thread(model_thread);
        scheduler->register_engine(this);
+       fuzzer->register_engine(m->get_history(), this);
 }
 
 /** @brief Destructor */
@@ -90,7 +92,7 @@ int ModelExecution::get_execution_number() const
        return model->get_execution_number();
 }
 
-static action_list_t * get_safe_ptr_action(HashTable<const void *, action_list_t *, uintptr_t, 4> * hash, void * ptr)
+static action_list_t * get_safe_ptr_action(HashTable<const void *, action_list_t *, uintptr_t, 2> * hash, void * ptr)
 {
        action_list_t *tmp = hash->get(ptr);
        if (tmp == NULL) {
@@ -100,7 +102,7 @@ static action_list_t * get_safe_ptr_action(HashTable<const void *, action_list_t
        return tmp;
 }
 
-static SnapVector<action_list_t> * get_safe_ptr_vect_action(HashTable<const void *, SnapVector<action_list_t> *, uintptr_t, 4> * hash, void * ptr)
+static SnapVector<action_list_t> * get_safe_ptr_vect_action(HashTable<const void *, SnapVector<action_list_t> *, uintptr_t, 2> * hash, void * ptr)
 {
        SnapVector<action_list_t> *tmp = hash->get(ptr);
        if (tmp == NULL) {
@@ -128,6 +130,12 @@ modelclock_t ModelExecution::get_next_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()
+{
+       priv->used_sequence_numbers--;
+}
+
 /**
  * @brief Should the current action wake up a given thread?
  *
@@ -153,6 +161,11 @@ bool ModelExecution::should_wake_up(const ModelAction *curr, const Thread *threa
                if (fence_release && *(get_last_action(thread->get_id())) < *fence_release)
                        return true;
        }
+       if (asleep->is_sleep()) {
+               if (fuzzer->shouldWake(asleep))
+                       return true;
+       }
+
        return false;
 }
 
@@ -161,9 +174,12 @@ void ModelExecution::wake_up_sleeping_actions(ModelAction *curr)
        for (unsigned int i = 0;i < get_num_threads();i++) {
                Thread *thr = get_thread(int_to_id(i));
                if (scheduler->is_sleep_set(thr)) {
-                       if (should_wake_up(curr, thr))
+                       if (should_wake_up(curr, thr)) {
                                /* Remove this thread from sleep set */
                                scheduler->remove_sleep(thr);
+                               if (thr->get_pending()->is_sleep())
+                                       thr->set_pending(NULL);
+                       }
                }
        }
 }
@@ -192,16 +208,6 @@ bool ModelExecution::have_bug_reports() const
        return priv->bugs.size() != 0;
 }
 
-/** @return True, if any fatal bugs have been reported for this execution.
- *  Any bug other than a data race is considered a fatal bug. Data races
- *  are not considered fatal unless the number of races is exceeds
- *  a threshold (temporarily set as 15).
- */
-bool ModelExecution::have_fatal_bug_reports() const
-{
-       return priv->bugs.size() != 0;
-}
-
 SnapVector<bug_message *> * ModelExecution::get_bugs() const
 {
        return &priv->bugs;
@@ -275,6 +281,7 @@ 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());
        return act;
 }
 
@@ -284,7 +291,7 @@ ModelAction * ModelExecution::convertNonAtomicStore(void * location) {
  * @param rf_set is the set of model actions we can possibly read from
  * @return True if processing this read updates the mo_graph.
  */
-void ModelExecution::process_read(ModelAction *curr, SnapVector<ModelAction *> * rf_set)
+bool ModelExecution::process_read(ModelAction *curr, SnapVector<ModelAction *> * rf_set)
 {
        SnapVector<const ModelAction *> * priorset = new SnapVector<const ModelAction *>();
        bool hasnonatomicstore = hasNonAtomicStore(curr->get_location());
@@ -295,8 +302,10 @@ void ModelExecution::process_read(ModelAction *curr, SnapVector<ModelAction *> *
 
        while(true) {
                int index = fuzzer->selectWrite(curr, rf_set);
-               ModelAction *rf = (*rf_set)[index];
+               if (index == -1)        // no feasible write exists
+                       return false;
 
+               ModelAction *rf = (*rf_set)[index];
 
                ASSERT(rf);
                bool canprune = false;
@@ -311,7 +320,7 @@ void ModelExecution::process_read(ModelAction *curr, SnapVector<ModelAction *> *
                                int tid = id_to_int(curr->get_tid());
                                (*obj_thrd_map.get(curr->get_location()))[tid].pop_back();
                        }
-                       return;
+                       return true;
                }
                priorset->clear();
                (*rf_set)[index] = rf_set->back();
@@ -367,7 +376,27 @@ bool ModelExecution::process_mutex(ModelAction *curr)
                }
                break;
        }
-       case ATOMIC_WAIT:
+       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);
+               }
+
+               /* 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));
+               }
+
+               break;
+       }
+       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...
 
@@ -381,10 +410,6 @@ bool ModelExecution::process_mutex(ModelAction *curr)
 
                /* unlock the lock - after checking who was waiting on it */
                state->locked = NULL;
-
-               if (!curr->is_wait())
-                       break;/* The rest is only for ATOMIC_WAIT */
-
                break;
        }
        case ATOMIC_NOTIFY_ALL: {
@@ -543,6 +568,12 @@ void ModelExecution::process_thread_action(ModelAction *curr)
        case THREAD_START: {
                break;
        }
+       case THREAD_SLEEP: {
+               Thread *th = get_thread(curr);
+               th->set_pending(curr);
+               scheduler->add_sleep(th);
+               break;
+       }
        default:
                break;
        }
@@ -650,6 +681,9 @@ bool ModelExecution::check_action_enabled(ModelAction *curr) {
                if (!blocking->is_complete()) {
                        return false;
                }
+       } else if (curr->is_sleep()) {
+               if (!fuzzer->shouldSleep(curr))
+                       return false;
        }
 
        return true;
@@ -676,26 +710,35 @@ 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 && curr->get_type() != NOOP)
-               add_action_to_lists(curr);
-
-       if (curr->is_write())
-               add_write_to_lists(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);
 
-       process_thread_action(curr);
-
        if (curr->is_read() && !second_part_of_rmw) {
                process_read(curr, rf_set);
                delete rf_set;
-       } else {
+
+/*             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);
+
+       if (curr->is_write())
+               add_write_to_lists(curr);
+
+       process_thread_action(curr);
 
        if (curr->is_write())
                process_write(curr);
@@ -1084,13 +1127,15 @@ ClockVector * ModelExecution::get_hb_from_write(ModelAction *rf) const {
 }
 
 /**
- * Performs various bookkeeping operations for the current ModelAction. For
- * instance, adds action to the per-object, per-thread action vector and to the
- * action trace list of all thread actions.
+ * Performs various bookkeeping operations for the current ModelAction when it is
+ * the first atomic action occurred at its memory location.
  *
- * @param act is the ModelAction to add.
+ * 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_action_to_lists(ModelAction *act)
+void ModelExecution::add_uninit_action_to_lists(ModelAction *act)
 {
        int tid = id_to_int(act->get_tid());
        ModelAction *uninit = NULL;
@@ -1101,39 +1146,69 @@ void ModelExecution::add_action_to_lists(ModelAction *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 (uninit_id >= (int)vec->size()) {
+               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();
+                       for(int i = oldsize; i < uninit_id + 1; i++) {
+                               new (&(*vec)[i]) action_list_t();
+                       }
                }
                (*vec)[uninit_id].push_front(uninit);
        }
-       list->push_back(act);
 
        // Update action trace, a total order of all actions
-       action_trace.push_back(act);
        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 (tid >= (int)vec->size()) {
-               uint oldsize =vec->size();
+       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();
+               for(uint i = oldsize; i < priv->next_thread_id; i++)
+                       new (&(*vec)[i]) action_list_t();
        }
-       (*vec)[tid].push_back(act);
        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());
-       thrd_last_action[tid] = act;
        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
+ * action trace list of all thread actions.
+ *
+ * @param act is the ModelAction to add.
+ */
+void ModelExecution::add_action_to_lists(ModelAction *act)
+{
+       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);
+
+       // Update action trace, a total order of all actions
+       action_trace.push_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());
+       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);
+
+       // 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());
+       thrd_last_action[tid] = act;
 
        // Update thrd_last_fence_release, the last release fence taken by each thread
        if (act->is_fence() && act->is_release()) {
@@ -1147,11 +1222,11 @@ void ModelExecution::add_action_to_lists(ModelAction *act)
                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 (tid >= (int)vec->size()) {
+               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();
+                       for(uint i = oldsize; i < priv->next_thread_id; i++)
+                               new (&(*vec)[i]) action_list_t();
                }
                (*vec)[tid].push_back(act);
        }
@@ -1160,11 +1235,11 @@ void ModelExecution::add_action_to_lists(ModelAction *act)
 void 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)
+       if (rit == NULL || (rit->getVal()->get_seq_number() == next_seq))
                list->push_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) {
                                list->insertAfter(rit, act);
                                break;
                        }
@@ -1213,7 +1288,7 @@ void ModelExecution::add_normal_write_to_lists(ModelAction *act)
                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();
+                       new (&(*vec)[i]) action_list_t();
        }
        insertIntoActionList(&(*vec)[tid],act);
 
@@ -1230,7 +1305,7 @@ void ModelExecution::add_write_to_lists(ModelAction *write) {
                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();
+                       new (&(*vec)[i]) action_list_t();
        }
        (*vec)[tid].push_back(write);
 }
@@ -1625,7 +1700,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())
+       if (curr->is_rmwr() && !paused_by_fuzzer(curr))
                return get_thread(curr);
        /* Follow CREATE with the created thread */
        /* which is not needed, because model.cc takes care of this */
@@ -1637,6 +1712,15 @@ 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
@@ -1652,7 +1736,7 @@ Thread * ModelExecution::take_step(ModelAction *curr)
        curr = check_current_action(curr);
        ASSERT(curr);
 
-       /* Process this action in ModelHistory for records*/
+       /* Process this action in ModelHistory for records */
        model->get_history()->process_action( curr, curr->get_tid() );
 
        if (curr_thrd->is_blocked() || curr_thrd->is_complete())