Move data structures from execution.h to history.h
[c11tester.git] / execution.cc
index fe27e2ff70ee41c0aa193179ae007cab673d90fc..7b8461226a8860d60a0311c2fa2538607c9b1363 100644 (file)
@@ -28,7 +28,6 @@ struct model_snapshot_members {
                next_thread_id(INITIAL_THREAD_ID),
                used_sequence_numbers(0),
                bugs(),
-               bad_synchronization(false),
                asserted(false)
        { }
 
@@ -42,7 +41,6 @@ struct model_snapshot_members {
        modelclock_t used_sequence_numbers;
        SnapVector<bug_message *> bugs;
        /** @brief Incorrectly-ordered synchronization was made */
-       bool bad_synchronization;
        bool asserted;
 
        SNAPSHOTALLOC
@@ -66,15 +64,16 @@ ModelExecution::ModelExecution(ModelChecker *m, Scheduler *scheduler) :
        priv(new struct model_snapshot_members ()),
        mo_graph(new CycleGraph()),
        fuzzer(new NewFuzzer()),
-       thrd_func_list(),
-       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);
+       scheduler->register_engine(this);
+#ifdef TLS
+       pthread_key_create(&pthreadkey, tlsdestructor);
+#endif
 }
 
 /** @brief Destructor */
@@ -92,7 +91,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) {
@@ -102,7 +101,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) {
@@ -161,6 +160,7 @@ bool ModelExecution::should_wake_up(const ModelAction *curr, const Thread *threa
                if (fence_release && *(get_last_action(thread->get_id())) < *fence_release)
                        return true;
        }
+       /* The sleep is literally sleeping */
        if (asleep->is_sleep()) {
                if (fuzzer->shouldWake(asleep))
                        return true;
@@ -174,29 +174,20 @@ 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_wakeup_state(true);
+                       }
                }
        }
 }
 
-/** @brief Alert the model-checker that an incorrectly-ordered
- * synchronization was made */
-void ModelExecution::set_bad_synchronization()
-{
-       priv->bad_synchronization = true;
-}
-
-bool ModelExecution::assert_bug(const char *msg)
+void ModelExecution::assert_bug(const char *msg)
 {
        priv->bugs.push_back(new bug_message(msg));
-
-       if (isfeasibleprefix()) {
-               set_assert();
-               return true;
-       }
-       return false;
+       set_assert();
 }
 
 /** @return True, if any bugs have been reported for this execution */
@@ -297,10 +288,19 @@ bool ModelExecution::process_read(ModelAction *curr, SnapVector<ModelAction *> *
                rf_set->push_back(nonatomicstore);
        }
 
+       // Remove writes that violate read modification order
+       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];
 
@@ -319,6 +319,9 @@ bool ModelExecution::process_read(ModelAction *curr, SnapVector<ModelAction *> *
                        }
                        return true;
                }
+
+               ASSERT(false);
+               /* TODO: Following code not needed anymore */
                priorset->clear();
                (*rf_set)[index] = rf_set->back();
                rf_set->pop_back();
@@ -373,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...
 
@@ -387,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: {
@@ -549,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;
        }
@@ -628,7 +653,7 @@ void ModelExecution::read_from(ModelAction *act, ModelAction *rf)
 bool ModelExecution::synchronize(const ModelAction *first, ModelAction *second)
 {
        if (*second < *first) {
-               set_bad_synchronization();
+               ASSERT(0);      //This should not happend
                return false;
        }
        return second->synchronize_with(first);
@@ -686,7 +711,7 @@ ModelAction * ModelExecution::check_current_action(ModelAction *curr)
        wake_up_sleeping_actions(curr);
 
        /* Add uninitialized actions to lists */
-       if (!second_part_of_rmw && curr->get_type() != NOOP)
+       if (!second_part_of_rmw)
                add_uninit_action_to_lists(curr);
 
        SnapVector<ModelAction *> * rf_set = NULL;
@@ -695,15 +720,13 @@ ModelAction * ModelExecution::check_current_action(ModelAction *curr)
                rf_set = build_may_read_from(curr);
 
        if (curr->is_read() && !second_part_of_rmw) {
-               bool success = process_read(curr, rf_set);
+               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 && curr->get_type() != NOOP)
+       if (!second_part_of_rmw)
                add_action_to_lists(curr);
 
        if (curr->is_write())
@@ -723,42 +746,6 @@ ModelAction * ModelExecution::check_current_action(ModelAction *curr)
        return curr;
 }
 
