X-Git-Url: http://plrg.eecs.uci.edu/git/?p=c11tester.git;a=blobdiff_plain;f=model.cc;h=ea8f268ff270fa8d59674570103699c1eb36eb03;hp=ac394d9a49ec9f164051c04328fe35af04e22d85;hb=edf082882ea7a2d27d3a3322a84e42b040f186a4;hpb=f820ef3caa1dc1a5bd935f901d7bc9c1f653e423 diff --git a/model.cc b/model.cc index ac394d9a..ea8f268f 100644 --- a/model.cc +++ b/model.cc @@ -344,13 +344,37 @@ uint64_t ModelChecker::switch_to_master(ModelAction *act) return old->get_return_value(); } -void ModelChecker::continueExecution(Thread *old) +void ModelChecker::continueRunExecution(Thread *old) { + + if (params.traceminsize != 0 && + execution->get_curr_seq_num() > checkfree) { + checkfree += params.checkthreshold; + execution->collectActions(); + } + + thread_chosen = false; + curr_thread_num = 1; + Thread *thr = getNextThread(); + if (thr != nullptr) { + scheduler->set_current_thread(thr); + if (Thread::swap(old, thr) < 0) { + perror("swap threads"); + exit(EXIT_FAILURE); + } + } else + handleChosenThread(old); +} + +void ModelChecker::startRunExecution(ucontext_t *old) +{ + if (params.traceminsize != 0 && execution->get_curr_seq_num() > checkfree) { checkfree += params.checkthreshold; execution->collectActions(); } + thread_chosen = false; curr_thread_num = 1; Thread *thr = getNextThread(); @@ -382,12 +406,12 @@ Thread* ModelChecker::getNextThread() scheduler->sleep(thr); } - chooseThread(act, thr); + chooseThread(act, thr); } return nextThread; } -void ModelChecker::finishExecution(Thread *old) +void ModelChecker::finishRunExecution(Thread *old) { scheduler->set_current_thread(NULL); if (Thread::swap(old, &system_context) < 0) { @@ -396,11 +420,27 @@ void ModelChecker::finishExecution(Thread *old) } } +void ModelChecker::finishRunExecution(ucontext_t *old) +{ + scheduler->set_current_thread(NULL); + break_execution = true; +} + void ModelChecker::consumeAction() { ModelAction *curr = chosen_thread->get_pending(); - chosen_thread->set_pending(NULL); - chosen_thread = execution->take_step(curr); + Thread * th = thread_current(); + if (curr->get_type() == THREAD_FINISH && th != NULL) { + // Thread finish must be consumed in the master context + scheduler->set_current_thread(NULL); + if (Thread::swap(th, &system_context) < 0) { + perror("swap threads"); + exit(EXIT_FAILURE); + } + } else { + chosen_thread->set_pending(NULL); + chosen_thread = execution->take_step(curr); + } } void ModelChecker::chooseThread(ModelAction *act, Thread *thr) @@ -448,19 +488,19 @@ uint64_t ModelChecker::switch_thread(ModelAction *act) if (old->is_waiting_on(old)) assert_bug("Deadlock detected (thread %u)", curr_thread_num); - ModelAction *act2 = old->get_pending(); - - if (act2 && execution->is_enabled(old) && !execution->check_action_enabled(act2)) { + if (act && execution->is_enabled(old) && !execution->check_action_enabled(act)) { scheduler->sleep(old); } - chooseThread(act2, old); + chooseThread(act, old); curr_thread_num++; Thread* next = getNextThread(); if (next != nullptr) handleNewValidThread(old, next); - else + else { + old->set_state(THREAD_READY); // Just to avoid the first ASSERT in ModelExecution::take_step handleChosenThread(old); + } return old->get_return_value(); } @@ -478,31 +518,64 @@ void ModelChecker::handleNewValidThread(Thread *old, Thread *next) void ModelChecker::handleChosenThread(Thread *old) { if (execution->has_asserted()) - finishExecution(old); + finishRunExecution(old); if (!chosen_thread) chosen_thread = get_next_thread(); if (!chosen_thread || chosen_thread->is_model_thread()) - finishExecution(old); + finishRunExecution(old); if (chosen_thread->just_woken_up()) { chosen_thread->set_wakeup_state(false); chosen_thread->set_pending(NULL); chosen_thread = NULL; // Allow this thread to stash the next pending action if (should_terminate_execution()) - finishExecution(old); + finishRunExecution(old); else - continueExecution(old); + continueRunExecution(old); } else { /* Consume the next action for a Thread */ consumeAction(); if (should_terminate_execution()) - finishExecution(old); + finishRunExecution(old); else - continueExecution(old); + continueRunExecution(old); } } +void ModelChecker::handleChosenThread(ucontext_t *old) +{ + if (execution->has_asserted()) { + finishRunExecution(old); + return; + } + if (!chosen_thread) + chosen_thread = get_next_thread(); + if (!chosen_thread || chosen_thread->is_model_thread()) { + finishRunExecution(old); + return; + } + if (chosen_thread->just_woken_up()) { + chosen_thread->set_wakeup_state(false); + chosen_thread->set_pending(NULL); + chosen_thread = NULL; + // Allow this thread to stash the next pending action + if (should_terminate_execution()) + finishRunExecution(old); + else + startRunExecution(old); + } else { + /* Consume the next action for a Thread */ + consumeAction(); + + if (should_terminate_execution()) + finishRunExecution(old); + else + startRunExecution(old); + } +} + + static void runChecker() { model->run(); delete model; @@ -534,16 +607,16 @@ void ModelChecker::run() checkfree = params.checkthreshold; for(int exec = 0;exec < params.maxexecutions;exec++) { chosen_thread = init_thread; - thread_chosen = false; - curr_thread_num = 1; - thread_id_t tid = int_to_id(1); - Thread *thr = get_thread(tid); - if (!thr->get_pending()) - switch_from_master(thr); - else { - consumeAction(); - switch_from_master(thr); - } + break_execution = false; + do { + if (break_execution) + break; + + thread_chosen = false; + curr_thread_num = 1; + startRunExecution(&system_context); + } while (!should_terminate_execution()); + finish_execution((exec+1) < params.maxexecutions); //restore random number generator state after rollback setstate(random_state);