X-Git-Url: http://plrg.eecs.uci.edu/git/?p=c11tester.git;a=blobdiff_plain;f=model.cc;h=78729bd38ac4d9da05d25527450f6668f38be997;hp=a4bba3cf38a769a0baf9246384a19390ea62175f;hb=651e9182baf50ef1e235ad7a587730b989bb44c7;hpb=7ae6e12db65b5addd144f7ab6db39874a8d0c38f diff --git a/model.cc b/model.cc index a4bba3cf..78729bd3 100644 --- a/model.cc +++ b/model.cc @@ -7,7 +7,6 @@ #include "model.h" #include "action.h" -#include "nodestack.h" #include "schedule.h" #include "snapshot-interface.h" #include "common.h" @@ -16,50 +15,66 @@ #include "output.h" #include "traceanalysis.h" #include "execution.h" +#include "history.h" #include "bugmessage.h" +#include "params.h" -ModelChecker *model; +ModelChecker *model = NULL; + +/** Wrapper to run the user's main function, with appropriate arguments */ +void user_main_wrapper(void *) +{ + user_main(model->params.argc, model->params.argv); +} /** @brief Constructor */ -ModelChecker::ModelChecker(struct model_params params) : +ModelChecker::ModelChecker() : /* Initialize default scheduler */ - params(params), + params(), restart_flag(false), - exit_flag(false), scheduler(new Scheduler()), - node_stack(new NodeStack()), - execution(new ModelExecution(this, &this->params, scheduler, node_stack)), // L: Model thread is created inside + execution(new ModelExecution(this, scheduler)), + history(new ModelHistory()), execution_number(1), - diverge(NULL), - earliest_diverge(NULL), trace_analyses(), inspect_plugin(NULL) { memset(&stats,0,sizeof(struct execution_stats)); + init_thread = new Thread(execution->get_next_id(), (thrd_t *) model_malloc(sizeof(thrd_t)), &user_main_wrapper, NULL, NULL); // L: user_main_wrapper passes the user program +#ifdef TLS + init_thread->setTLS((char *)get_tls_addr()); +#endif + execution->add_thread(init_thread); + scheduler->set_current_thread(init_thread); + execution->setParams(¶ms); + param_defaults(¶ms); + initRaceDetector(); } /** @brief Destructor */ ModelChecker::~ModelChecker() { - delete node_stack; delete scheduler; } +/** Method to set parameters */ +model_params * ModelChecker::getParams() { + return ¶ms; +} + /** * Restores user program to initial state and resets all model-checker data * structures. */ void ModelChecker::reset_to_initial_state() { - DEBUG("+++ Resetting to initial state +++\n"); - node_stack->reset_execution(); /** * FIXME: if we utilize partial rollback, we will need to free only * those pending actions which were NOT pending before the rollback * point */ - for (unsigned int i = 0; i < get_num_threads(); i++) + for (unsigned int i = 0;i < get_num_threads();i++) delete get_thread(int_to_id(i))->get_pending(); snapshot_backtrack_before(0); @@ -95,29 +110,12 @@ Thread * ModelChecker::get_current_thread() const */ Thread * ModelChecker::get_next_thread() { - thread_id_t tid; /* * Have we completed exploring the preselected path? Then let the * scheduler decide */ - return scheduler->select_next_thread(node_stack->get_head()); -} - -/** - * We need to know what the next actions of all threads in the sleep - * set will be. This method computes them and stores the actions at - * the corresponding thread object's pending action. - */ -void ModelChecker::execute_sleep_set() -{ - for (unsigned int i = 0; i < get_num_threads(); i++) { - thread_id_t tid = int_to_id(i); - Thread *thr = get_thread(tid); - if (scheduler->is_sleep_set(thr) && thr->get_pending()) { - thr->get_pending()->set_sleep_flag(); - } - } + return scheduler->select_next_thread(); } /** @@ -162,10 +160,10 @@ void ModelChecker::print_bugs() const SnapVector *bugs = execution->get_bugs(); model_print("Bug report: %zu bug%s detected\n", - bugs->size(), - bugs->size() > 1 ? "s" : ""); - for (unsigned int i = 0; i < bugs->size(); i++) - (*bugs)[i]->print(); + bugs->size(), + bugs->size() > 1 ? "s" : ""); + for (unsigned int i = 0;i < bugs->size();i++) + (*bugs)[i] -> print(); } /** @@ -176,15 +174,15 @@ void ModelChecker::print_bugs() const */ void ModelChecker::record_stats() { - stats.num_total++; + stats.num_total ++; if (!execution->isfeasibleprefix()) - stats.num_infeasible++; + stats.num_infeasible ++; else if (execution->have_bug_reports()) - stats.num_buggy_executions++; + stats.num_buggy_executions ++; else if (execution->is_complete_execution()) - stats.num_complete++; + stats.num_complete ++; else { - stats.num_redundant++; + stats.num_redundant ++; /** * @todo We can violate this ASSERT() when fairness/sleep sets @@ -203,8 +201,6 @@ void ModelChecker::print_stats() const model_print("Number of buggy executions: %d\n", stats.num_buggy_executions); model_print("Number of infeasible executions: %d\n", stats.num_infeasible); model_print("Total executions: %d\n", stats.num_total); - if (params.verbose) - model_print("Total nodes created: %d\n", node_stack->get_total_nodes()); } /** @@ -214,17 +210,10 @@ void ModelChecker::print_stats() const void ModelChecker::print_execution(bool printbugs) const { model_print("Program output from execution %d:\n", - get_execution_number()); + get_execution_number()); print_program_output(); if (params.verbose >= 3) { - model_print("\nEarliest divergence point since last feasible execution:\n"); - if (earliest_diverge) - earliest_diverge->print(); - else - model_print("(Not set)\n"); - - model_print("\n"); print_stats(); } @@ -250,17 +239,16 @@ bool ModelChecker::next_execution() DBG(); /* Is this execution a feasible execution that's worth bug-checking? */ bool complete = execution->isfeasibleprefix() && - (execution->is_complete_execution() || - execution->have_bug_reports()); + (execution->is_complete_execution() || + execution->have_bug_reports()); /* End-of-execution bug checks */ if (complete) { if (execution->is_deadlocked()) assert_bug("Deadlock detected"); - checkDataRaces(); run_trace_analyses(); - } + } record_stats(); /* Output */ @@ -274,46 +262,15 @@ bool ModelChecker::next_execution() return true; } // test code - execution_number++; + execution_number ++; reset_to_initial_state(); - node_stack->full_reset(); - diverge = NULL; return false; -/* test - if (complete) - earliest_diverge = NULL; - - if (exit_flag) - return false; - -// diverge = execution->get_next_backtrack(); - if (diverge == NULL) { - execution_number++; - reset_to_initial_state(); - model_print("Does not diverge\n"); - return false; - } - - if (DBG_ENABLED()) { - model_print("Next execution will diverge at:\n"); - diverge->print(); - } - - execution_number++; - - if (params.maxexecutions != 0 && stats.num_complete >= params.maxexecutions) - return false; - - reset_to_initial_state(); - return true; -*/ - } /** @brief Run trace analyses on complete trace */ void ModelChecker::run_trace_analyses() { - for (unsigned int i = 0; i < trace_analyses.size(); i++) - trace_analyses[i]->analyze(execution->get_action_trace()); + for (unsigned int i = 0;i < trace_analyses.size();i ++) + trace_analyses[i] -> analyze(execution->get_action_trace()); } /** @@ -362,14 +319,25 @@ void ModelChecker::switch_from_master(Thread *thread) */ uint64_t ModelChecker::switch_to_master(ModelAction *act) { + if (modellock) { + static bool fork_message_printed = false; + + if (!fork_message_printed) { + model_print("Fork handler or dead thread trying to call into model checker...\n"); + fork_message_printed = true; + } + delete act; + return 0; + } DBG(); Thread *old = thread_current(); scheduler->set_current_thread(NULL); ASSERT(!old->get_pending()); -/* W: No plugin + if (inspect_plugin != NULL) { - inspect_plugin->inspectModelAction(act); - }*/ + inspect_plugin->inspectModelAction(act); + } + old->set_pending(act); if (Thread::swap(old, &system_context) < 0) { perror("swap threads"); @@ -378,10 +346,15 @@ uint64_t ModelChecker::switch_to_master(ModelAction *act) return old->get_return_value(); } -/** Wrapper to run the user's main function, with appropriate arguments */ -void user_main_wrapper(void *) -{ - user_main(model->params.argc, model->params.argv); +static void runChecker() { + model->run(); + delete model; +} + +void ModelChecker::startChecker() { + startExecution(get_system_context(), runChecker); + snapshot_stack_init(); + snapshot_record(0); } bool ModelChecker::should_terminate_execution() @@ -389,23 +362,15 @@ bool ModelChecker::should_terminate_execution() /* Infeasible -> don't take any more steps */ if (execution->is_infeasible()) return true; - else if (execution->isfeasibleprefix() && execution->have_bug_reports()) { + else if (execution->isfeasibleprefix() && execution->have_fatal_bug_reports()) { execution->set_assert(); return true; - } - - if (execution->too_many_steps()) + } else if (execution->isFinished()) { return true; + } return false; } -/** @brief Exit ModelChecker upon returning to the run loop of the - * model checker. */ -void ModelChecker::exit_model_checker() -{ - exit_flag = true; -} - /** @brief Restart ModelChecker upon returning to the run loop of the * model checker. */ void ModelChecker::restart() @@ -416,23 +381,41 @@ void ModelChecker::restart() void ModelChecker::do_restart() { restart_flag = false; - diverge = NULL; - earliest_diverge = NULL; reset_to_initial_state(); - node_stack->full_reset(); memset(&stats,0,sizeof(struct execution_stats)); execution_number = 1; } +void ModelChecker::startMainThread() { + init_thread->set_state(THREAD_RUNNING); + scheduler->set_current_thread(init_thread); + main_thread_startup(); +} + +static bool is_nonsc_write(const ModelAction *act) { + if (act->get_type() == ATOMIC_WRITE) { + std::memory_order order = act->get_mo(); + switch(order) { + case std::memory_order_relaxed: + case std::memory_order_release: + return true; + default: + return false; + } + } + return false; +} + /** @brief Run ModelChecker for the user program */ void ModelChecker::run() { - bool has_next; - int i = 0; - do { - thrd_t user_thread; - Thread *t = new Thread(execution->get_next_id(), &user_thread, &user_main_wrapper, NULL, NULL); // L: user_main_wrapper passes the user program - execution->add_thread(t); + //Need to initial random number generator state to avoid resets on rollback + char random_state[256]; + initstate(423121, random_state, sizeof(random_state)); + + for(int exec = 0;exec < params.maxexecutions;exec++) { + Thread * t = init_thread; + do { /* * Stash next pending action(s) for thread(s). There @@ -440,19 +423,19 @@ void ModelChecker::run() * thread which just took a step--plus the first step * for any newly-created thread */ - - for (unsigned int i = 0; i < get_num_threads(); i++) { + ModelAction * pending; + for (unsigned int i = 0;i < get_num_threads();i++) { thread_id_t tid = int_to_id(i); Thread *thr = get_thread(tid); - if (!thr->is_model_thread() && !thr->is_complete() && !thr->get_pending()) { - switch_from_master(thr); // L: context swapped, and action type of thr changed. + if (!thr->is_model_thread() && !thr->is_complete() && ((!(pending=thr->get_pending())) || is_nonsc_write(pending)) ) { + switch_from_master(thr); // L: context swapped, and action type of thr changed. if (thr->is_waiting_on(thr)) 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++) { + 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 && execution->is_enabled(th) && !execution->check_action_enabled(act)) { @@ -460,33 +443,33 @@ void ModelChecker::run() } } - for (unsigned int i = 1; i < get_num_threads(); i++) { + for (unsigned int i = 1;i < get_num_threads();i++) { Thread *th = get_thread(int_to_id(i)); ModelAction *act = th->get_pending(); - if (act && execution->is_enabled(th) && (th->get_state() != THREAD_BLOCKED) ){ - if (act->is_write()){ - std::memory_order order = act->get_mo(); - if (order == std::memory_order_relaxed || \ - order == std::memory_order_release) { + if (act && execution->is_enabled(th) && (th->get_state() != THREAD_BLOCKED) ) { + if (act->is_write()) { + std::memory_order order = act->get_mo(); + if (order == std::memory_order_relaxed || \ + order == std::memory_order_release) { t = th; break; } } else if (act->get_type() == THREAD_CREATE || \ - act->get_type() == PTHREAD_CREATE || \ - act->get_type() == THREAD_START || \ - act->get_type() == THREAD_FINISH) { + act->get_type() == PTHREAD_CREATE || \ + act->get_type() == THREAD_START || \ + act->get_type() == THREAD_FINISH) { t = th; break; - } + } } } /* Catch assertions from prior take_step or from - * between-ModelAction bugs (e.g., data races) */ + * between-ModelAction bugs (e.g., data races) */ if (execution->has_asserted()) break; - if (!t) + if (!t) t = get_next_thread(); if (!t || t->is_model_thread()) break; @@ -496,17 +479,15 @@ void ModelChecker::run() t->set_pending(NULL); t = execution->take_step(curr); } while (!should_terminate_execution()); - - has_next = next_execution(); - i++; - } while (i<2); // while (has_next); - - execution->fixup_release_sequences(); + next_execution(); + //restore random number generator state after rollback + setstate(random_state); + } model_print("******* Model-checking complete: *******\n"); print_stats(); /* Have the trace analyses dump their output. */ - for (unsigned int i = 0; i < trace_analyses.size(); i++) + for (unsigned int i = 0;i < trace_analyses.size();i++) trace_analyses[i]->finish(); }