-/**
- * This is the strongest feasibility check available.
- * @return whether the current trace (partial or complete) must be a prefix of
- * a feasible trace.
- */
-bool ModelExecution::isfeasibleprefix() const
-{
-       return !is_infeasible();
-}
-
-/**
- * Print disagnostic information about an infeasible execution
- * @param prefix A string to prefix the output with; if NULL, then a default
- * message prefix will be provided
- */
-void ModelExecution::print_infeasibility(const char *prefix) const
-{
-       char buf[100];
-       char *ptr = buf;
-       if (priv->bad_synchronization)
-               ptr += sprintf(ptr, "[bad sw ordering]");
-       if (ptr != buf)
-               model_print("%s: %s", prefix ? prefix : "Infeasible", buf);
-}
-
-/**
- * Check if the current partial trace is infeasible. Does not check any
- * end-of-execution flags, which might rule out the execution. Thus, this is
- * useful only for ruling an execution as infeasible.
- * @return whether the current partial trace is infeasible.
- */
-bool ModelExecution::is_infeasible() const
-{
-       return priv->bad_synchronization;
-}
-
 /** Close out a RMWR by converting previous RMWR into a RMW or READ. */
 ModelAction * ModelExecution::process_rmw(ModelAction *act) {
        ModelAction *lastread = get_last_action(act->get_tid());
@@ -783,10 +770,14 @@ ModelAction * ModelExecution::process_rmw(ModelAction *act) {
  *
  * @param curr The current action. Must be a read.
  * @param rf The ModelAction or Promise that curr reads from. Must be a write.
+ * @param check_only If true, then only check whether the current action satisfies
+ *        read modification order or not, without modifiying priorset and canprune.
+ *        False by default.
  * @return True if modification order edges were added; false otherwise
  */
 
-bool ModelExecution::r_modification_order(ModelAction *curr, const ModelAction *rf, SnapVector<const ModelAction *> * priorset, bool * canprune)
+bool ModelExecution::r_modification_order(ModelAction *curr, const ModelAction *rf,
+                                                                                                                                                                       SnapVector<const ModelAction *> * priorset, bool * canprune, bool check_only)
 {
        SnapVector<action_list_t> *thrd_lists = obj_thrd_map.get(curr->get_location());
        unsigned int i;
@@ -839,7 +830,8 @@ bool ModelExecution::r_modification_order(ModelAction *curr, const ModelAction *
                                                *act < *last_sc_fence_thread_local) {
                                        if (mo_graph->checkReachable(rf, act))
                                                return false;
-                                       priorset->push_back(act);
+                                       if (!check_only)
+                                               priorset->push_back(act);
                                        break;
                                }
                                /* C++, Section 29.3 statement 4 */
@@ -847,7 +839,8 @@ bool ModelExecution::r_modification_order(ModelAction *curr, const ModelAction *
                                                                 *act < *last_sc_fence_local) {
                                        if (mo_graph->checkReachable(rf, act))
                                                return false;
-                                       priorset->push_back(act);
+                                       if (!check_only)
+                                               priorset->push_back(act);
                                        break;
                                }
                                /* C++, Section 29.3 statement 6 */
@@ -855,7 +848,8 @@ bool ModelExecution::r_modification_order(ModelAction *curr, const ModelAction *
                                                                 *act < *last_sc_fence_thread_before) {
                                        if (mo_graph->checkReachable(rf, act))
                                                return false;
-                                       priorset->push_back(act);
+                                       if (!check_only)
+                                               priorset->push_back(act);
                                        break;
                                }
                        }
@@ -874,17 +868,20 @@ bool ModelExecution::r_modification_order(ModelAction *curr, const ModelAction *
                                if (act->is_write()) {
                                        if (mo_graph->checkReachable(rf, act))
                                                return false;
-                                       priorset->push_back(act);
+                                       if (!check_only)
+                                               priorset->push_back(act);
                                } else {
                                        const ModelAction *prevrf = act->get_reads_from();
                                        if (!prevrf->equals(rf)) {
                                                if (mo_graph->checkReachable(rf, prevrf))
                                                        return false;
-                                               priorset->push_back(prevrf);
+                                               if (!check_only)
+                                                       priorset->push_back(prevrf);
                                        } else {
                                                if (act->get_tid() == curr->get_tid()) {
                                                        //Can prune curr from obj list
-                                                       *canprune = true;
+                                                       if (!check_only)
+                                                               *canprune = true;
                                                }
                                        }
                                }
@@ -1111,16 +1108,15 @@ 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()) {
+       SnapVector<action_list_t> *objvec = get_safe_ptr_vect_action(&obj_thrd_map, act->get_location());
+       if (objvec->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++) {
+                       for(int i = oldsize;i < uninit_id + 1;i++) {
                                new (&(*vec)[i]) action_list_t();
                        }
                }
@@ -1136,7 +1132,7 @@ void ModelExecution::add_uninit_action_to_lists(ModelAction *act)
        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++)
+               for(uint i = oldsize;i < priv->next_thread_id;i++)
                        new (&(*vec)[i]) action_list_t();
        }
        if (uninit)
@@ -1160,8 +1156,10 @@ void ModelExecution::add_uninit_action_to_lists(ModelAction *act)
 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);
+       if ((act->is_fence() && act->is_seqcst()) || act->is_unlock()) {
+         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);
@@ -1171,7 +1169,7 @@ void ModelExecution::add_action_to_lists(ModelAction *act)
        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++)
+               for(uint i = oldsize;i < priv->next_thread_id;i++)
                        new (&(*vec)[i]) action_list_t();
        }
        (*vec)[tid].push_back(act);
@@ -1196,7 +1194,7 @@ void ModelExecution::add_action_to_lists(ModelAction *act)
                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++)
+                       for(uint i = oldsize;i < priv->next_thread_id;i++)
                                new (&(*vec)[i]) action_list_t();
                }
                (*vec)[tid].push_back(act);
@@ -1250,9 +1248,6 @@ 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);
-
        // 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()) {
@@ -1569,13 +1564,11 @@ void ModelExecution::print_summary()
 #endif
 
        model_print("Execution trace %d:", get_execution_number());
-       if (isfeasibleprefix()) {
-               if (scheduler->all_threads_sleeping())
-                       model_print(" SLEEP-SET REDUNDANT");
-               if (have_bug_reports())
-                       model_print(" DETECTED BUG(S)");
-       } else
-               print_infeasibility(" INFEASIBLE");
+       if (scheduler->all_threads_sleeping())
+               model_print(" SLEEP-SET REDUNDANT");
+       if (have_bug_reports())
+               model_print(" DETECTED BUG(S)");
+
        model_print("\n");
 
        print_list(&action_trace);
@@ -1671,7 +1664,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 */
@@ -1683,6 +1676,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