#include "clockvector.h"
#include "cyclegraph.h"
#include "promise.h"
+#include "datarace.h"
#define INITIAL_THREAD_ID 0
node_stack(new NodeStack()),
next_backtrack(NULL),
mo_graph(new CycleGraph()),
- failed_promise(false)
+ failed_promise(false),
+ asserted(false)
{
}
nextThread = NULL;
next_backtrack = NULL;
failed_promise = false;
+ reset_asserted();
snapshotObject->backTrackBeforeStep(0);
}
return next;
}
-void ModelChecker::check_current_action(void)
+/**
+ * This is the heart of the model checker routine. It performs model-checking
+ * actions corresponding to a given "current action." Among other processes, it
+ * calculates reads-from relationships, updates synchronization clock vectors,
+ * forms a memory_order constraints graph, and handles replay/backtrack
+ * 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.)
+ */
+Thread * ModelChecker::check_current_action(ModelAction *curr)
{
- ModelAction *curr = this->current_action;
bool already_added = false;
- this->current_action = NULL;
- if (!curr) {
- DEBUG("trying to push NULL action...\n");
- return;
- }
+
+ ASSERT(curr);
if (curr->is_rmwc() || curr->is_rmw()) {
ModelAction *tmp = process_rmw(curr);
if (curr->get_type() == THREAD_CREATE) {
Thread *th = (Thread *)curr->get_location();
th->set_creation(curr);
+ } else if (curr->get_type() == THREAD_JOIN) {
+ Thread *wait, *join;
+ wait = get_thread(curr->get_tid());
+ join = (Thread *)curr->get_location();
+ if (!join->is_complete())
+ scheduler->wait(wait, join);
+ } else if (curr->get_type() == THREAD_FINISH) {
+ Thread *th = get_thread(curr->get_tid());
+ while (!th->wait_list_empty()) {
+ Thread *wake = th->pop_wait_list();
+ scheduler->wake(wake);
+ }
+ th->complete();
}
/* Deal with new thread */
}
} else if (curr->is_write()) {
if (w_modification_order(curr))
- updated = true;;
+ updated = true;
if (resolve_promises(curr))
updated = true;
}
if (!already_added)
add_action_to_lists(curr);
- /** @todo Is there a better interface for setting the next thread rather
- than this field/convoluted approach? Perhaps like just returning
- it or something? */
-
- /* Do not split atomic actions. */
- if (curr->is_rmwr())
- nextThread = thread_current();
- else
- nextThread = get_next_replay_thread();
-
Node *currnode = curr->get_node();
Node *parnode = currnode->get_parent();
next_backtrack = curr;
set_backtracking(curr);
+
+ /* Do not split atomic actions. */
+ if (curr->is_rmwr())
+ return thread_current();
+ else
+ return get_next_replay_thread();
+}
+
+/** @returns whether the current partial trace must be a prefix of a
+ * feasible trace. */
+
+bool ModelChecker::isfeasibleprefix() {
+ return promises->size()==0;
}
/** @returns whether the current partial trace is feasible. */
it++;
}
+ // If we resolved promises or data races, see if we have realized a data race.
+ if (checkDataRaces()) {
+ model->set_assert();
+ }
+
return updated;
}
} else
promise_index++;
}
+
return resolved;
}
* context). This switch is made with the intention of exploring a particular
* model-checking action (described by a ModelAction object). Must be called
* from a user-thread context.
- * @param act The current action that will be explored. May be NULL, although
- * there is little reason to switch to the model-checker without an action to
- * explore (note: act == NULL is sometimes used as a hack to allow a thread to
- * yield control without performing any progress; see thrd_join()).
+ * @param act The current action that will be explored. Must not be NULL.
* @return Return status from the 'swap' call (i.e., success/fail, 0/-1)
*/
int ModelChecker::switch_to_master(ModelAction *act)
bool ModelChecker::take_step() {
Thread *curr, *next;
+ if (has_asserted())
+ return false;
+
curr = thread_current();
if (curr) {
if (curr->get_state() == THREAD_READY) {
- check_current_action();
- scheduler->add_thread(curr);
- } else if (curr->get_state() == THREAD_RUNNING) {
- /* Stopped while running; i.e., completed */
- curr->complete();
+ ASSERT(current_action);
+ nextThread = check_current_action(current_action);
+ current_action = NULL;
+ if (!curr->is_blocked() && !curr->is_complete())
+ scheduler->add_thread(curr);
} else {
ASSERT(false);
}