#include <algorithm>
#include <mutex>
#include <new>
+#include <stdarg.h>
#include "model.h"
#include "action.h"
DEBUG("+++ Resetting to initial state +++\n");
node_stack->reset_execution();
- /* Print all model-checker output before rollback */
- fflush(model_out);
-
/**
* FIXME: if we utilize partial rollback, we will need to free only
* those pending actions which were NOT pending before the rollback
* @param msg Descriptive message for the bug (do not include newline char)
* @return True if bug is immediately-feasible
*/
-bool ModelChecker::assert_bug(const char *msg)
+bool ModelChecker::assert_bug(const char *msg, ...)
{
- priv->bugs.push_back(new bug_message(msg));
+ char str[800];
+
+ va_list ap;
+ va_start(ap, msg);
+ vsnprintf(str, sizeof(str), msg, ap);
+ va_end(ap);
+
+ priv->bugs.push_back(new bug_message(str));
if (isfeasibleprefix()) {
set_assert();
Node *node = prev->get_node()->get_parent();
+ /* See Dynamic Partial Order Reduction (addendum), POPL '05 */
int low_tid, high_tid;
if (node->enabled_status(t->get_id()) == THREAD_ENABLED) {
low_tid = id_to_int(act->get_tid());
if (i >= node->get_num_threads())
break;
+ /* See Dynamic Partial Order Reduction (addendum), POPL '05 */
/* Don't backtrack into a point where the thread is disabled or sleeping. */
if (node->enabled_status(tid) != THREAD_ENABLED)
continue;
{
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_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);
Thread *curr_thrd = get_thread(curr);
ASSERT(curr_thrd->get_state() == THREAD_READY);
+ ASSERT(check_action_enabled(curr)); /* May have side effects? */
curr = check_current_action(curr);
-
- /* Infeasible -> don't take any more steps */
- if (is_infeasible())
- return NULL;
- else if (isfeasibleprefix() && have_bug_reports()) {
- set_assert();
- return NULL;
- }
-
- if (params.bound != 0 && priv->used_sequence_numbers > params.bound)
- return NULL;
+ ASSERT(curr);
if (curr_thrd->is_blocked() || curr_thrd->is_complete())
scheduler->remove_thread(curr_thrd);
- Thread *next_thrd = NULL;
- if (curr)
- next_thrd = action_select_next_thread(curr);
- if (!next_thrd)
- next_thrd = get_next_thread();
-
- DEBUG("(%d, %d)\n", curr_thrd ? id_to_int(curr_thrd->get_id()) : -1,
- next_thrd ? id_to_int(next_thrd->get_id()) : -1);
-
- return next_thrd;
+ return action_select_next_thread(curr);
}
/** Wrapper to run the user's main function, with appropriate arguments */
user_main(model->params.argc, model->params.argv);
}
+bool ModelChecker::should_terminate_execution()
+{
+ /* Infeasible -> don't take any more steps */
+ if (is_infeasible())
+ return true;
+ else if (isfeasibleprefix() && have_bug_reports()) {
+ set_assert();
+ return true;
+ }
+
+ if (params.bound != 0 && priv->used_sequence_numbers > params.bound)
+ return true;
+ return false;
+}
+
/** @brief Run ModelChecker for the user program */
void ModelChecker::run()
{
if (!thr->is_model_thread() && !thr->is_complete() && !thr->get_pending()) {
switch_from_master(thr);
if (thr->is_waiting_on(thr))
- assert_bug("Deadlock detected");
+ assert_bug("Deadlock detected (thread %u)", i);
+ }
+ }
+
+ /* Don't schedule threads which should be disabled */
+ for (unsigned int i = 0; i < get_num_threads(); i++) {
+ Thread *th = get_thread(int_to_id(i));
+ ModelAction *act = th->get_pending();
+ if (act && is_enabled(th) && !check_action_enabled(act)) {
+ scheduler->sleep(th);
}
}
if (has_asserted())
break;
+ if (!t)
+ t = get_next_thread();
+ if (!t || t->is_model_thread())
+ break;
+
/* Consume the next action for a Thread */
ModelAction *curr = t->get_pending();
t->set_pending(NULL);
t = take_step(curr);
- } while (t && !t->is_model_thread());
+ } while (!should_terminate_execution());
/*
* Launch end-of-execution release sequence fixups only when