/* Print all model-checker output before rollback */
fflush(model_out);
- snapshotObject->backTrackBeforeStep(0);
+ snapshot_backtrack_before(0);
}
/** @return a thread ID for a new Thread */
return priv->next_thread_id;
}
-/** @return The currently executing Thread. */
+/**
+ * Must be called from user-thread context (e.g., through the global
+ * thread_current() interface)
+ *
+ * @return The currently executing Thread.
+ */
Thread * ModelChecker::get_current_thread() const
{
return scheduler->get_current_thread();
/* 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();
+ return curr->get_thread_operand();
}
/* Have we completed exploring the preselected path? */
tid = next->get_tid();
node_stack->pop_restofstack(2);
} else {
+ ASSERT(prevnode);
/* Make a different thread execute for next step */
- scheduler->add_sleep(thread_map->get(id_to_int(next->get_tid())));
+ scheduler->add_sleep(get_thread(next->get_tid()));
tid = prevnode->get_next_backtrack();
/* Make sure the backtracked thread isn't sleeping. */
node_stack->pop_restofstack(1);
record_stats();
/* Output */
- if (DBG_ENABLED() || params.verbose || have_bug_reports())
+ if (DBG_ENABLED() || params.verbose || (complete && have_bug_reports()))
print_execution(complete);
else
clear_program_output();
action_list_t::reverse_iterator rit;
for (rit = list->rbegin(); rit != list->rend(); rit++) {
ModelAction *prev = *rit;
- if (!act->same_thread(prev)&&prev->is_failed_trylock())
+ if (!act->same_thread(prev) && prev->is_failed_trylock())
return prev;
}
break;
action_list_t::reverse_iterator rit;
for (rit = list->rbegin(); rit != list->rend(); rit++) {
ModelAction *prev = *rit;
- if (!act->same_thread(prev)&&prev->is_failed_trylock())
+ if (!act->same_thread(prev) && prev->is_failed_trylock())
return prev;
- if (!act->same_thread(prev)&&prev->is_notify())
+ if (!act->same_thread(prev) && prev->is_notify())
return prev;
}
break;
action_list_t::reverse_iterator rit;
for (rit = list->rbegin(); rit != list->rend(); rit++) {
ModelAction *prev = *rit;
- if (!act->same_thread(prev)&&prev->is_wait())
+ if (!act->same_thread(prev) && prev->is_wait())
return prev;
}
break;
Node *node = prev->get_node()->get_parent();
int low_tid, high_tid;
- if (node->is_enabled(t)) {
+ if (node->enabled_status(t->get_id()) == THREAD_ENABLED) {
low_tid = id_to_int(act->get_tid());
high_tid = low_tid + 1;
} else {
high_tid = get_num_threads();
}
- for(int i = low_tid; i < high_tid; i++) {
+ for (int i = low_tid; i < high_tid; i++) {
thread_id_t tid = int_to_id(i);
/* Make sure this thread can be enabled here. */
continue;
}
/* Cache the latest backtracking point */
- if (!priv->next_backtrack || *prev > *priv->next_backtrack)
- priv->next_backtrack = prev;
+ set_latest_backtrack(prev);
/* If this is a new backtracking point, mark the tree */
if (!node->set_backtrack(tid))
}
}
+/**
+ * @brief Cache the a backtracking point as the "most recent", if eligible
+ *
+ * Note that this does not prepare the NodeStack for this backtracking
+ * operation, it only caches the action on a per-execution basis
+ *
+ * @param act The operation at which we should explore a different next action
+ * (i.e., backtracking point)
+ * @return True, if this action is now the most recent backtracking point;
+ * false otherwise
+ */
+bool ModelChecker::set_latest_backtrack(ModelAction *act)
+{
+ if (!priv->next_backtrack || *act > *priv->next_backtrack) {
+ priv->next_backtrack = act;
+ return true;
+ }
+ return false;
+}
+
/**
* Returns last backtracking point. The model checker will explore a different
* path for this point in the next execution.
r_status = r_modification_order(curr, reads_from);
}
-
- if (!second_part_of_rmw&&is_infeasible()&&(curr->get_node()->increment_read_from()||curr->get_node()->increment_future_value())) {
+ if (!second_part_of_rmw && is_infeasible() && (curr->get_node()->increment_read_from() || curr->get_node()->increment_future_value())) {
mo_graph->rollbackChanges();
priv->too_many_reads = false;
continue;
read_from(curr, reads_from);
mo_graph->commitChanges();
- mo_check_promises(curr->get_tid(), reads_from);
+ mo_check_promises(curr->get_tid(), reads_from, NULL);
updated |= r_status;
} else if (!second_part_of_rmw) {
/* Read from future value */
- value = curr->get_node()->get_future_value();
- modelclock_t expiration = curr->get_node()->get_future_value_expiration();
- curr->set_read_from(NULL);
- Promise *valuepromise = new Promise(curr, value, expiration);
- promises->push_back(valuepromise);
+ struct future_value fv = curr->get_node()->get_future_value();
+ Promise *promise = new Promise(curr, fv);
+ value = fv.value;
+ curr->set_read_from_promise(promise);
+ promises->push_back(promise);
}
get_thread(curr)->set_return_value(value);
return updated;
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()) {
+ } else if (curr->is_wait()) {
mutex = (std::mutex *)curr->get_value();
state = mutex->get_state();
}
if (curr->get_node()->get_misc() == 0) {
get_safe_ptr_action(condvar_waiters_map, curr->get_location())->push_back(curr);
//disable us
- scheduler->sleep(get_current_thread());
+ scheduler->sleep(get_thread(curr));
}
break;
}
return false;
}
+void ModelChecker::add_future_value(const ModelAction *writer, ModelAction *reader)
+{
+ /* Do more ambitious checks now that mo is more complete */
+ if (mo_may_allow(writer, reader)) {
+ Node *node = reader->get_node();
+
+ /* Find an ancestor thread which exists at the time of the reader */
+ Thread *write_thread = get_thread(writer);
+ while (id_to_int(write_thread->get_id()) >= node->get_num_threads())
+ write_thread = write_thread->get_parent();
+
+ struct future_value fv = {
+ writer->get_value(),
+ writer->get_seq_number() + params.maxfuturedelay,
+ write_thread->get_id(),
+ };
+ if (node->add_future_value(fv))
+ set_latest_backtrack(reader);
+ }
+}
+
/**
* Process a write ModelAction
* @param curr The ModelAction to process
if (promises->size() == 0) {
for (unsigned int i = 0; i < futurevalues->size(); i++) {
struct PendingFutureValue pfv = (*futurevalues)[i];
- //Do more ambitious checks now that mo is more complete
- if (mo_may_allow(pfv.writer, pfv.act)&&
- pfv.act->get_node()->add_future_value(pfv.writer->get_value(), pfv.writer->get_seq_number()+params.maxfuturedelay) &&
- (!priv->next_backtrack || *pfv.act > *priv->next_backtrack))
- priv->next_backtrack = pfv.act;
+ add_future_value(pfv.writer, pfv.act);
}
- futurevalues->resize(0);
+ futurevalues->clear();
}
mo_graph->commitChanges();
- mo_check_promises(curr->get_tid(), curr);
+ mo_check_promises(curr->get_tid(), curr, NULL);
get_thread(curr)->set_return_value(VALUE_NONE);
return updated_mod_order || updated_promises;
switch (curr->get_type()) {
case THREAD_CREATE: {
- Thread *th = (Thread *)curr->get_location();
+ Thread *th = curr->get_thread_operand();
th->set_creation(curr);
+ /* Promises can be satisfied by children */
+ for (unsigned int i = 0; i < promises->size(); i++) {
+ Promise *promise = (*promises)[i];
+ if (promise->thread_is_available(curr->get_tid()))
+ promise->add_thread(th->get_id());
+ }
break;
}
case THREAD_JOIN: {
- Thread *blocking = (Thread *)curr->get_location();
+ Thread *blocking = curr->get_thread_operand();
ModelAction *act = get_last_action(blocking->get_id());
curr->synchronize_with(act);
updated = true; /* trigger rel-seq checks */
scheduler->wake(get_thread(act));
}
th->complete();
+ /* Completed thread can't satisfy promises */
+ for (unsigned int i = 0; i < promises->size(); i++) {
+ Promise *promise = (*promises)[i];
+ if (promise->thread_is_available(th->get_id()))
+ if (promise->eliminate_thread(th->get_id()))
+ priv->failed_promise = true;
+ }
updated = true; /* trigger rel-seq checks */
break;
}
* execution when running permutations of previously-observed executions.
*
* @param curr The current action to process
- * @return The next Thread that must be executed. May be NULL if ModelChecker
- * makes no choice (e.g., according to replay execution, combining RMW actions,
- * etc.)
+ * @return The ModelAction that is actually executed; may be different than
+ * curr; may be NULL, if the current action is not enabled to run
*/
-Thread * ModelChecker::check_current_action(ModelAction *curr)
+ModelAction * ModelChecker::check_current_action(ModelAction *curr)
{
ASSERT(curr);
bool second_part_of_rmw = curr->is_rmwc() || curr->is_rmw();
if (!check_action_enabled(curr)) {
/* Make the execution look like we chose to run this action
* much later, when a lock/join can succeed */
- get_current_thread()->set_pending(curr);
- scheduler->sleep(get_current_thread());
- return get_next_thread(NULL);
+ get_thread(curr)->set_pending(curr);
+ scheduler->sleep(get_thread(curr));
+ return NULL;
}
bool newly_explored = initialize_curr_action(&curr);
+ DBG();
+ if (DBG_ENABLED())
+ curr->print();
+
wake_up_sleeping_actions(curr);
/* Add the action to lists before any other model-checking tasks */
check_curr_backtracking(curr);
set_backtracking(curr);
- return get_next_thread(curr);
+ return curr;
}
void ModelChecker::check_curr_backtracking(ModelAction *curr)
Node *currnode = curr->get_node();
Node *parnode = currnode->get_parent();
- if ((!parnode->backtrack_empty() ||
+ if ((parnode && !parnode->backtrack_empty()) ||
!currnode->misc_empty() ||
!currnode->read_from_empty() ||
!currnode->future_value_empty() ||
!currnode->promise_empty() ||
- !currnode->relseq_break_empty())
- && (!priv->next_backtrack ||
- *curr > *priv->next_backtrack)) {
- priv->next_backtrack = curr;
+ !currnode->relseq_break_empty()) {
+ set_latest_backtrack(curr);
}
}
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->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
{
- if (DBG_ENABLED() && promises->size() != 0)
- DEBUG("Infeasible: unrevolved promises\n");
-
return !is_infeasible() && promises->size() == 0;
}
*/
bool ModelChecker::is_infeasible() const
{
- if (DBG_ENABLED() && mo_graph->checkForRMWViolation())
- DEBUG("Infeasible: RMW violation\n");
-
- return mo_graph->checkForRMWViolation() || is_infeasible_ignoreRMW();
-}
-
-/**
- * Check If the current partial trace is infeasible, while ignoring
- * infeasibility related to 2 RMW's reading from the same store. It does not
- * check end-of-execution feasibility.
- * @see ModelChecker::is_infeasible
- * @return whether the current partial trace is infeasible, ignoring multiple
- * RMWs reading from the same store.
- * */
-bool ModelChecker::is_infeasible_ignoreRMW() const
-{
- if (DBG_ENABLED()) {
- if (mo_graph->checkForCycles())
- DEBUG("Infeasible: modification order cycles\n");
- if (priv->failed_promise)
- DEBUG("Infeasible: failed promise\n");
- if (priv->too_many_reads)
- DEBUG("Infeasible: too many reads\n");
- if (priv->bad_synchronization)
- DEBUG("Infeasible: bad synchronization ordering\n");
- if (promises_expired())
- DEBUG("Infeasible: promises expired\n");
- }
- return mo_graph->checkForCycles() || priv->failed_promise ||
- priv->too_many_reads || priv->bad_synchronization ||
+ return mo_graph->checkForCycles() ||
+ priv->failed_promise ||
+ priv->too_many_reads ||
+ priv->bad_synchronization ||
promises_expired();
}
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++) {
+ for (; count < params.maxreads; rit++, count++) {
if (rit == list->rend())
return;
ModelAction *act = *rit;
if (write == rf)
continue;
- /* Test to see whether this is a feasible write to read from*/
+ /* Test to see whether this is a feasible write to read from */
mo_graph->startChanges();
r_modification_order(curr, write);
bool feasiblereadfrom = !is_infeasible();
bool feasiblewrite = true;
//new we need to see if this write works for everyone
- for (int loop = count; loop>0; loop--,rit++) {
+ 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++) {
+ 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;
* read.
*
* Basic idea is the following: Go through each other thread and find
- * the lastest action that happened before our read. Two cases:
+ * 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.
* 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 action that curr reads from. Must be a write.
+ * @param rf The ModelAction or Promise that curr reads from. Must be a write.
* @return True if modification order edges were added; false otherwise
*/
-bool ModelChecker::r_modification_order(ModelAction *curr, const ModelAction *rf)
+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;
for (rit = list->rbegin(); rit != list->rend(); rit++) {
ModelAction *act = *rit;
- if (act->is_write() && act != rf && act != curr) {
+ 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) {
*/
if (act->happens_before(curr) && act != curr) {
if (act->is_write()) {
- if (rf != act) {
+ if (!act->equals(rf)) {
mo_graph->addEdge(act, rf);
added = true;
}
if (prevreadfrom == NULL)
continue;
- if (rf != prevreadfrom) {
+ if (!prevreadfrom->equals(rf)) {
mo_graph->addEdge(prevreadfrom, rf);
added = true;
}
/* Include at most one act per-thread that "happens before" curr */
if (lastact != NULL) {
- if (lastact== curr) {
+ if (lastact == curr) {
//Case 1: The resolved read is a RMW, and we need to make sure
//that the write portion of the RMW mod order after rf
*/
if (thin_air_constraint_may_allow(curr, act)) {
- if (!is_infeasible() ||
- (curr->is_rmw() && act->is_rmw() && curr->get_reads_from() == act->get_reads_from() && !is_infeasible_ignoreRMW())) {
- struct PendingFutureValue pfv = {curr,act};
- futurevalues->push_back(pfv);
- }
+ 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);
}
}
}
for (rit = list->rbegin(); rit != list->rend(); rit++) {
ModelAction *act = *rit;
- if (!reader->happens_before(act))
+ /* Don't disallow due to act == reader */
+ if (!reader->happens_before(act) || reader == act)
break;
else if (act->is_write())
write_after_read = act;
- else if (act->is_read() && act->get_reads_from() != NULL && act != reader) {
+ else if (act->is_read() && act->get_reads_from() != NULL)
write_after_read = act->get_reads_from();
- }
}
if (write_after_read && write_after_read != writer && mo_graph->checkReachable(write_after_read, writer))
bool ModelChecker::resolve_promises(ModelAction *write)
{
bool resolved = false;
- std::vector< thread_id_t, ModelAlloc<thread_id_t> > threads_to_check;
+ std::vector< ModelAction *, ModelAlloc<ModelAction *> > actions_to_check;
for (unsigned int i = 0, promise_index = 0; promise_index < promises->size(); i++) {
Promise *promise = (*promises)[promise_index];
post_r_modification_order(read, write);
//Make sure the promise's value matches the write's value
ASSERT(promise->get_value() == write->get_value());
- delete(promise);
+ delete promise;
promises->erase(promises->begin() + promise_index);
- threads_to_check.push_back(read->get_tid());
+ actions_to_check.push_back(read);
resolved = true;
} else
//Check whether reading these writes has made threads unable to
//resolve promises
- for (unsigned int i = 0; i < threads_to_check.size(); i++)
- mo_check_promises(threads_to_check[i], write);
+ for (unsigned int i = 0; i < actions_to_check.size(); i++) {
+ ModelAction *read=actions_to_check[i];
+ mo_check_promises(read->get_tid(), write, read);
+ }
return resolved;
}
const ModelAction *act = promise->get_action();
if ((old_cv == NULL || !old_cv->synchronized_since(act)) &&
merge_cv->synchronized_since(act)) {
- if (promise->increment_threads(tid)) {
+ if (promise->eliminate_thread(tid)) {
//Promise has failed
priv->failed_promise = true;
return;
}
}
-void ModelChecker::check_promises_thread_disabled() {
+void ModelChecker::check_promises_thread_disabled()
+{
for (unsigned int i = 0; i < promises->size(); i++) {
Promise *promise = (*promises)[i];
- if (promise->check_promise()) {
+ if (promise->has_failed()) {
priv->failed_promise = true;
return;
}
}
}
-/** Checks promises in response to addition to modification order for threads.
+/**
+ * @brief 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
- * pthread that is sequenced after pread or the value read by the
- * first read to the same lcoation as pread by pthread that is
- * sequenced after pread..
+ * pthread that is sequenced after pread or the write read by the
+ * first read to the same location as pread by pthread that is
+ * sequenced after pread.
*
- * 1. If tid=pthread, then we check what other threads are reachable
- * through the mode order starting with pwrite. Those threads cannot
+ * 1. If tid=pthread, then we check what other threads are reachable
+ * through the mod order starting with pwrite. Those threads cannot
* perform a write that will resolve the promise due to modification
* order constraints.
*
* cannot perform a future write that will resolve the promise due to
* modificatin order constraints.
*
- * @param tid The thread that either read from the model action
- * write, or actually did the model action write.
+ * @param tid The thread that either read from the model action write, or
+ * actually did the model action write.
*
- * @param write The ModelAction representing the relevant write.
+ * @param write The ModelAction representing the relevant write.
+ * @param read The ModelAction that reads a promised write, or NULL otherwise.
*/
-void ModelChecker::mo_check_promises(thread_id_t tid, const ModelAction *write)
+void ModelChecker::mo_check_promises(thread_id_t tid, const ModelAction *write, const ModelAction *read)
{
void *location = write->get_location();
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 )
+ // Is this promise on the same location?
+ if (act->get_location() != location)
continue;
- //same thread as the promise
- if ( act->get_tid() == tid ) {
+ // same thread as the promise
+ if (act->get_tid() == tid) {
+ // make sure that the reader of this write happens after the promise
+ if ((read == NULL) || (promise->get_action()->happens_before(read))) {
+ // do we have a pwrite for the promise, if not, set it
+ if (promise->get_write() == NULL) {
+ promise->set_write(write);
+ // The pwrite cannot happen before the promise
+ if (write->happens_before(act) && (write != act)) {
+ priv->failed_promise = true;
+ return;
+ }
+ }
- //do we have a pwrite for the promise, if not, set it
- if (promise->get_write() == NULL ) {
- promise->set_write(write);
- //The pwrite cannot happen before the promise
- if (write->happens_before(act) && (write != act)) {
+ if (mo_graph->checkPromise(write, promise)) {
priv->failed_promise = true;
return;
}
}
- if (mo_graph->checkPromise(write, promise)) {
- priv->failed_promise = true;
- return;
- }
}
- //Don't do any lookups twice for the same thread
- if (promise->has_sync_thread(tid))
+ // Don't do any lookups twice for the same thread
+ if (!promise->thread_is_available(tid))
continue;
- if (promise->get_write()&&mo_graph->checkReachable(promise->get_write(), write)) {
- if (promise->increment_threads(tid)) {
+ if (promise->get_write() && mo_graph->checkReachable(promise->get_write(), write)) {
+ if (promise->eliminate_thread(tid)) {
priv->failed_promise = true;
return;
}
else if (curr->get_sleep_flag() && !curr->is_seqcst() && !sleep_can_read_from(curr, act))
allow_read = false;
- if (allow_read) {
- DEBUG("Adding action to may_read_from:\n");
- if (DBG_ENABLED()) {
- act->print();
- curr->print();
- }
+ if (allow_read)
curr->get_node()->add_read_from(act);
- }
/* Include at most one act per-thread that "happens before" curr */
if (act->happens_before(curr))
return act;
}
-static void print_list(action_list_t *list, int exec_num = -1)
+static void print_list(action_list_t *list)
{
action_list_t::iterator it;
model_print("---------------------------------------------------------------------\n");
- if (exec_num >= 0)
- model_print("Execution %d:\n", exec_num);
unsigned int hash = 0;
void ModelChecker::dumpGraph(char *filename) const
{
char buffer[200];
- sprintf(buffer, "%s.dot",filename);
+ sprintf(buffer, "%s.dot", filename);
FILE *file = fopen(buffer, "w");
- fprintf(file, "digraph %s {\n",filename);
+ fprintf(file, "digraph %s {\n", filename);
mo_graph->dumpNodes(file);
- ModelAction **thread_array = (ModelAction **)model_calloc(1, sizeof(ModelAction *)*get_num_threads());
+ 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()) {
- fprintf(file, "N%u [label=\"%u, T%u\"];\n", action->get_seq_number(),action->get_seq_number(), action->get_tid());
+ fprintf(file, "N%u [label=\"%u, T%u\"];\n", action->get_seq_number(), action->get_seq_number(), action->get_tid());
if (action->get_reads_from() != NULL)
fprintf(file, "N%u -> N%u[label=\"rf\", color=red];\n", action->get_seq_number(), action->get_reads_from()->get_seq_number());
}
thread_array[action->get_tid()] = action;
}
- fprintf(file,"}\n");
+ fprintf(file, "}\n");
model_free(thread_array);
fclose(file);
}
void ModelChecker::print_summary() const
{
#if SUPPORT_MOD_ORDER_DUMP
- scheduler->print();
char buffername[100];
sprintf(buffername, "exec%04u", stats.num_total);
mo_graph->dumpGraphToFile(buffername);
dumpGraph(buffername);
#endif
- if (!isfeasibleprefix())
- model_print("INFEASIBLE EXECUTION!\n");
- print_list(action_trace, stats.num_total);
+ model_print("Execution %d:", stats.num_total);
+ if (isfeasibleprefix())
+ model_print("\n");
+ else
+ print_infeasibility(" INFEASIBLE");
+ print_list(action_trace);
model_print("\n");
}
* @param act The ModelAction
* @return A Thread reference
*/
-Thread * ModelChecker::get_thread(ModelAction *act) const
+Thread * ModelChecker::get_thread(const ModelAction *act) const
{
return get_thread(act->get_tid());
}
Thread *curr_thrd = get_thread(curr);
ASSERT(curr_thrd->get_state() == THREAD_READY);
- Thread *next_thrd = check_current_action(curr);
-
- if (curr_thrd->is_blocked() || curr_thrd->is_complete())
- scheduler->remove_thread(curr_thrd);
-
- next_thrd = scheduler->next_thread(next_thrd);
+ curr = check_current_action(curr);
/* Infeasible -> don't take any more steps */
if (is_infeasible())
return false;
}
- if (params.bound != 0) {
- if (priv->used_sequence_numbers > params.bound) {
+ if (params.bound != 0)
+ if (priv->used_sequence_numbers > params.bound)
return false;
- }
- }
+
+ if (curr_thrd->is_blocked() || curr_thrd->is_complete())
+ scheduler->remove_thread(curr_thrd);
+
+ Thread *next_thrd = get_next_thread(curr);
+ next_thrd = scheduler->next_thread(next_thrd);
DEBUG("(%d, %d)\n", curr_thrd ? id_to_int(curr_thrd->get_id()) : -1,
next_thrd ? id_to_int(next_thrd->get_id()) : -1);