diff --git a/Makefile.am b/Makefile.am index bb381ff..5052c37 100644 --- a/Makefile.am +++ b/Makefile.am @@ -187,6 +187,7 @@ src_backend_libbackend_la_SOURCES = \ src/backend/serializer_error.cc \ src/backend/serializers_gatekeeper.cc \ src/backend/simulation.cc \ + src/backend/simulation_observer.cc \ src/backend/static_process.cc \ src/backend/static_request.cc \ src/backend/static_resource.cc \ @@ -233,6 +234,7 @@ pkginclude_HEADERS += \ src/backend/serializer_error.hh \ src/backend/serializers_gatekeeper.hh \ src/backend/simulation.hh \ + src/backend/simulation_observer.hh \ src/backend/sub_request.hh \ src/backend/thread.hh \ src/backend/user_interrupt_exception.hh diff --git a/glade/configure-dialog.glade b/glade/configure-dialog.glade index 5d4a7bd..39b3f5d 100644 --- a/glade/configure-dialog.glade +++ b/glade/configure-dialog.glade @@ -13,6 +13,7 @@ 300 True False + gtk-preferences True False False @@ -551,7 +552,7 @@ True - True + False 0 @@ -651,31 +652,6 @@ - - 0 - True - True - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - 0 False diff --git a/glade/main-window.glade b/glade/main-window.glade index d6b5e96..ce01c35 100644 --- a/glade/main-window.glade +++ b/glade/main-window.glade @@ -92,27 +92,6 @@ - - - True - _Simulation - True - - - - - - - True - gtk-media-play - True - - - - - - - True @@ -135,21 +114,38 @@ - + True - _Help + _Simulation True - + - + True - gtk-about + gtk-media-play True + + + + True + gtk-media-pause + True + + + + + + True + gtk-media-stop + True + + + @@ -175,6 +171,27 @@ + + + + True + _Help + True + + + + + + + True + gtk-about + True + + + + + + 0 diff --git a/src/backend/concrete_simulation.cc b/src/backend/concrete_simulation.cc index de78b49..e653639 100644 --- a/src/backend/concrete_simulation.cc +++ b/src/backend/concrete_simulation.cc @@ -19,6 +19,7 @@ // 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 @@ -27,6 +28,11 @@ #include "smartp.tcc" +#include +#include +#include +#include + using namespace std; using namespace sgpem; using namespace memory; @@ -34,7 +40,10 @@ using Glib::usleep; ConcreteSimulation::ConcreteSimulation() : _state(state_stopped), _mode(true), _timer_interval(1000), _policy(NULL) -{} +{ + _notify = false; + _front = 0; +} void ConcreteSimulation::set_timer(unsigned int t) @@ -60,6 +69,37 @@ ConcreteSimulation::get_mode() const return _mode; } +void +ConcreteSimulation::jump_to(History::position p) +{ + + switch (_state) + { + case state_running: + pause(); + break; + case state_stopped: + _history.reset(true); + _front = 0; + break; + default: + ; + } + + pause(); + + bool yet_to_finish = true; + while (yet_to_finish && p > _front) + yet_to_finish = step(); + + if (!yet_to_finish) + stop(); + _history.get_size() << std::endl; + _front = p < _front ? p : _front; + notify_change(); +} + + void ConcreteSimulation::pause() { @@ -81,6 +121,7 @@ ConcreteSimulation::run() throw(UserInterruptException, NullPolicyException, Mal return; case state_stopped: _history.reset(true); + _front = 0; break; default: ; @@ -102,8 +143,12 @@ ConcreteSimulation::run() throw(UserInterruptException, NullPolicyException, Mal try { //step forward - bool yet_to_finish = Scheduler::get_instance().step_forward(_history, *get_policy()); + bool yet_to_finish = true; + if (_front == get_history().get_size() - 1) + yet_to_finish = Scheduler::get_instance().step_forward(_history, *get_policy()); if (!yet_to_finish) stop(); + _front++; + notify_change(); //sleep Glib::usleep(_timer_interval*1000); @@ -128,7 +173,11 @@ ConcreteSimulation::run() throw(UserInterruptException, NullPolicyException, Mal { assert(get_policy() != NULL); //step forward - bool yet_to_finish = Scheduler::get_instance().step_forward(_history, *get_policy()); + bool yet_to_finish = true; + if (_front == get_history().get_size() - 1) + yet_to_finish = Scheduler::get_instance().step_forward(_history, *get_policy()); + _front++; + notify_change(); if (yet_to_finish) pause(); else @@ -142,6 +191,34 @@ ConcreteSimulation::run() throw(UserInterruptException, NullPolicyException, Mal } } +bool +ConcreteSimulation::step() + throw(UserInterruptException, NullPolicyException, MalformedPolicyException) +{ + if (get_policy() == NULL) + { + stop(); + throw NullPolicyException("no policy selected"); + } + + try + { + assert(get_policy() != NULL); + //step forward + bool yet_to_finish = true; + if (_front == get_history().get_size() - 1) + yet_to_finish = Scheduler::get_instance().step_forward(_history, *get_policy()); + _front++; + return yet_to_finish; + } + catch (const CPUPolicyException& e) + { + stop(); + throw; + } +} + + Simulation::state ConcreteSimulation::get_state() const { @@ -154,6 +231,13 @@ ConcreteSimulation::get_history() return _history; } +const ConcreteHistory& +ConcreteSimulation::get_history() const +{ + return _history; +} + + void ConcreteSimulation::set_policy(CPUPolicy* p) throw(CPUPolicyException) { diff --git a/src/backend/concrete_simulation.hh b/src/backend/concrete_simulation.hh index 40c0ec9..b563a74 100644 --- a/src/backend/concrete_simulation.hh +++ b/src/backend/concrete_simulation.hh @@ -21,9 +21,16 @@ #ifndef CONCRETE_SIMULATION_HH #define CONCRETE_SIMULATION_HH 1 +#include "config.h" + #include "simulation.hh" #include "concrete_history.hh" +#include +#include +#include +#include + namespace sgpem { class ConcreteSimulation; @@ -37,8 +44,12 @@ namespace sgpem void pause(); + void jump_to(History::position p); + void stop(); + bool step() throw(UserInterruptException, NullPolicyException, MalformedPolicyException); + void set_timer(const unsigned int); int get_timer() const; @@ -56,8 +67,11 @@ namespace sgpem ConcreteHistory& get_history(); + const ConcreteHistory& get_history() const; + CPUPolicy* get_policy(); + private: state _state; bool _mode; diff --git a/src/backend/simulation.cc b/src/backend/simulation.cc index cf7a0c7..5e2faa3 100644 --- a/src/backend/simulation.cc +++ b/src/backend/simulation.cc @@ -18,11 +18,18 @@ // along with SGPEMv2; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +#include "config.h" + #include "simulation.hh" +#include "simulation_observer.hh" #include "concrete_simulation.hh" +#include +#include + // Do not include in header file: #include "singleton.tcc" + using namespace sgpem; // Explicit template instantiation to allow to export symbols from the DSO. @@ -37,3 +44,47 @@ Simulation::get_instance() { return Singleton::get_instance(); } + +void +Simulation::attach(SimulationObserver& observer) +{ + _observers.push_back(&observer); +} + + +void +Simulation::detach(const SimulationObserver& observer) +{ + _observers.erase(std::find(_observers.begin(), + _observers.end(), + &observer)); +} + +unsigned int Simulation::get_front() const +{ + return _front; +} + +void +Simulation::notify_change() +{ + //if (!_notify) return; // what's the purpose of this? + + for (RegisteredObservers::iterator it = _observers.begin(); + it != _observers.end(); it++) + (*it)->update(*this); +} + + +bool +Simulation::set_notify_enabled(bool enabled) +{ + bool old_value = _notify; + _notify = enabled; + + // Force notify if we re-enable it + if (old_value == false && _notify == true) + notify_change(); + + return old_value; +} diff --git a/src/backend/simulation.hh b/src/backend/simulation.hh index e7c2813..0b9dfdb 100644 --- a/src/backend/simulation.hh +++ b/src/backend/simulation.hh @@ -25,15 +25,17 @@ namespace sgpem { class ConcreteSimulation; class CPUPolicy; - class History; + class SimulationObserver; } #include "config.h" - +#include "history.hh" #include "singleton.hh" #include "user_interrupt_exception.hh" #include "null_policy_exception.hh" #include "malformed_policy_exception.hh" +#include +#include #include namespace sgpem @@ -97,6 +99,17 @@ namespace sgpem */ virtual void stop() = 0; + + + /** + \brief Jumps the simulation to the specified instant + + Pauses the simulation and jumps to the specified instant + */ + virtual void jump_to(History::position p) = 0; + + + /** \brief Setter for the attribute timer_interval. @@ -142,12 +155,44 @@ namespace sgpem virtual History& get_history() = 0; + virtual const History& get_history() const = 0; + + virtual unsigned int get_front() const; + /** * Small kludge to avoid the need for declaration of ConcreteSimulation * by the calling code of Simulation::get_instance() */ static Simulation& get_instance(); - }; + + + + virtual void attach(SimulationObserver& observer); + virtual void detach(const SimulationObserver& observer); + + /** \brief Enable/disable notifications to registered observers + * + * This is quite useful to disable momentarily notification while you + * do a bunch of insertions and/or deletions in one go, in order to + * speed up things. + * + * \return The old value + */ + virtual bool set_notify_enabled(bool enabled = true); + + protected: + typedef std::vector RegisteredObservers; + RegisteredObservers _observers; + + // since no constructor is available, these fields must be defined in concrete subclasses. + bool _notify; + History::position _front; + + virtual void notify_change(); + + private: + + }; } diff --git a/src/text_simulation.cc b/src/text_simulation.cc index 44e0e36..1f95aa3 100644 --- a/src/text_simulation.cc +++ b/src/text_simulation.cc @@ -23,6 +23,7 @@ #include "backend/cpu_policy_manager.hh" #include "backend/policy_parameters.hh" #include "backend/history.hh" +#include "backend/simulation.hh" #include "backend/serializers_gatekeeper.hh" #include "backend/serializer.hh" #include "backend/static_process.hh" @@ -31,6 +32,7 @@ #include "backend/static_request.hh" #include "backend/static_sub_request.hh" #include "backend/concrete_history.hh" +#include "backend/concrete_simulation.hh" #include "text_simulation.hh" @@ -356,7 +358,7 @@ TextSimulation::on_run(const Tokens& arguments) check_arguments_num(arguments, 0); // Listen for updates only during scheduling - Simulation::get_instance().get_history().attach(*this); + Simulation::get_instance().attach(*this); try { @@ -393,7 +395,7 @@ TextSimulation::on_run(const Tokens& arguments) p_stderr(_("\nSimulation is now stopped\n")); } - Simulation::get_instance().get_history().detach(*this); + Simulation::get_instance().detach(*this); } void @@ -404,6 +406,82 @@ TextSimulation::on_pause(const Tokens& arguments) Simulation::get_instance().pause(); } + +void +TextSimulation::on_jumpto(const Tokens& arguments) +{ + if (!check_arguments_num(arguments, 1)) + return; + + // Listen for updates only during scheduling + + ustring _position = arguments[0]; + + History::position p; + + try + { + int pos = string_to(_position) + 1; + if (pos < 0) + { + p_stderr(_("ERROR: provided instant is out of range.\n")); + return; + } + p = static_cast(pos); + } + catch (domain_error e) + { + p_stderr(_("ERROR: provided instant is not a valid integer\n")); + return; + } + catch (out_of_range e) + { + p_stderr(_("ERROR: the instant is not within range.\n")); // does this make sense? + return; + } + + Simulation::get_instance().attach(*this); + + try + { + Simulation::get_instance().jump_to(p); + } + catch (const UserInterruptException& e) + { + p_stderr(_("ERROR: ")); + p_stderr(e.what()); + p_stderr(_("\nSimulation is now stopped\n")); + } + catch (const MalformedPolicyException& e) + { + p_stderr(_("ERROR: ")); + p_stderr(e.what()); + p_stderr(_("\nSimulation is now stopped, and " + "the current policy will be deactivated\n")); + try + { + Simulation::get_instance().set_policy(NULL); + } + catch(const CPUPolicyException& f) + { + // should never happen + p_stderr(_("FATAL ERROR: unable to deactivate the policy: ")); + p_stderr(f.what()); + abort(); + } + } + catch (const NullPolicyException& e) + { + p_stderr(_("ERROR: ")); + p_stderr(e.what()); + p_stderr(_("\nSimulation is now stopped\n")); + } + + Simulation::get_instance().detach(*this); +} + + + void TextSimulation::on_stop(const Tokens& arguments) { @@ -524,6 +602,8 @@ TextSimulation::on_help(const Tokens& arguments) else if (command == "PAUSE") p_stdout(_("-- PAUSE COMMAND --\nPauses the simulation. The next call to RUN will " "continue it.\n")); + else if (command == "JUMPTO") + p_stdout(_("-- JUMPTO COMMAND --\nPauses the simulation and jumps to the specified instant.\n")); else if (command == "CONFIGURE-CPU-POLICY") p_stdout(_("-- CONFIGURE-CPU-POLICY COMMAND --\nConfigure parameters exposed by " "the cpu policy.\n\nThis is currently the only way to control the behaviour of " @@ -1458,6 +1538,7 @@ TextSimulation::parse_command(TextSimulation& sim, const ustring& str) command_handlers["RUN"] = &TextSimulation::on_run; command_handlers["STOP"] = &TextSimulation::on_stop; command_handlers["PAUSE"] = &TextSimulation::on_pause; + command_handlers["JUMPTO"] = &TextSimulation::on_jumpto; command_handlers["CONFIGURE-CPU-POLICY"] = &TextSimulation::on_configure_cpu_policy; command_handlers["HELP"] = &TextSimulation::on_help; command_handlers["GET"] = &TextSimulation::on_get; @@ -1553,7 +1634,7 @@ operator<<(ostream& os, Request::state state) } void -TextSimulation::update(const History& changed_history) +TextSimulation::update(const Simulation& changed_simulation) { ostringstream oss; int printed_instant; @@ -1561,10 +1642,10 @@ TextSimulation::update(const History& changed_history) // Print header for each instant: - if (changed_history.get_size() > 1) - printed_instant = static_cast(changed_history.get_size()) - 2; + if (changed_simulation.get_front() > 1) + printed_instant = static_cast(changed_simulation.get_front()) - 1; else - printed_instant = -1; + printed_instant = 0; oss << endl << ">>>> " << printed_instant; @@ -1572,7 +1653,7 @@ TextSimulation::update(const History& changed_history) // Print ready queue oss << endl << _("READY QUEUE: { "); - const Environment& env = changed_history.get_last_environment(); + const Environment& env = changed_simulation.get_history().get_environment_at(changed_simulation.get_front()); const ReadyQueue& q = env.get_sorted_queue(); for (unsigned int i = 0; i < q.size(); ++i) diff --git a/src/text_simulation.hh b/src/text_simulation.hh index a76f315..4472102 100644 --- a/src/text_simulation.hh +++ b/src/text_simulation.hh @@ -28,7 +28,7 @@ #include "templates/smartp.hh" //#include "backend/policy_parameters.hh" #include "backend/string_utils.hh" -#include "backend/history_observer.hh" +#include "backend/simulation_observer.hh" #include "smartp.hh" @@ -53,7 +53,7 @@ namespace sgpem A command-based interface is used, so methods of the base class can be called with a proper command string obtained from the input device(s). */ - class SG_DLLEXPORT TextSimulation : public HistoryObserver + class SG_DLLEXPORT TextSimulation : public SimulationObserver { public: TextSimulation(); @@ -71,7 +71,7 @@ namespace sgpem Prints the actual state of the simulation, with emphasis on the current status of the scheduling process (ready queue and running process). */ - virtual void update(const History& changed_history); + virtual void update(const Simulation& changed_simulation); bool check_arguments_num(const Tokens& arguments, unsigned int num); bool unsaved_ask_confirm() const; @@ -81,6 +81,7 @@ namespace sgpem void get_parameter(CommandParameter& parameter); void on_run(const Tokens& arguments); void on_pause(const Tokens& arguments); + void on_jumpto(const Tokens& arguments); void on_stop(const Tokens& arguments); void on_configure_cpu_policy(const Tokens& arguments); void on_help(const Tokens& arguments);