model: refactor build_reads_from_past
[c11tester.git] / model.cc
index f67b552dcd74ce3db332c2b157cc2515d600072f..94620ea9d0400fcee239973705361210542040f5 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -101,7 +101,7 @@ thread_id_t ModelChecker::get_next_id()
 }
 
 /** @return the number of user threads created during this execution */
-unsigned int ModelChecker::get_num_threads()
+unsigned int ModelChecker::get_num_threads() const
 {
        return priv->next_thread_id;
 }
@@ -208,7 +208,7 @@ Thread * ModelChecker::get_next_thread(ModelAction *curr)
        return thread_map->get(id_to_int(tid));
 }
 
-/** 
+/**
  * We need to know what the next actions of all threads in the sleep
  * set will be.  This method computes them and stores the actions at
  * the corresponding thread object's pending action.
@@ -218,7 +218,8 @@ void ModelChecker::execute_sleep_set() {
        for(unsigned int i=0;i<get_num_threads();i++) {
                thread_id_t tid=int_to_id(i);
                Thread *thr=get_thread(tid);
-               if ( scheduler->get_enabled(thr) == THREAD_SLEEP_SET ) {
+               if ( scheduler->get_enabled(thr) == THREAD_SLEEP_SET &&
+                                thr->get_pending() == NULL ) {
                        thr->set_state(THREAD_RUNNING);
                        scheduler->next_thread(thr);
                        Thread::swap(&system_context, thr);
@@ -240,7 +241,27 @@ void ModelChecker::wake_up_sleeping_actions(ModelAction * curr) {
                                scheduler->remove_sleep(thr);
                        }
                }
-       }       
+       }
+}
+
+/**
+ * Check if we are in a deadlock. Should only be called at the end of an
+ * execution, although it should not give false positives in the middle of an
+ * execution (there should be some ENABLED thread).
+ *
+ * @return True if program is in a deadlock; false otherwise
+ */
+bool ModelChecker::is_deadlocked() const
+{
+       bool blocking_threads = false;
+       for (unsigned int i = 0; i < get_num_threads(); i++) {
+               Thread *t = get_thread(int_to_id(i));
+               if (scheduler->is_enabled(t) != THREAD_DISABLED)
+                       return false;
+               else if (!t->is_model_thread() && t->get_pending())
+                       blocking_threads = true;
+       }
+       return blocking_threads;
 }
 
 /**
@@ -256,6 +277,8 @@ bool ModelChecker::next_execution()
 
        num_executions++;
 
+       if (is_deadlocked())
+               printf("ERROR: DEADLOCK\n");
        if (isfinalfeasible()) {
                printf("Earliest divergence point since last feasible execution:\n");
                if (earliest_diverge)
@@ -271,8 +294,10 @@ bool ModelChecker::next_execution()
                        pending_rel_seqs->size());
 
 
-       if (isfinalfeasible() || (params.bound != 0 && priv->used_sequence_numbers > params.bound ) || DBG_ENABLED() )
+       if (isfinalfeasible() || (params.bound != 0 && priv->used_sequence_numbers > params.bound ) || DBG_ENABLED() ) {
+               checkDataRaces();
                print_summary();
+       }
 
        if ((diverge = get_next_backtrack()) == NULL)
                return false;
@@ -390,7 +415,7 @@ void ModelChecker::set_backtracking(ModelAction *act)
                /* Don't backtrack into a point where the thread is disabled or sleeping. */
                if (node->enabled_status(tid)!=THREAD_ENABLED)
                        continue;
-       
+
                /* Check if this has been explored already */
                if (node->has_been_explored(tid))
                        continue;
@@ -971,7 +996,7 @@ bool ModelChecker::promises_expired() {
 /** @return whether the current partial trace must be a prefix of a
  * feasible trace. */
 bool ModelChecker::isfeasibleprefix() {
-       return promises->size() == 0 && pending_rel_seqs->size() == 0;
+       return promises->size() == 0 && pending_rel_seqs->size() == 0 && isfeasible();
 }
 
 /** @return whether the current partial trace is feasible. */
@@ -1063,7 +1088,7 @@ void ModelChecker::check_recency(ModelAction *curr, const ModelAction *rf) {
                        ModelAction *act = *rit;
                        if (!act->is_read())
                                return;
-                       
+
                        if (act->get_reads_from() != rf)
                                return;
                        if (act->get_node()->get_read_from_size() <= 1)
@@ -1288,7 +1313,7 @@ bool ModelChecker::w_modification_order(ModelAction *curr)
                                 * 1) If RMW and it actually read from something, then we
                                 * already have all relevant edges, so just skip to next
                                 * thread.
-                                * 
+                                *
                                 * 2) If RMW and it didn't read from anything, we should
                                 * whatever edge we can get to speed up convergence.
                                 *
