priv = (struct model_snapshot_members *)calloc(1, sizeof(*priv));
/* First thread created will have id INITIAL_THREAD_ID */
priv->next_thread_id = INITIAL_THREAD_ID;
+
+ lazy_sync_size = &priv->lazy_sync_size;
}
/** @brief Destructor */
}
/**
- * Choose the next thread in the replay sequence.
+ * @brief Choose the next thread to execute.
*
- * If the replay sequence has reached the 'diverge' point, returns a thread
- * from the backtracking set. Otherwise, simply returns the next thread in the
- * sequence that is being replayed.
+ * This function chooses the next thread that should execute. It can force the
+ * adjacency of read/write portions of a RMW action, force THREAD_CREATE to be
+ * followed by a THREAD_START, or it can enforce execution replay/backtracking.
+ * The model-checker may have no preference regarding the next thread (i.e.,
+ * when exploring a new execution ordering), in which case this will return
+ * NULL.
+ * @param curr The current ModelAction. This action might guide the choice of
+ * next thread.
+ * @return The next thread to run. If the model-checker has no preference, NULL.
*/
-Thread * ModelChecker::get_next_replay_thread()
+Thread * ModelChecker::get_next_thread(ModelAction *curr)
{
thread_id_t tid;
+ /* Do not split atomic actions. */
+ if (curr->is_rmwr())
+ return thread_current();
+ /* The THREAD_CREATE action points to the created Thread */
+ else if (curr->get_type() == THREAD_CREATE)
+ return (Thread *)curr->get_location();
+
/* Have we completed exploring the preselected path? */
if (diverge == NULL)
return NULL;
set_backtracking(curr);
- /* Do not split atomic actions. */
- if (curr->is_rmwr())
- return thread_current();
- /* The THREAD_CREATE action points to the created Thread */
- else if (curr->get_type() == THREAD_CREATE)
- return (Thread *)curr->get_location();
- else
- return get_next_replay_thread();
+ return get_next_thread(curr);
}
/** @returns whether the current partial trace must be a prefix of a
* feasible trace. */
-
bool ModelChecker::isfeasibleprefix() {
- return promises->size()==0;
+ return promises->size() == 0 && *lazy_sync_size == 0;
}
/** @returns whether the current partial trace is feasible. */
if (rf->is_release())
release_heads->push_back(rf);
if (rf->is_rmw()) {
- if (rf->is_acquire())
+ /* We need a RMW action that is both an acquire and release to stop */
+ /** @todo Need to be smarter here... In the linux lock
+ * example, this will run to the beginning of the program for
+ * every acquire. */
+ if (rf->is_acquire() && rf->is_release())
return true; /* complete */
return release_seq_head(rf->get_reads_from(), release_heads);
}
std::list<ModelAction *> *list;
list = lazy_sync_with_release->get_safe_ptr(act->get_location());
list->push_back(act);
+ (*lazy_sync_size)++;
}
}
propagate->synchronize_with(act);
}
}
- if (complete)
+ if (complete) {
it = list->erase(it);
- else
+ (*lazy_sync_size)--;
+ } else
it++;
}