// src/backend/concrete_simulation.cc - Copyright 2005, 2006, University // of Padova, dept. of Pure and Applied // Mathematics // // This file is part of SGPEMv2. // // This is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // SGPEMv2 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with SGPEMv2; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "concrete_simulation.hh" #include "simulation_observer.hh" #include "scheduler.hh" #include "cpu_policies_gatekeeper.hh" #include "resource_policies_gatekeeper.hh" #include #include "smartp.tcc" #include #include #include #include using namespace std; using namespace sgpem; using namespace memory; ConcreteSimulation::ConcreteSimulation() : Simulation(), _state(state_stopped), _mode(mode_continuous), _policy(NULL), _resource_policy(NULL) { } void ConcreteSimulation::set_mode(const mode new_mode) { _mode = new_mode; } Simulation::mode ConcreteSimulation::get_mode() const { return _mode; } void ConcreteSimulation::jump_to(History::position p) throw(UserInterruptException, NullPolicyException, MalformedPolicyException) { switch (_state) { case state_running: // pauses the simulation (see below) break; case state_stopped: _history.set_front(0); break; default: break; } // Disable momentarily updates for registered observers on // sgpem::Simulation too. // See History for an example of how to implement this. set_notify_enabled(false); pause(); // Disable updates to registered observers _history.set_notify_enabled(false); bool yet_to_finish = true; History::position increment = 0; while (yet_to_finish && p > _history.get_front() + increment) { yet_to_finish = step(); increment++; } get_history().set_front(std::min(p, _history.get_size())); if (!yet_to_finish) stop(); // Reenables updates to registered observers. // Calls _history.notify_change() on reactivation. _history.set_notify_enabled(true); // Do the same for notifications on the state // of Simulation set_notify_enabled(true); } void ConcreteSimulation::pause() { if(_state != state_paused) { _state = state_paused; notify_change(); } } void ConcreteSimulation::stop() { if(_state != state_stopped) { _state = state_stopped; notify_change(); } } void ConcreteSimulation::run() throw(UserInterruptException, NullPolicyException, MalformedPolicyException) { switch (_state) { case state_stopped: _history.set_front(0); break; default: break; } _state = state_running; //step forward bool yet_to_finish = step(); _history.set_front(_history.get_front() + 1); if (yet_to_finish) { if(_mode == mode_step_by_step) pause(); else // We remain in running state, and we notify everybody! // This is non-trivial, and we must do so since we // put the state to running inconditionally. Don't // touch this if you don't provide another way to tell // a SimulationObserver that the simulation advanced // and *yet* it is in running state! notify_change(); } else // Simulation ended stop(); } bool ConcreteSimulation::step() throw(UserInterruptException, NullPolicyException, MalformedPolicyException) { if (get_policy() == NULL) { stop(); throw NullPolicyException("no CPU policy selected"); } if (get_resource_policy() == NULL) { stop(); throw NullPolicyException("no resource policy selected"); } try { // step forward bool yet_to_finish = true; if (_history.get_front() == _history.get_size() - 1) if(!_history.is_sealed()) yet_to_finish = Scheduler::get_instance().step_forward(_history, *get_policy(), *get_resource_policy()); else yet_to_finish = false; if (!yet_to_finish) _history.seal(); // since the simulation expects to be notified // of simulation termination when reaching the last environment // and the front will be updated just out of this method, // we have to make this horrible thing if (_history.get_front() == _history.get_size() - 2 && _history.is_sealed()) yet_to_finish = false; return yet_to_finish; } catch (const CPUPolicyException& e) { stop(); throw; } } Simulation::state ConcreteSimulation::get_state() const { return _state; } ConcreteHistory& ConcreteSimulation::get_history() { return _history; } const ConcreteHistory& ConcreteSimulation::get_history() const { return _history; } void ConcreteSimulation::set_policy(CPUPolicy* p) throw(CPUPolicyException) { stop(); // NOTE: restoring of the previous policy is done here because I // couldn't think of a clean way to do it // inside activate_policy() try { CPUPoliciesGatekeeper::get_instance().activate_policy(&_history, p); _policy = p; } catch(const CPUPolicyException& e1) { try { // this is a no-op if _policy is NULL CPUPoliciesGatekeeper::get_instance().activate_policy(&_history, _policy); } catch(const CPUPolicyException& e2) { _policy = NULL; string msg = _("unable to change policy and to restore the previous: "); msg += e2.what(); throw CPUPolicyException(msg); } string msg = _("unable to change policy: "); msg+= e1.what(); throw CPUPolicyException(msg); } } CPUPolicy* ConcreteSimulation::get_policy() { return _policy; } void ConcreteSimulation::set_resource_policy(ResourcePolicy* p) { stop(); ResourcePoliciesGatekeeper::get_instance().activate_policy(&_history, p); _resource_policy = p; } ResourcePolicy* ConcreteSimulation::get_resource_policy() { return _resource_policy; }