@@ -1298,7 +1323,7 @@ bool ModelChecker::w_modification_order(ModelAction *curr)
                                if (curr->is_rmw()) {
                                        if (curr->get_reads_from()!=NULL)
                                                break;
-                                       else 
+                                       else
                                                continue;
                                } else
                                        continue;
@@ -1317,7 +1342,7 @@ bool ModelChecker::w_modification_order(ModelAction *curr)
                                 */
                                if (act->is_write())
                                        mo_graph->addEdge(act, curr);
-                               else if (act->is_read()) { 
+                               else if (act->is_read()) {
                                        //if previous read accessed a null, just keep going
                                        if (act->get_reads_from() == NULL)
                                                continue;
@@ -1385,10 +1410,9 @@ bool ModelChecker::mo_may_allow(const ModelAction *writer, const ModelAction *re
 {
        std::vector<action_list_t> *thrd_lists = obj_thrd_map->get_safe_ptr(reader->get_location());
        unsigned int i;
-
        /* Iterate over all threads */
        for (i = 0; i < thrd_lists->size(); i++) {
-               ModelAction *write_after_read = NULL;
+               const ModelAction *write_after_read = NULL;
 
                /* Iterate over actions in thread, starting from most recent */
                action_list_t *list = &(*thrd_lists)[i];
@@ -1400,12 +1424,14 @@ bool ModelChecker::mo_may_allow(const ModelAction *writer, const ModelAction *re
                                break;
                        else if (act->is_write())
                                write_after_read = act;
+                       else if (act->is_read() && act->get_reads_from() != NULL && act != reader) {
+                               write_after_read = act->get_reads_from();
+                       }
                }
 
-               if (write_after_read && mo_graph->checkReachable(write_after_read, writer))
+               if (write_after_read && write_after_read!=writer && mo_graph->checkReachable(write_after_read, writer))
                        return false;
        }
-
        return true;
 }
 
@@ -1686,7 +1712,7 @@ void ModelChecker::add_action_to_lists(ModelAction *act)
        if (act->is_wait()) {
                void *mutex_loc=(void *) act->get_value();
                obj_map->get_safe_ptr(mutex_loc)->push_back(act);
-       
+
                std::vector<action_list_t> *vec = obj_thrd_map->get_safe_ptr(mutex_loc);
                if (tid >= (int)vec->size())
                        vec->resize(priv->next_thread_id);
@@ -1798,7 +1824,7 @@ bool ModelChecker::resolve_promises(ModelAction *write)
                        //Make sure the promise's value matches the write's value
                        ASSERT(promise->get_value() == write->get_value());
                        delete(promise);
-                       
+
                        promises->erase(promises->begin() + promise_index);
                        threads_to_check.push_back(read->get_tid());
 
@@ -1833,7 +1859,7 @@ void ModelChecker::compute_promises(ModelAction *curr)
                                !act->same_thread(curr) &&
                                act->get_location() == curr->get_location() &&
                                promise->get_value() == curr->get_value()) {
-                       curr->get_node()->set_promise(i);
+                       curr->get_node()->set_promise(i, act->is_rmw());
                }
        }
 }
@@ -1855,10 +1881,20 @@ void ModelChecker::check_promises(thread_id_t tid, ClockVector *old_cv, ClockVec
        }
 }
 
