+/**
+ * This is the strongest feasibility check available.
+ * @return whether the current trace (partial or complete) must be a prefix of
+ * a feasible trace.
+ */
+bool ModelChecker::isfeasibleprefix() const
+{
+ return pending_rel_seqs->size() == 0 && is_feasible_prefix_ignore_relseq();
+}
+
+/**
+ * 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 ModelChecker::print_infeasibility(const char *prefix) const
+{
+ char buf[100];
+ char *ptr = buf;
+ if (mo_graph->checkForCycles())
+ ptr += sprintf(ptr, "[mo cycle]");
+ if (priv->failed_promise)
+ ptr += sprintf(ptr, "[failed promise]");
+ if (priv->too_many_reads)
+ ptr += sprintf(ptr, "[too many reads]");
+ if (priv->no_valid_reads)
+ ptr += sprintf(ptr, "[no valid reads-from]");
+ if (priv->bad_synchronization)
+ ptr += sprintf(ptr, "[bad sw ordering]");
+ if (promises_expired())
+ ptr += sprintf(ptr, "[promise expired]");
+ if (promises->size() != 0)
+ ptr += sprintf(ptr, "[unresolved promise]");
+ if (ptr != buf)
+ model_print("%s: %s\n", prefix ? prefix : "Infeasible", buf);
+}
+
+/**
+ * Returns whether the current completed trace is feasible, except for pending
+ * release sequences.
+ */
+bool ModelChecker::is_feasible_prefix_ignore_relseq() const
+{
+ return !is_infeasible() && promises->size() == 0;
+}
+
+/**
+ * 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 ModelChecker::is_infeasible() const
+{
+ return mo_graph->checkForCycles() ||
+ priv->no_valid_reads ||
+ priv->failed_promise ||
+ priv->too_many_reads ||
+ priv->bad_synchronization ||
+ promises_expired();
+}
+
+/** Close out a RMWR by converting previous RMWR into a RMW or READ. */
+ModelAction * ModelChecker::process_rmw(ModelAction *act) {
+ ModelAction *lastread = get_last_action(act->get_tid());
+ lastread->process_rmw(act);
+ if (act->is_rmw()) {
+ if (lastread->get_reads_from())
+ mo_graph->addRMWEdge(lastread->get_reads_from(), lastread);
+ else
+ mo_graph->addRMWEdge(lastread->get_reads_from_promise(), lastread);
+ mo_graph->commitChanges();
+ }
+ return lastread;
+}
+
+/**
+ * Checks whether a thread has read from the same write for too many times
+ * without seeing the effects of a later write.
+ *
+ * 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.
+ *
+ * If so, we decide that the execution is no longer feasible.
+ */
+void ModelChecker::check_recency(ModelAction *curr, const ModelAction *rf)
+{
+ if (params.maxreads != 0) {
+ if (curr->get_node()->get_read_from_size() <= 1)
+ return;
+ //Must make sure that execution is currently feasible... We could
+ //accidentally clear by rolling back
+ if (is_infeasible())
+ return;
+ std::vector<action_list_t> *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, curr->get_location());
+ int tid = id_to_int(curr->get_tid());
+
+ /* Skip checks */
+ if ((int)thrd_lists->size() <= tid)
+ return;
+ action_list_t *list = &(*thrd_lists)[tid];
+
+ action_list_t::reverse_iterator rit = list->rbegin();
+ /* Skip past curr */
+ for (; (*rit) != curr; rit++)
+ ;
+ /* go past curr now */
+ rit++;
+
+ action_list_t::reverse_iterator ritcopy = rit;
+ //See if we have enough reads from the same value
+ int count = 0;
+ for (; count < params.maxreads; rit++, count++) {
+ if (rit == list->rend())
+ return;
+ ModelAction *act = *rit;
+ if (!act->is_read())
+ return;
+
+ if (act->get_reads_from() != rf)
+ return;
+ if (act->get_node()->get_read_from_size() <= 1)
+ return;
+ }
+ for (int i = 0; i < curr->get_node()->get_read_from_size(); i++) {
+ /* Get write */
+ const ModelAction *write = curr->get_node()->get_read_from_at(i);
+
+ /* Need a different write */
+ if (write == rf)
+ continue;
+
+ /* Test to see whether this is a feasible write to read from */
+ /** NOTE: all members of read-from set should be
+ * feasible, so we no longer check it here **/
+
+ rit = ritcopy;
+
+ bool feasiblewrite = true;
+ //new we need to see if this write works for everyone
+
+ for (int loop = count; loop > 0; loop--, rit++) {
+ ModelAction *act = *rit;
+ bool foundvalue = false;
+ for (int j = 0; j < act->get_node()->get_read_from_size(); j++) {
+ if (act->get_node()->get_read_from_at(j) == write) {
+ foundvalue = true;
+ break;
+ }
+ }
+ if (!foundvalue) {
+ feasiblewrite = false;
+ break;
+ }
+ }
+ if (feasiblewrite) {
+ priv->too_many_reads = true;
+ return;
+ }
+ }
+ }
+}
+
+/**
+ * Updates the mo_graph with the constraints imposed from the current
+ * read.
+ *
+ * Basic idea is the following: Go through each other thread and find
+ * the last action that happened before our read. Two cases:
+ *
+ * (1) The action is a write => that write must either occur before
+ * the write we read from or be the write we read from.
+ *
+ * (2) The action is a read => the write that that action read from
+ * must occur before the write we read from or be the same write.
+ *
+ * @param curr The current action. Must be a read.
+ * @param rf The ModelAction or Promise that curr reads from. Must be a write.
+ * @return True if modification order edges were added; false otherwise
+ */
+template <typename rf_type>
+bool ModelChecker::r_modification_order(ModelAction *curr, const rf_type *rf)
+{
+ std::vector<action_list_t> *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, curr->get_location());
+ unsigned int i;
+ bool added = false;
+ 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);
+
+ /* Iterate over all threads */
+ for (i = 0; i < thrd_lists->size(); i++) {
+ /* Last SC fence in thread i */
+ ModelAction *last_sc_fence_thread_local = NULL;
+ if (int_to_id((int)i) != curr->get_tid())
+ last_sc_fence_thread_local = get_last_seq_cst_fence(int_to_id(i), NULL);
+
+ /* Last SC fence in thread i, before last SC fence in current thread */
+ ModelAction *last_sc_fence_thread_before = NULL;
+ if (last_sc_fence_local)
+ last_sc_fence_thread_before = get_last_seq_cst_fence(int_to_id(i), last_sc_fence_local);
+
+ /* Iterate over actions in thread, starting from most recent */
+ action_list_t *list = &(*thrd_lists)[i];
+ action_list_t::reverse_iterator rit;
+ for (rit = list->rbegin(); rit != list->rend(); rit++) {
+ ModelAction *act = *rit;
+
+ if (act->is_write() && !act->equals(rf) && act != curr) {
+ /* C++, Section 29.3 statement 5 */
+ if (curr->is_seqcst() && last_sc_fence_thread_local &&
+ *act < *last_sc_fence_thread_local) {
+ added = mo_graph->addEdge(act, rf) || added;
+ break;
+ }
+ /* C++, Section 29.3 statement 4 */
+ else if (act->is_seqcst() && last_sc_fence_local &&
+ *act < *last_sc_fence_local) {
+ added = mo_graph->addEdge(act, rf) || added;
+ break;
+ }
+ /* C++, Section 29.3 statement 6 */
+ else if (last_sc_fence_thread_before &&
+ *act < *last_sc_fence_thread_before) {
+ added = mo_graph->addEdge(act, rf) || added;
+ break;
+ }
+ }
+
+ /*
+ * Include at most one act per-thread that "happens
+ * before" curr. Don't consider reflexively.
+ */
+ if (act->happens_before(curr) && act != curr) {
+ if (act->is_write()) {
+ if (!act->equals(rf)) {
+ added = mo_graph->addEdge(act, rf) || added;
+ }
+ } else {
+ const ModelAction *prevreadfrom = act->get_reads_from();
+ //if the previous read is unresolved, keep going...
+ if (prevreadfrom == NULL)
+ continue;
+
+ if (!prevreadfrom->equals(rf)) {
+ added = mo_graph->addEdge(prevreadfrom, rf) || added;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ /*
+ * All compatible, thread-exclusive promises must be ordered after any
+ * concrete loads from the same thread
+ */
+ for (unsigned int i = 0; i < promises->size(); i++)
+ if ((*promises)[i]->is_compatible_exclusive(curr))
+ added = mo_graph->addEdge(rf, (*promises)[i]) || added;
+
+ return added;
+}
+
+/**
+ * Updates the mo_graph with the constraints imposed from the current write.
+ *
+ * Basic idea is the following: Go through each other thread and find
+ * the lastest action that happened before our write. Two cases:
+ *
+ * (1) The action is a write => that write must occur before
+ * the current write
+ *
+ * (2) The action is a read => the write that that action read from
+ * must occur before the current write.
+ *
+ * This method also handles two other issues:
+ *
+ * (I) Sequential Consistency: Making sure that if the current write is
+ * seq_cst, that it occurs after the previous seq_cst write.
+ *
+ * (II) Sending the write back to non-synchronizing reads.
+ *
+ * @param curr The current action. Must be a write.
+ * @return True if modification order edges were added; false otherwise
+ */
+bool ModelChecker::w_modification_order(ModelAction *curr)
+{
+ std::vector<action_list_t> *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, curr->get_location());
+ unsigned int i;
+ bool added = false;
+ ASSERT(curr->is_write());
+
+ if (curr->is_seqcst()) {
+ /* We have to at least see the last sequentially consistent write,
+ so we are initialized. */
+ ModelAction *last_seq_cst = get_last_seq_cst_write(curr);
+ if (last_seq_cst != NULL) {
+ added = mo_graph->addEdge(last_seq_cst, curr) || added;
+ }
+ }
+
+ /* Last SC fence in the current thread */
+ ModelAction *last_sc_fence_local = get_last_seq_cst_fence(curr->get_tid(), NULL);
+
+ /* Iterate over all threads */
+ for (i = 0; i < thrd_lists->size(); i++) {
+ /* Last SC fence in thread i, before last SC fence in current thread */
+ ModelAction *last_sc_fence_thread_before = NULL;
+ if (last_sc_fence_local && int_to_id((int)i) != curr->get_tid())
+ last_sc_fence_thread_before = get_last_seq_cst_fence(int_to_id(i), last_sc_fence_local);
+
+ /* Iterate over actions in thread, starting from most recent */
+ action_list_t *list = &(*thrd_lists)[i];
+ action_list_t::reverse_iterator rit;
+ for (rit = list->rbegin(); rit != list->rend(); rit++) {
+ ModelAction *act = *rit;
+ if (act == 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.
+ *
+ * 3) If normal write, we need to look at earlier actions, so
+ * continue processing list.
+ */
+ if (curr->is_rmw()) {
+ if (curr->get_reads_from() != NULL)
+ break;
+ else
+ continue;
+ } else
+ continue;
+ }
+
+ /* C++, Section 29.3 statement 7 */
+ if (last_sc_fence_thread_before && act->is_write() &&
+ *act < *last_sc_fence_thread_before) {
+ added = mo_graph->addEdge(act, curr) || added;
+ break;
+ }
+
+ /*
+ * Include at most one act per-thread that "happens
+ * before" curr
+ */
+ if (act->happens_before(curr)) {
+ /*
+ * Note: if act is RMW, just add edge:
+ * act --mo--> curr
+ * The following edge should be handled elsewhere:
+ * readfrom(act) --mo--> act
+ */
+ if (act->is_write())
+ added = mo_graph->addEdge(act, curr) || added;
+ else if (act->is_read()) {
+ //if previous read accessed a null, just keep going
+ if (act->get_reads_from() == NULL)
+ continue;
+ added = mo_graph->addEdge(act->get_reads_from(), curr) || added;
+ }
+ break;
+ } else if (act->is_read() && !act->could_synchronize_with(curr) &&
+ !act->same_thread(curr)) {
+ /* We have an action that:
+ (1) did not happen before us
+ (2) is a read and we are a write
+ (3) cannot synchronize with us
+ (4) is in a different thread
+ =>
+ that read could potentially read from our write. Note that
+ these checks are overly conservative at this point, we'll
+ do more checks before actually removing the
+ pendingfuturevalue.
+
+ */
+ if (thin_air_constraint_may_allow(curr, act)) {
+ if (!is_infeasible())
+ futurevalues->push_back(PendingFutureValue(curr, act));
+ else if (curr->is_rmw() && act->is_rmw() && curr->get_reads_from() && curr->get_reads_from() == act->get_reads_from())
+ add_future_value(curr, act);
+ }
+ }
+ }
+ }
+
+ /*
+ * All compatible, thread-exclusive promises must be ordered after any
+ * concrete stores to the same thread, or else they can be merged with
+ * this store later
+ */
+ for (unsigned int i = 0; i < promises->size(); i++)
+ if ((*promises)[i]->is_compatible_exclusive(curr))
+ added = mo_graph->addEdge(curr, (*promises)[i]) || added;
+
+ return added;
+}
+
+/** Arbitrary reads from the future are not allowed. Section 29.3
+ * part 9 places some constraints. This method checks one result of constraint
+ * constraint. Others require compiler support. */
+bool ModelChecker::thin_air_constraint_may_allow(const ModelAction *writer, const ModelAction *reader)
+{
+ if (!writer->is_rmw())
+ return true;
+
+ if (!reader->is_rmw())
+ return true;
+
+ for (const ModelAction *search = writer->get_reads_from(); search != NULL; search = search->get_reads_from()) {
+ if (search == reader)
+ return false;
+ if (search->get_tid() == reader->get_tid() &&
+ search->happens_before(reader))
+ break;
+ }