action: add get_mutex()
[model-checker.git] / model.cc
index 5a1f3992343bc4376fc1c0570832efe9e6bc43d9..7741760025162b786b48c903aaf86937bb4cb0f1 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -853,7 +853,6 @@ ModelAction * ModelChecker::get_next_backtrack()
 bool ModelChecker::process_read(ModelAction *curr)
 {
        Node *node = curr->get_node();
-       uint64_t value = VALUE_NONE;
        while (true) {
                bool updated = false;
                switch (node->get_read_from_status()) {
@@ -864,27 +863,25 @@ bool ModelChecker::process_read(ModelAction *curr)
                        mo_graph->startChanges();
 
                        ASSERT(!is_infeasible());
-                       if (!check_recency(curr, rf))
-                               priv->too_many_reads = true;
-                       updated = r_modification_order(curr, rf);
-
-                       if (is_infeasible() && node->increment_read_from()) {
-                               mo_graph->rollbackChanges();
-                               priv->too_many_reads = false;
-                               continue;
+                       if (!check_recency(curr, rf)) {
+                               if (node->increment_read_from()) {
+                                       mo_graph->rollbackChanges();
+                                       continue;
+                               } else {
+                                       priv->too_many_reads = true;
+                               }
                        }
 
-                       value = rf->get_value();
+                       updated = r_modification_order(curr, rf);
                        read_from(curr, rf);
                        mo_graph->commitChanges();
                        mo_check_promises(curr, true);
-
                        break;
                }
                case READ_FROM_PROMISE: {
                        Promise *promise = curr->get_node()->get_read_from_promise();
-                       promise->add_reader(curr);
-                       value = promise->get_value();
+                       if (promise->add_reader(curr))
+                               priv->failed_promise = true;
                        curr->set_read_from_promise(promise);
                        mo_graph->startChanges();
                        if (!check_recency(curr, promise))
@@ -897,7 +894,6 @@ bool ModelChecker::process_read(ModelAction *curr)
                        /* Read from future value */
                        struct future_value fv = node->get_future_value();
                        Promise *promise = new Promise(curr, fv);
-                       value = fv.value;
                        curr->set_read_from_promise(promise);
                        promises->push_back(promise);
                        mo_graph->startChanges();
@@ -908,7 +904,7 @@ bool ModelChecker::process_read(ModelAction *curr)
                default:
                        ASSERT(false);
                }
-               get_thread(curr)->set_return_value(value);
+               get_thread(curr)->set_return_value(curr->get_return_value());
                return updated;
        }
 }
@@ -931,16 +927,11 @@ bool ModelChecker::process_read(ModelAction *curr)
  */
 bool ModelChecker::process_mutex(ModelAction *curr)
 {
-       std::mutex *mutex = NULL;
+       std::mutex *mutex = curr->get_mutex();
        struct std::mutex_state *state = NULL;
 
-       if (curr->is_trylock() || curr->is_lock() || curr->is_unlock()) {
-               mutex = (std::mutex *)curr->get_location();
-               state = mutex->get_state();
-       } else if (curr->is_wait()) {
-               mutex = (std::mutex *)curr->get_value();
+       if (mutex)
                state = mutex->get_state();
-       }
 
        switch (curr->get_type()) {
        case ATOMIC_TRYLOCK: {
@@ -1644,6 +1635,17 @@ ModelAction * ModelChecker::process_rmw(ModelAction *act) {
        return lastread;
 }
 
+/**
+ * A helper function for ModelChecker::check_recency, to check if the current
+ * thread is able to read from a different write/promise for 'params.maxreads'
+ * number of steps and if that write/promise should become visible (i.e., is
+ * ordered later in the modification order). This helps model memory liveness.
+ *
+ * @param curr The current action. Must be a read.
+ * @param rf The write/promise from which we plan to read
+ * @param other_rf The write/promise from which we may read
+ * @return True if we were able to read from other_rf for params.maxreads steps
+ */
 template <typename T, typename U>
 bool ModelChecker::should_read_instead(const ModelAction *curr, const T *rf, const U *other_rf) const
 {
@@ -1672,13 +1674,14 @@ bool ModelChecker::should_read_instead(const ModelAction *curr, const T *rf, con
 }
 
 /**
- * Checks whether a thread has read from the same write for too many times
- * without seeing the effects of a later write.
+ * Checks whether a thread has read from the same write or Promise for too many
+ * times without seeing the effects of a later write/Promise.
  *
  * Basic idea:
- * 1) there must a different write that we could read from that would satisfy the modification order,
- * 2) we must have read from the same value in excess of maxreads times, and
- * 3) that other write must have been in the reads_from set for maxreads times.
+ * 1) there must a different write/promise that we could read from,
+ * 2) we must have read from the same write/promise in excess of maxreads times,
+ * 3) that other write/promise must have been in the reads_from set for maxreads times, and
+ * 4) that other write/promise must be mod-ordered after the write/promise we are reading.
  *
  * If so, we decide that the execution is no longer feasible.
  *
@@ -2500,7 +2503,6 @@ int ModelChecker::get_promise_to_resolve(const ModelAction *curr) const
 bool ModelChecker::resolve_promise(ModelAction *write, unsigned int promise_idx)
 {
        std::vector< ModelAction *, ModelAlloc<ModelAction *> > actions_to_check;
-       promise_list_t mustResolve;
        Promise *promise = (*promises)[promise_idx];
 
        for (unsigned int i = 0; i < promise->get_num_readers(); i++) {
@@ -2510,20 +2512,23 @@ bool ModelChecker::resolve_promise(ModelAction *write, unsigned int promise_idx)
        }
        /* Make sure the promise's value matches the write's value */
        ASSERT(promise->is_compatible(write) && promise->same_value(write));
-       mo_graph->resolvePromise(promise, write, &mustResolve);
+       if (!mo_graph->resolvePromise(promise, write))
+               priv->failed_promise = true;
 
        promises->erase(promises->begin() + promise_idx);
-
-       /** @todo simplify the 'mustResolve' stuff */
-       ASSERT(mustResolve.size() <= 1);
-
-       if (!mustResolve.empty() && mustResolve[0] != promise)
-               priv->failed_promise = true;
-       delete promise;
+       /**
+        * @todo  It is possible to end up in an inconsistent state, where a
+        * "resolved" promise may still be referenced if
+        * CycleGraph::resolvePromise() failed, so don't delete 'promise'.
+        *
+        * Note that the inconsistency only matters when dumping mo_graph to
+        * file.
+        *
+        * delete promise;
+        */
 
        //Check whether reading these writes has made threads unable to
        //resolve promises
-
        for (unsigned int i = 0; i < actions_to_check.size(); i++) {
                ModelAction *read = actions_to_check[i];
                mo_check_promises(read, true);