fix merge issue
[c11tester.git] / model.cc
index 6dce3682fe6971ad061d83dbc30c5cf785085b73..cfbc3b8606243e1cf558a1e7a2a48d0bd3c70967 100644 (file)
--- 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"
 #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() :
@@ -26,26 +33,30 @@ ModelChecker::ModelChecker() :
        params(),
        restart_flag(false),
        scheduler(new Scheduler()),
-       node_stack(new NodeStack()),
-       execution(new ModelExecution(this, scheduler, node_stack)),
+       execution(new ModelExecution(this, scheduler)),
+       history(new ModelHistory()),
        execution_number(1),
        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
+       execution->add_thread(init_thread);
+       scheduler->set_current_thread(init_thread);
+       execution->setParams(&params);
+       param_defaults(&params);
+       initRaceDetector();
 }
 
 /** @brief Destructor */
 ModelChecker::~ModelChecker()
 {
-       delete node_stack;
        delete scheduler;
 }
 
 /** Method to set parameters */
-void ModelChecker::setParams(struct model_params params) {
-       this->params = params;
-       execution->setParams(&params);
+model_params * ModelChecker::getParams() {
+       return &params;
 }
 
 /**
@@ -54,8 +65,6 @@ void ModelChecker::setParams(struct model_params params) {
  */
 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
@@ -103,7 +112,7 @@ Thread * ModelChecker::get_next_thread()
         * Have we completed exploring the preselected path? Then let the
         * scheduler decide
         */
-       return scheduler->select_next_thread(node_stack->get_head());
+       return scheduler->select_next_thread();
 }
 
 /**
@@ -130,6 +139,28 @@ bool ModelChecker::assert_bug(const char *msg, ...)
        return execution->assert_bug(str);
 }
 
+/**
+ * @brief Assert a data race in the executing program.
+ *
+ * Different from assert_bug, the program will not be aborted immediately
+ * upon calling this function, unless the number of data races exceeds
+ * a threshold.
+ *
+ * @param msg Descriptive message for the bug (do not include newline char)
+ * @return True if bug is immediately-feasible
+ */
+bool ModelChecker::assert_race(const char *msg, ...)
+{
+       char str[800];
+
+       va_list ap;
+       va_start(ap, msg);
+       vsnprintf(str, sizeof(str), msg, ap);
+       va_end(ap);
+
+       return execution->assert_race(str);
+}
+
 /**
  * @brief Assert a bug in the executing program, asserted by a user thread
  * @see ModelChecker::assert_bug
@@ -235,7 +266,6 @@ bool ModelChecker::next_execution()
                if (execution->is_deadlocked())
                        assert_bug("Deadlock detected");
 
-               checkDataRaces();
                run_trace_analyses();
        }
 
@@ -253,7 +283,6 @@ bool ModelChecker::next_execution()
 // test code
        execution_number ++;
        reset_to_initial_state();
-       node_stack->full_reset();
        return false;
 }
 
@@ -309,14 +338,25 @@ void ModelChecker::switch_from_master(Thread *thread)
  */
 uint64_t ModelChecker::switch_to_master(ModelAction *act)
 {
+       if (forklock) {
+               static bool fork_message_printed = false;
+
+               if (!fork_message_printed) {
+                       model_print("Fork handler 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);
-        }*/
+
+       if (inspect_plugin != NULL) {
+               inspect_plugin->inspectModelAction(act);
+       }
+
        old->set_pending(act);
        if (Thread::swap(old, &system_context) < 0) {
                perror("swap threads");
@@ -325,10 +365,13 @@ 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);
 }
 
 bool ModelChecker::should_terminate_execution()
@@ -336,7 +379,7 @@ 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;
        }
@@ -354,11 +397,30 @@ void ModelChecker::do_restart()
 {
        restart_flag = false;
        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);
+       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()
 {
@@ -366,11 +428,9 @@ void ModelChecker::run()
        char random_state[256];
        initstate(423121, random_state, sizeof(random_state));
 
-       for(int exec = 0;exec < params.maxexecutions;exec ++) {
-               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 seed random number generator, otherwise its state gets reset
+       for(int exec = 0;exec < params.maxexecutions;exec++) {
+               Thread * t = init_thread;
+
                do {
                        /*
                         * Stash next pending action(s) for thread(s). There
@@ -378,11 +438,11 @@ void ModelChecker::run()
                         * thread which just took a step--plus the first step
                         * for any newly-created thread
                         */
-
+                       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()) {
+                               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);