X-Git-Url: http://plrg.eecs.uci.edu/git/?p=c11tester.git;a=blobdiff_plain;f=model.cc;h=ea8f268ff270fa8d59674570103699c1eb36eb03;hp=0493e7e2039914988dea1172cf84b5a169132a51;hb=edf082882ea7a2d27d3a3322a84e42b040f186a4;hpb=6b49a0fc2e4919c2cdb233907219a55017eb265b diff --git a/model.cc b/model.cc index 0493e7e2..ea8f268f 100644 --- a/model.cc +++ b/model.cc @@ -344,6 +344,125 @@ uint64_t ModelChecker::switch_to_master(ModelAction *act) return old->get_return_value(); } +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(); + if (thr != nullptr) { + scheduler->set_current_thread(thr); + if (Thread::swap(old, thr) < 0) { + perror("swap threads"); + exit(EXIT_FAILURE); + } + } else + handleChosenThread(old); +} + +Thread* ModelChecker::getNextThread() +{ + Thread *nextThread = nullptr; + for (unsigned int i = curr_thread_num; i < get_num_threads(); i++) { + thread_id_t tid = int_to_id(i); + Thread *thr = get_thread(tid); + + if (!thr->is_complete() && !thr->get_pending()) { + curr_thread_num = i; + nextThread = thr; + break; + } + ModelAction *act = thr->get_pending(); + + if (act && execution->is_enabled(thr) && !execution->check_action_enabled(act)) { + scheduler->sleep(thr); + } + + chooseThread(act, thr); + } + return nextThread; +} + +void ModelChecker::finishRunExecution(Thread *old) +{ + scheduler->set_current_thread(NULL); + if (Thread::swap(old, &system_context) < 0) { + perror("swap threads"); + exit(EXIT_FAILURE); + } +} + +void ModelChecker::finishRunExecution(ucontext_t *old) +{ + scheduler->set_current_thread(NULL); + break_execution = true; +} + +void ModelChecker::consumeAction() +{ + ModelAction *curr = chosen_thread->get_pending(); + 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) +{ + if (!thread_chosen && act && execution->is_enabled(thr) && (thr->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) { + chosen_thread = thr; + thread_chosen = true; + } + } else if (act->get_type() == THREAD_CREATE || \ + act->get_type() == PTHREAD_CREATE || \ + act->get_type() == THREAD_START || \ + act->get_type() == THREAD_FINISH) { + chosen_thread = thr; + thread_chosen = true; + } + } +} + uint64_t ModelChecker::switch_thread(ModelAction *act) { if (modellock) { @@ -365,41 +484,98 @@ uint64_t ModelChecker::switch_thread(ModelAction *act) } old->set_pending(act); - //Thread *next; - /*do { - curr_thread_num++; - thread_id_t tid = int_to_id(curr_thread_num); - next = get_thread(tid); - - } while (next->is_model_thread() || next->is_complete() || next->get_pending() && curr_thread_num < get_num_threads()); - */ - Thread *next = NULL; + + if (old->is_waiting_on(old)) + assert_bug("Deadlock detected (thread %u)", curr_thread_num); + + if (act && execution->is_enabled(old) && !execution->check_action_enabled(act)) { + scheduler->sleep(old); + } + chooseThread(act, old); + curr_thread_num++; - while (curr_thread_num < get_num_threads()) { - thread_id_t tid = int_to_id(curr_thread_num); - next = get_thread(tid); - if (!next->is_model_thread() && !next->is_complete() && !next->get_pending()) - break; - curr_thread_num++; + Thread* next = getNextThread(); + if (next != nullptr) + handleNewValidThread(old, next); + else { + old->set_state(THREAD_READY); // Just to avoid the first ASSERT in ModelExecution::take_step + handleChosenThread(old); } - if (curr_thread_num < get_num_threads()) { - scheduler->set_current_thread(next); - if (Thread::swap(old, next) < 0) { - perror("swap threads"); - exit(EXIT_FAILURE); - } - if (next->is_waiting_on(next)) - assert_bug("Deadlock detected (thread %u)", curr_thread_num); + + return old->get_return_value(); +} + +void ModelChecker::handleNewValidThread(Thread *old, Thread *next) +{ + scheduler->set_current_thread(next); + + if (Thread::swap(old, next) < 0) { + perror("swap threads"); + exit(EXIT_FAILURE); + } +} + +void ModelChecker::handleChosenThread(Thread *old) +{ + if (execution->has_asserted()) + finishRunExecution(old); + if (!chosen_thread) + chosen_thread = get_next_thread(); + if (!chosen_thread || chosen_thread->is_model_thread()) + 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()) + finishRunExecution(old); + else + continueRunExecution(old); } else { - scheduler->set_current_thread(NULL); - if (Thread::swap(old, &system_context) < 0) { - perror("swap threads"); - exit(EXIT_FAILURE); - } + /* Consume the next action for a Thread */ + consumeAction(); + + if (should_terminate_execution()) + finishRunExecution(old); + else + 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); } - return old->get_return_value(); } + static void runChecker() { model->run(); delete model; @@ -428,91 +604,19 @@ void ModelChecker::run() //Need to initial random number generator state to avoid resets on rollback char random_state[256]; initstate(423121, random_state, sizeof(random_state)); - modelclock_t checkfree = params.checkthreshold; + checkfree = params.checkthreshold; for(int exec = 0;exec < params.maxexecutions;exec++) { - Thread * t = init_thread; - + chosen_thread = init_thread; + break_execution = false; do { - /* Check whether we need to free model actions. */ - - if (params.traceminsize != 0 && - execution->get_curr_seq_num() > checkfree) { - checkfree += params.checkthreshold; - execution->collectActions(); - } - - /* - * Stash next pending action(s) for thread(s). There - * should only need to stash one thread's action--the - * thread which just took a step--plus the first step - * for any newly-created thread - */ - curr_thread_num = 0; - thread_id_t tid = int_to_id(0); - Thread *thr = get_thread(tid); - switch_from_master(thr); - /* - 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); - 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++) { - Thread *th = get_thread(int_to_id(i)); - ModelAction *act = th->get_pending(); - if (act && execution->is_enabled(th) && !execution->check_action_enabled(act)) { - scheduler->sleep(th); - } - } - - 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) { - 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) { - t = th; - break; - } - } - } - - /* Catch assertions from prior take_step or from - * between-ModelAction bugs (e.g., data races) */ - - if (execution->has_asserted()) + if (break_execution) break; - if (!t) - t = get_next_thread(); - if (!t || t->is_model_thread()) - break; - if (t->just_woken_up()) { - t->set_wakeup_state(false); - t->set_pending(NULL); - t = NULL; - continue; // Allow this thread to stash the next pending action - } - /* Consume the next action for a Thread */ - ModelAction *curr = t->get_pending(); - t->set_pending(NULL); - t = execution->take_step(curr); + 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);