+void ModelChecker::check_promises_thread_disabled() {
+       for (unsigned int i = 0; i < promises->size(); i++) {
+               Promise *promise = (*promises)[i];
+               if (promise->check_promise()) {
+                       failed_promise = true;
+                       return;
+               }
+       }
+}
+
 /** Checks promises in response to addition to modification order for threads.
  * Definitions:
  * pthread is the thread that performed the read that created the promise
- * 
+ *
  * pread is the read that created the promise
  *
  * pwrite is either the first write to same location as pread by
@@ -1887,7 +1923,7 @@ void ModelChecker::mo_check_promises(thread_id_t tid, const ModelAction *write)
        for (unsigned int i = 0; i < promises->size(); i++) {
                Promise *promise = (*promises)[i];
                const ModelAction *act = promise->get_action();
-               
+
                //Is this promise on the same location?
                if ( act->get_location() != location )
                        continue;
@@ -1909,12 +1945,12 @@ void ModelChecker::mo_check_promises(thread_id_t tid, const ModelAction *write)
                                return;
                        }
                }
-               
+
                //Don't do any lookups twice for the same thread
                if (promise->has_sync_thread(tid))
                        continue;
-               
-               if (mo_graph->checkReachable(promise->get_write(), write)) {
+
+               if (promise->get_write()&&mo_graph->checkReachable(promise->get_write(), write)) {
                        if (promise->increment_threads(tid)) {
                                failed_promise = true;
                                return;
@@ -1986,17 +2022,14 @@ void ModelChecker::build_reads_from_past(ModelAction *curr)
 
                        /* Don't consider more than one seq_cst write if we are a seq_cst read. */
                        if (!curr->is_seqcst() || (!act->is_seqcst() && (last_seq_cst == NULL || !act->happens_before(last_seq_cst))) || act == last_seq_cst) {
-                               DEBUG("Adding action to may_read_from:\n");
-                               if (DBG_ENABLED()) {
-                                       act->print();
-                                       curr->print();
-                               }
-
-                               if (curr->get_sleep_flag() && ! curr->is_seqcst()) {
-                                       if (sleep_can_read_from(curr, act))
-                                               curr->get_node()->add_read_from(act);
-                               } else
+                               if (!curr->get_sleep_flag() || curr->is_seqcst() || sleep_can_read_from(curr, act)) {
+                                       DEBUG("Adding action to may_read_from:\n");
+                                       if (DBG_ENABLED()) {
+                                               act->print();
+                                               curr->print();
+                                       }
                                        curr->get_node()->add_read_from(act);
+                               }
                        }
 
                        /* Include at most one act per-thread that "happens before" curr */
@@ -2025,7 +2058,7 @@ void ModelChecker::build_reads_from_past(ModelAction *curr)
 bool ModelChecker::sleep_can_read_from(ModelAction * curr, const ModelAction *write) {
        while(true) {
                Node *prevnode=write->get_node()->get_parent();
-               
+
                bool thread_sleep=prevnode->enabled_status(curr->get_tid())==THREAD_SLEEP_SET;
                if (write->is_release()&&thread_sleep)
                        return true;
@@ -2045,7 +2078,7 @@ static void print_list(action_list_t *list)
        printf("---------------------------------------------------------------------\n");
        printf("Trace:\n");
        unsigned int hash=0;
-       
+
        for (it = list->begin(); it != list->end(); it++) {
                (*it)->print();
                hash=hash^(hash<<3)^((*it)->hash());
@@ -2057,12 +2090,12 @@ static void print_list(action_list_t *list)
 #if SUPPORT_MOD_ORDER_DUMP
 void ModelChecker::dumpGraph(char *filename) {
        char buffer[200];
-  sprintf(buffer, "%s.dot",filename);
-  FILE *file=fopen(buffer, "w");
-  fprintf(file, "digraph %s {\n",filename);
+       sprintf(buffer, "%s.dot",filename);
+       FILE *file=fopen(buffer, "w");
+       fprintf(file, "digraph %s {\n",filename);
        mo_graph->dumpNodes(file);
        ModelAction ** thread_array=(ModelAction **)model_calloc(1, sizeof(ModelAction *)*get_num_threads());
-       
+
        for (action_list_t::iterator it = action_trace->begin(); it != action_trace->end(); it++) {
                ModelAction *action=*it;
                if (action->is_read()) {
@@ -2073,12 +2106,12 @@ void ModelChecker::dumpGraph(char *filename) {
                if (thread_array[action->get_tid()] != NULL) {
                        fprintf(file, "N%u -> N%u[label=\"sb\", color=blue];\n", thread_array[action->get_tid()]->get_seq_number(), action->get_seq_number());
                }
-               
+
                thread_array[action->get_tid()]=action;
        }
-  fprintf(file,"}\n");
+       fprintf(file,"}\n");
        model_free(thread_array);
-  fclose(file);        
+       fclose(file);
 }
 #endif
 
@@ -2095,7 +2128,7 @@ void ModelChecker::print_summary()
        sprintf(buffername, "exec%04u", num_executions);
        mo_graph->dumpGraphToFile(buffername);
        sprintf(buffername, "graph%04u", num_executions);
-  dumpGraph(buffername);
+       dumpGraph(buffername);
 #endif
 
        if (!isfinalfeasible())
@@ -2116,7 +2149,7 @@ void ModelChecker::add_thread(Thread *t)
 }
 
 /**
- * Removes a thread from the scheduler. 
+ * Removes a thread from the scheduler.
  * @param the thread to remove.
  */
 void ModelChecker::remove_thread(Thread *t)