// src/backend/text_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 "backend/string_utils.hh" #include "backend/policies_gatekeeper.hh" #include "backend/policy_manager.hh" #include "backend/policy_parameters.hh" #include "backend/history.hh" #include "backend/static_process.hh" #include "backend/static_resource.hh" #include "backend/static_thread.hh" #include "backend/static_request.hh" #include "backend/static_sub_request.hh" #include "backend/concrete_history.hh" #include "text_simulation.hh" #include using namespace std; using namespace sgpem; using namespace memory; using Glib::Thread; using Glib::ustring; #include "smartp.tcc" namespace sgpem { //TODO move this class to another file... (?) template class CommandParameter { public: CommandParameter(const ustring& _description, const T& _low_bound, const T& _up_bound, bool _required, const T& _preset); CommandParameter(const PolicyParameters::Parameter& pparam); ustring description; T low_bound; T up_bound; bool required; T preset; T value; }; template CommandParameter::CommandParameter(const ustring& _description, const T& _low_bound, const T& _up_bound, bool _required, const T& _preset) : description(_description), low_bound(_low_bound), up_bound(_up_bound), required(_required), preset(_preset), value(_preset) { } template CommandParameter::CommandParameter(const PolicyParameters::Parameter& pparam) : description(pparam.get_name()), low_bound(pparam.get_lower_bound()), up_bound(pparam.get_upper_bound()), required(pparam.is_required()), preset(pparam.get_default()), value(pparam.get_value()) { } } TextSimulation::~TextSimulation() {} /** Adds an IO_device and creates a thread which loops the read-parse-execute process */ void TextSimulation::add_io_device(smart_ptr io) { _devices.push_back(io); //pair p(this, 0); //if (!io->is_full_duplex()) // Thread::create( sigc::bind(&TextSimulation::_io_loop, p), true); } bool TextSimulation::check_arguments_num(const Tokens& arguments, unsigned int num) { if(arguments.size() < num) { ostringstream oss; oss << _("\nERROR: this command requires at least ") << num << _(" arguments\n"); p_stderr(oss.str()); return false; } else if(arguments.size() > num) p_stderr(_("\nWARNING: some arguments will be ignored")); return true; } template void TextSimulation::show(const Container& entities) { for(unsigned int i = 0; i < entities.size(); ++i) { ostringstream oss; oss << i + 1 << ". " << entities[i]->get_name() << endl; p_stdout(oss.str()); } } // Specializations need to go explicitly inside the namespace. why? namespace sgpem { template <> void TextSimulation::show >(const vector& entities) { for(unsigned int i = 0; i < entities.size(); ++i) { ostringstream oss; oss << i + 1 << ". instant: " << entities[i]->get_instant() << endl; p_stdout(oss.str()); } } template <> void TextSimulation::show >(const vector& entities) { for(unsigned int i = 0; i < entities.size(); ++i) { ostringstream oss; oss << i + 1 << ". resource: " << entities[i]->get_resource_key() << endl; p_stdout(oss.str()); } } template <> void TextSimulation::show >(const map& entities) { typedef map::const_iterator ResourceIt; for(ResourceIt it = entities.begin(); it != entities.end(); ++it) { ostringstream oss; oss << it->first << ". " << it->second->get_name(); oss << "[" << it->second->get_places() << "]" << endl; p_stdout(oss.str()); } } } template void TextSimulation::get_parameter(CommandParameter& parameter) { bool correct = true; do { ostringstream buf; buf << "\n"; if(parameter.required) buf << "*"; buf << parameter.description << " (range: [" << parameter.low_bound << ", " << parameter.up_bound << "] current: " << parameter.value << ") : "; p_stdout(buf.str()); ustring input = readline(); T value; // FIXME semi-hack, it's a bit overkill to tokenize the string // to find if it's only composed of white spaces... // Indedeed there's a pro: by using extensively tokenize() we are more sure // it's correct ;-) if(tokenize(input).size() > 0) { try { value = string_to(input); if(value > parameter.up_bound || value < parameter.low_bound) { p_stderr(_("\nERROR: Provided value is out of range")); correct = false; } } catch(domain_error e) { p_stderr(_("\nERROR: Please provide a valid numeric value")); correct = false; } if(correct) parameter.value = value; } else if(parameter.required) { p_stderr(_("\nERROR: This is a mandatory attribute; you MUST provide a valid value!")); correct = false; } } while(!correct); } // Specializations need to go explicitly inside the namespace. why? namespace sgpem { template <> void TextSimulation::get_parameter(CommandParameter& parameter) { bool loop = true; while(loop) { ustring buf; buf = "\n"; if(parameter.required) buf += "*"; p_stdout(buf + parameter.description + " (current: \"" + parameter.value + "\") : "); buf = readline(); // FIXME semi-hack, it's a bit overkill to tokenize the string // to find if it's only composed of white spaces... // Indedeed there's a pro: by using extensively tokenize() we are more sure // it's correct ;-) Tokens tokens = tokenize(buf); if(tokens.size() == 0 && parameter.required) p_stderr(_("\nERROR: This is a mandatory atribute; you MUST provide a valid value!")); else { // FIXME should we assign the entire line here or just a token? parameter.value = buf; loop = false; } } } template <> void TextSimulation::get_parameter(CommandParameter& parameter) { bool loop = true; while(loop) { ostringstream buf; buf << "\n"; if(parameter.required) buf << "*"; buf << parameter.description << " (current: " << boolalpha << parameter.value << ") : "; p_stdout(buf.str()); ustring str = readline(); // FIXME semi-hack, it's a bit overkill to tokenize the string // to find if it's only composed of white spaces... // Indedeed there's a pro: by using extensively tokenize() we are more sure // it's correct ;-) Tokens tokens = tokenize(str); if(tokens.size() == 0 && parameter.required) p_stderr(_("\nERROR: This is a mandatory atribute; you MUST provide a valid value!")); else { try { parameter.value = string_to(str); loop = false; } catch(domain_error e) { p_stderr(_("\nERROR: Please provide a valid boolean value ('true' or 'false')")); } } } } } void TextSimulation::on_run(const Tokens& arguments) { check_arguments_num(arguments, 0); try { Simulation::get_instance().run(); } catch(UserInterruptException e) { p_stderr(_("\nERROR: ")); p_stderr(e.what()); p_stderr(_("\nSimulation is now stopped")); } } void TextSimulation::on_pause(const Tokens& arguments) { check_arguments_num(arguments, 0); Simulation::get_instance().pause(); } void TextSimulation::on_stop(const Tokens& arguments) { check_arguments_num(arguments, 0); Simulation::get_instance().stop(); } void TextSimulation::on_configure_cpu_policy(const Tokens& arguments) { check_arguments_num(arguments, 0); Policy* policy = Simulation::get_instance().get_policy(); if(policy == NULL) { p_stderr(_("\nERROR: No policy actually selected for the simulation\n")); return; } PolicyParameters& parameters = policy->get_parameters(); p_stdout(_("\nPlease provide a value for each attribute:")); p_stdout(_("\nMandatory arguments are marked with an asterisk (*)\n")); p_stdout(_("\nInteger arguments:\n")); typedef map > IntParams; typedef map > FloatParams; typedef map > StringParams; IntParams int_params = parameters.get_registered_int_parameters(); for(IntParams::iterator it = int_params.begin(); it != int_params.end();) { PolicyParameters::Parameter &p = it->second; CommandParameter cmd_p(p); get_parameter(cmd_p); parameters.set_int(p.get_name(), cmd_p.value); ++it; // ostringstream buf; // // buf << "\n"; // // if(p.is_required()) // buf << "*"; // // buf << p.get_name() << " (range: [" << p.get_lower_bound() << ", " << // p.get_upper_bound() << "] default: " << p.get_default() << ") = "; // // p_stdout(buf.str()); // // bool correct = true; // // ustring input = readline(); // // int value; // // // FIXME semi-hack, it's a bit overkill to tokenize the string // // to find if it's only composed of white spaces... // // Indedeed there's a pro: by using extensively tokenize() we are more sure // // it's correct ;-) // if(tokenize(input).size() > 0) // { // try // { // value = string_to(input); // // if(value > p.get_upper_bound() || value < p.get_lower_bound()) // { // p_stderr(_("\nERROR: Provided value is out of range")); // correct = false; // } // } // catch(domain_error e) // { // p_stderr(_("\nERROR: Please provide a valid integer value")); // correct = false; // } // // if(correct) // parameters.set_int(p.get_name(), value); // } // else if(p.is_required()) // { // p_stderr(_("\nERROR: This is a mandatory attribute; you MUST provide a valid value!")); // // correct = false; // } // // if(correct) // ++it; } p_stdout(_("\nFloating-point arguments:\n")); // NOTE this piece code is a verbatim copy of the one above. // I tried solving this issue by using templates, but to make // it work will require adding to PolicyParameters a member template // method with 2 specializations... FloatParams float_params = parameters.get_registered_float_parameters(); for(FloatParams::iterator it = float_params.begin(); it != float_params.end();) { PolicyParameters::Parameter &p = it->second; CommandParameter cmd_p(p); get_parameter(cmd_p); parameters.set_float(p.get_name(), cmd_p.value); ++it; // ostringstream buf; // // buf << "\n"; // // if(p.is_required()) // buf << "*"; // // buf << p.get_name() << " (range: [" << p.get_lower_bound() << ", " << // p.get_upper_bound() << "] default: " << p.get_default() << ") = "; // // p_stdout(buf.str()); // // bool correct = true; // // ustring input = readline(); // // float value; // // // FIXME semi-hack, it's a bit overkill to tokenize the string // // to find if it's only composed of white spaces... // // Indedeed there's a pro: by using extensively tokenize() we are more sure // // it's correct ;-) // if(tokenize(input).size() > 0) // { // try // { // value = string_to(input); // // if(value > p.get_upper_bound() || value < p.get_lower_bound()) // { // p_stderr(_("\nERROR: Provided value is out of range")); // correct = false; // } // } // catch(domain_error e) // { // p_stderr(_("\nERROR: Please provide a valid floating-point value")); // correct = false; // } // // if(correct) // parameters.set_float(p.get_name(), value); // } // else if(p.is_required()) // { // p_stderr(_("\nERROR: This is a mandatory attribute; you MUST provide a valid value!")); // // correct = false; // } // // if(correct) // ++it; } p_stdout(_("\nString arguments:\n")); StringParams string_params = parameters.get_registered_string_parameters(); for(StringParams::iterator it = string_params.begin(); it != string_params.end();) { PolicyParameters::Parameter &p = it->second; CommandParameter cmd_p(p); get_parameter(cmd_p); parameters.set_string(p.get_name(), cmd_p.value); ++it; // ustring buf; // // buf = "\n"; // // if(p.is_required()) // buf += "*"; // // p_stdout(buf + p.get_name() + " = "); // // buf = readline(); // // // FIXME semi-hack, it's a bit overkill to tokenize the string // // to find if it's only composed of white spaces... // // Indedeed there's a pro: by using extensively tokenize() we are more sure // // it's correct ;-) // Tokens tokens = tokenize(buf); // // if(tokens.size() == 0 && p.is_required()) // p_stderr(_("\nERROR: This is a mandatory atribute; you MUST provide a valid value!")); // else // { // // FIXME should we insert the entire line here or just a token? // parameters.set_string(p.get_name(), buf); // ++it; // } } } void TextSimulation::on_help(const Tokens& arguments) { ustring command; if(arguments.size() > 0) { command = arguments[0].uppercase(); // print warning if necessary check_arguments_num(arguments, 1); } if(command.size() == 0) p_stdout(_("\nAvaiable commands:\nRUN\nPAUSE\nSTOP\nQUIT\nHELP" "\nGET\nSET\nSHOW\nADD\nREMOVE\nCONFIGURE-CPU-POLICY" "\n\nHELP followed by a command shows help about it." "\n ex. HELP RUN shows help about the command RUN\n")); else if(command == "RUN") p_stdout(_("\n-- RUN COMMAND --\nStarts the simulation. It can be " "continuous or step-by-step depending on the mode configured with " "SET MODE (default=CONTINUOUS).\n\n" "The output of RUN is one or more rows each of which represents the " "state of the schedulable entities. It can be RUNNING, READY, BLOCKED, " "FUTURE or TERMINATED." "\nThe row begins with the number of the instant described by the " "following lists of states. The instant 0 represents the INITIAL STATE " "during which no process is running. The scheduler " "activity begins at instant 1. Each schedulable entity is represented by " "its name followed " "by its priority enclosed between round parenthesis.")); else if(command == "STOP") p_stdout(_("\n-- STOP COMMAND --\nStops the simulation. The next call to RUN will " "bring the simulation to the FIRST instant and start it.")); else if(command == "PAUSE") p_stdout(_("\n-- PAUSE COMMAND --\nPauses the simulation. The next call to RUN will restart it.")); else if(command == "CONFIGURE-CPU-POLICY") p_stdout(_("\nFIXME")); else if(command == "HELP") p_stdout(_("\n-- Do you really want me to explain what HELP means? --" "\n ************** YOU ARE JOKING ME !!! ************\n\n")); else if(command == "GET") p_stdout(_("\n -- GET COMMAND --\nSyntax: GET \n where " "may be simulation_tick")); else if(command == "SET") p_stdout(_("\n -- SET COMMAND --\nSyntax: SET [=] \n" "where may be simulation_tick")); else if(command == "SHOW") p_stderr(_("\nFIXME: Not implemented")); else if(command == "ADD") p_stderr(_("\nFIXME: Not implemented")); else if(command == "REMOVE") p_stderr(_("\nFIXME: Not implemented")); else if(command == "QUIT") p_stderr(_("\nFIXME: Not implemented")); else p_stderr(_("\nERROR: Sorry, no help available for this command.")); } void TextSimulation::on_quit(const Tokens& arguments) { check_arguments_num(arguments, 0); p_stdout(_("\n\n*** Thank you for using SGPEM by Sirius Cybernetics Corporation ***\n\n")); // Is this ok? Really? Oh, sure, if it we always did it in this way, it is surely a Good Thing! exit(1); } void TextSimulation::on_get(const Tokens& arguments) { if(!check_arguments_num(arguments, 1)) return; ustring attr = arguments[0].uppercase(); if(attr == "SIMULATION_TICK") { ostringstream oss; oss << "\nsimulation_tick = " << Simulation::get_instance().get_timer() << "ms" << endl; p_stdout(oss.str()); } else p_stderr(_("\nERROR: invalid attribute. Accepted are: simulation_tick\n")); } void TextSimulation::on_set(const Tokens& arguments) { // handle the optional "=' (I knew that I was buying myself a problem when I // decided to support the assigment operator!) if(arguments.size() >= 3) check_arguments_num(arguments, 3); else if(!check_arguments_num(arguments, 2)) return; ustring attr = arguments[0].uppercase(); ustring value; if(arguments[1] == "=") value = arguments[2]; else value = arguments[1]; if(attr == "SIMULATION_TICK") { try { Simulation::get_instance().set_timer(string_to(value)); } catch(domain_error e) { p_stderr(_("\nERROR: you must provide a valid integer value\n")); } } else p_stderr(_("\nERROR: invalid attribute. Accepted are: simulation_tick\n")); } void TextSimulation::on_show(const Tokens& arguments) { if(arguments.size() < 1) { //print error check_arguments_num(arguments, 1); return; } //make a local copy which we'll probably modify Tokens args = arguments; ustring entities = args[0].uppercase(); args.erase(args.begin()); typedef void (TextSimulation::*f_ptr)(const Tokens&); map entities_handlers; entities_handlers["PROCESSES"] = &TextSimulation::on_show_processes; entities_handlers["RESOURCES"] = &TextSimulation::on_show_resources; entities_handlers["THREADS"] = &TextSimulation::on_show_threads; entities_handlers["REQUESTS"] = &TextSimulation::on_show_requests; entities_handlers["SUBREQUESTS"] = &TextSimulation::on_show_subrequests; entities_handlers["CPU-POLICIES"] = &TextSimulation::on_show_cpu_policies; entities_handlers["RESOURCE-POLICIES"] = &TextSimulation::on_show_resource_policies; if(entities_handlers.find(entities) == entities_handlers.end()) p_stderr(_("\nERROR: invalid argument\n")); else (this->*(entities_handlers[entities]))(args); } void TextSimulation::on_show_processes(const Tokens& arguments) { check_arguments_num(arguments, 0); const Environment& env = Simulation::get_instance().get_history().get_environment_at(0); const Environment::Processes& processes = env.get_processes(); show(processes); } void TextSimulation::on_show_resources(const Tokens& arguments) { check_arguments_num(arguments, 0); const Environment& env = Simulation::get_instance().get_history().get_environment_at(0); const Environment::Resources& resources = env.get_resources(); show(resources); } void TextSimulation::on_show_threads(const Tokens& arguments) { if(!check_arguments_num(arguments, 1)) return; ustring process = arguments[0]; const Environment& env = Simulation::get_instance().get_history().get_environment_at(0); const Environment::Processes& processes = env.get_processes(); vector threads; try { int pid = string_to(process) - 1; threads = processes.at(pid)->get_threads(); } catch(domain_error e) { p_stderr(_("ERROR: provided process identifier is not a valid integer\n")); return; } catch(out_of_range e) { p_stderr(_("ERROR: this process identifier does not belong to an existing process\n")); return; } show(threads); } void TextSimulation::on_show_requests(const Tokens& arguments) { if(!check_arguments_num(arguments, 2)) return; ustring process = arguments[0]; ustring thread = arguments[1]; const Environment& env = Simulation::get_instance().get_history().get_environment_at(0); const Environment::Processes& processes = env.get_processes(); vector requests; try { int pid = string_to(process) - 1; int tid = string_to(thread) - 1; vector threads = processes.at(pid)->get_threads(); requests = threads.at(tid)->get_requests(); } catch(domain_error e) { p_stderr(_("ERROR: provided identifier(s) not a valid integer\n")); return; } catch(out_of_range e) { p_stderr(_("ERROR: the identifier(s) do not belong to an existing entity\n")); return; } show(requests); } void TextSimulation::on_show_subrequests(const Tokens& arguments) { if(!check_arguments_num(arguments, 3)) return; ustring process = arguments[0]; ustring thread = arguments[1]; ustring request = arguments[2]; const Environment& env = Simulation::get_instance().get_history().get_environment_at(0); const Environment::Processes& processes = env.get_processes(); vector subrequests; try { int pid = string_to(process) - 1; int tid = string_to(thread) - 1; int rid = string_to(request) - 1; vector threads = processes.at(pid)->get_threads(); vector requests = threads.at(tid)->get_requests(); subrequests = requests.at(rid)->get_subrequests(); } catch(domain_error e) { p_stderr(_("ERROR: provided identifier(s) not a valid integer\n")); return; } catch(out_of_range e) { p_stderr(_("ERROR: the identifier(s) do not belong to an existing entity\n")); return; } show(subrequests); } void TextSimulation::on_show_cpu_policies(const Tokens& arguments) { typedef vector ManagerVec; typedef vector::iterator PolicyIt; check_arguments_num(arguments, 0); PoliciesGatekeeper& gatekeeper = PoliciesGatekeeper::get_instance(); ManagerVec managers = gatekeeper.get_registered(); unsigned int index = 1; for(ManagerVec::iterator it = managers.begin(); it != managers.end(); ++it) { vector policies = (*it)->get_avail_policies(); for(PolicyIt it = policies.begin(); it != policies.end(); ++it) { ostringstream oss; oss << index << ". " << (*it)->get_name() << endl; oss << "\t" << (*it)->get_description() << endl; p_stdout(oss.str()); } ++index; } } void TextSimulation::on_show_resource_policies(const Tokens& arguments) { // Waiting for the coder to implementat resource policies // But wait a moment, the coder is me!!! p_stderr(_("\nFIXME: Not implemented\n")); } void TextSimulation::on_add(const Tokens& arguments) { if(arguments.size() < 1) { //print error check_arguments_num(arguments, 1); return; } if(Simulation::get_instance().get_state() != Simulation::state_stopped) p_stderr(_("WARNING: Simulation is not stopped, it will be automatically stopped")); //make a local copy which we'll probably modify Tokens args = arguments; ustring entity = args[0].uppercase(); args.erase(args.begin()); typedef void (TextSimulation::*f_ptr)(const Tokens&); map entity_handlers; entity_handlers["PROCESS"] = &TextSimulation::on_add_process; entity_handlers["RESOURCE"] = &TextSimulation::on_add_resource; entity_handlers["THREAD"] = &TextSimulation::on_add_thread; entity_handlers["REQUEST"] = &TextSimulation::on_add_request; entity_handlers["SUBREQUEST"] = &TextSimulation::on_add_subrequest; if(entity_handlers.find(entity) == entity_handlers.end()) p_stderr(_("\nERROR: invalid argument\n")); else (this->*(entity_handlers[entity]))(args); } void TextSimulation::on_add_process(const Tokens& arguments) { check_arguments_num(arguments, 0); CommandParameter name(_("name"), "", "", false, ""); CommandParameter arrival_time(_("arrival time"), 0, INT_MAX, false, 0); CommandParameter base_priority(_("priority"), 0, INT_MAX, false, 0); get_parameter(name); get_parameter(arrival_time); get_parameter(base_priority); History& h = Simulation::get_instance().get_history(); h.add_process(name.value, arrival_time.value, base_priority.value); } void TextSimulation::on_add_resource(const Tokens& arguments) { check_arguments_num(arguments, 0); CommandParameter name(_("name"), "", "", false, ""); CommandParameter preemptable(_("pre-emptable?"), false, false, false, false); CommandParameter places(_("places"), 0, INT_MAX, false, 1); CommandParameter availability(_("availability"), 0, INT_MAX, false, 0); get_parameter(name); get_parameter(preemptable); get_parameter(places); get_parameter(availability); History& h = Simulation::get_instance().get_history(); h.add_resource(name.value, preemptable.value, places.value, availability.value); } void TextSimulation::on_add_thread(const Tokens& arguments) { if(!check_arguments_num(arguments, 1)) return; ustring process = arguments[0]; const Environment& env = Simulation::get_instance().get_history().get_environment_at(0); const Environment::Processes& processes = env.get_processes(); Process* p; try { p = processes.at(string_to(process) - 1); } catch(domain_error e) { p_stderr(_("ERROR: provided identifier(s) not a valid integer\n")); return; } catch(out_of_range e) { p_stderr(_("ERROR: the identifier(s) do not belong to an existing entity\n")); return; } CommandParameter name(_("name"), "", "", false, ""); CommandParameter cpu_time(_("cpu time"), 0, INT_MAX, true, 0); CommandParameter arrival_time(_("arrival time"), 0, INT_MAX, false, 0); CommandParameter base_priority(_("base priority"), 0, INT_MAX, false, 0); get_parameter(name); get_parameter(cpu_time); get_parameter(arrival_time); get_parameter(base_priority); History& h = Simulation::get_instance().get_history(); h.add_thread(name.value, *p, cpu_time.value, arrival_time.value, base_priority.value); } void TextSimulation::on_add_request(const Tokens& arguments) { if(!check_arguments_num(arguments, 2)) return; ustring process = arguments[0]; ustring thread = arguments[1]; const Environment& env = Simulation::get_instance().get_history().get_environment_at(0); const Environment::Processes& processes = env.get_processes(); Thread* t; try { int pid = string_to(process) - 1; int tid = string_to(thread) - 1; vector threads = processes.at(pid)->get_threads(); t = threads.at(tid); } catch(domain_error e) { p_stderr(_("ERROR: provided identifier(s) not a valid integer\n")); return; } catch(out_of_range e) { p_stderr(_("ERROR: the identifier(s) do not belong to an existing entity\n")); return; } CommandParameter instant(_("instant"), 0, INT_MAX, true, 0); get_parameter(instant); History& h = Simulation::get_instance().get_history(); h.add_request(*t, instant.value); } void TextSimulation::on_add_subrequest(const Tokens& arguments) { if(!check_arguments_num(arguments, 3)) return; ustring process = arguments[0]; ustring thread = arguments[1]; ustring request = arguments[2]; const Environment& env = Simulation::get_instance().get_history().get_environment_at(0); const Environment::Processes& processes = env.get_processes(); Request* r; try { int pid = string_to(process) - 1; int tid = string_to(thread) - 1; int rid = string_to(request) - 1; vector threads = processes.at(pid)->get_threads(); vector requests = threads.at(tid)->get_requests(); r = requests.at(rid); } catch(domain_error e) { p_stderr(_("ERROR: provided identifier(s) not a valid integer\n")); return; } catch(out_of_range e) { p_stderr(_("ERROR: the identifier(s) do not belong to an existing entity\n")); return; } CommandParameter resource_key(_("resource key"), 0, INT_MAX, true, 0); CommandParameter duration(_("duration"), 0, INT_MAX, true, 0); History& h = Simulation::get_instance().get_history(); h.add_subrequest(*r, resource_key.value, duration.value); } void TextSimulation::on_remove(const Tokens& arguments) { if(arguments.size() < 1) { //print error check_arguments_num(arguments, 1); return; } if(Simulation::get_instance().get_state() != Simulation::state_stopped) p_stderr(_("WARNING: Simulation is not stopped, it will be automatically stopped")); //make a local copy which we'll probably modify Tokens args = arguments; ustring entity = args[0].uppercase(); args.erase(args.begin()); typedef void (TextSimulation::*f_ptr)(const Tokens&); map entity_handlers; entity_handlers["PROCESS"] = &TextSimulation::on_remove_process; entity_handlers["RESOURCE"] = &TextSimulation::on_remove_resource; entity_handlers["THREAD"] = &TextSimulation::on_remove_thread; entity_handlers["REQUEST"] = &TextSimulation::on_remove_request; entity_handlers["SUBREQUEST"] = &TextSimulation::on_remove_subrequest; if(entity_handlers.find(entity) == entity_handlers.end()) p_stderr(_("\nERROR: invalid argument\n")); else (this->*(entity_handlers[entity]))(args); } void TextSimulation::on_remove_process(const Tokens& arguments) { if(!check_arguments_num(arguments, 1)) return; ustring process = arguments[0]; const Environment& env = Simulation::get_instance().get_history().get_environment_at(0); const Environment::Processes& processes = env.get_processes(); Process* p; try { p = processes.at(string_to(process) - 1); } catch(domain_error e) { p_stderr(_("ERROR: provided identifier(s) not a valid integer\n")); return; } catch(out_of_range e) { p_stderr(_("ERROR: the identifier(s) do not belong to an existing entity\n")); return; } History& h = Simulation::get_instance().get_history(); h.remove(*p); } void TextSimulation::on_remove_resource(const Tokens& arguments) { if(!check_arguments_num(arguments, 1)) return; ustring resource = arguments[0]; const Environment& env = Simulation::get_instance().get_history().get_environment_at(0); const Environment::Processes& processes = env.get_processes(); ConcreteHistory::resource_key_t rid; try { rid = string_to(resource); } catch(domain_error e) { p_stderr(_("ERROR: provided identifier(s) not a valid integer\n")); return; } catch(out_of_range e) { p_stderr(_("ERROR: the identifier(s) do not belong to an existing entity\n")); return; } History& h = Simulation::get_instance().get_history(); h.remove(rid); } void TextSimulation::on_remove_thread(const Tokens& arguments) { if(!check_arguments_num(arguments, 2)) return; ustring process = arguments[0]; ustring thread = arguments[1]; const Environment& env = Simulation::get_instance().get_history().get_environment_at(0); const Environment::Processes& processes = env.get_processes(); Thread* t; try { int pid = string_to(process) - 1; int tid = string_to(thread) - 1; vector threads = processes.at(pid)->get_threads(); t = threads.at(tid); } catch(domain_error e) { p_stderr(_("ERROR: provided identifier(s) not a valid integer\n")); return; } catch(out_of_range e) { p_stderr(_("ERROR: the identifier(s) do not belong to an existing entity\n")); return; } History& h = Simulation::get_instance().get_history(); h.remove(*t); } void TextSimulation::on_remove_request(const Tokens& arguments) { if(!check_arguments_num(arguments, 3)) return; ustring process = arguments[0]; ustring thread = arguments[1]; ustring request = arguments[2]; const Environment& env = Simulation::get_instance().get_history().get_environment_at(0); const Environment::Processes& processes = env.get_processes(); Request* r; try { int pid = string_to(process) - 1; int tid = string_to(thread) - 1; int rid = string_to(request) - 1; vector threads = processes.at(pid)->get_threads(); vector requests = threads.at(tid)->get_requests(); r = requests.at(rid); } catch(domain_error e) { p_stderr(_("ERROR: provided identifier(s) not a valid integer\n")); return; } catch(out_of_range e) { p_stderr(_("ERROR: the identifier(s) do not belong to an existing entity\n")); return; } History& h = Simulation::get_instance().get_history(); h.remove(*r); } void TextSimulation::on_remove_subrequest(const Tokens& arguments) { if(!check_arguments_num(arguments, 4)) return; ustring process = arguments[0]; ustring thread = arguments[1]; ustring request = arguments[2]; ustring subrequest = arguments[3]; const Environment& env = Simulation::get_instance().get_history().get_environment_at(0); const Environment::Processes& processes = env.get_processes(); SubRequest* r; try { int pid = string_to(process) - 1; int tid = string_to(thread) - 1; int rid = string_to(request) - 1; int srid = string_to(subrequest) - 1; vector threads = processes.at(pid)->get_threads(); vector requests = threads.at(tid)->get_requests(); vector subrequests = requests.at(rid)->get_subrequests(); r = subrequests.at(srid); } catch(domain_error e) { p_stderr(_("ERROR: provided identifier(s) not a valid integer\n")); return; } catch(out_of_range e) { p_stderr(_("ERROR: the identifier(s) do not belong to an existing entity\n")); return; } History& h = Simulation::get_instance().get_history(); h.remove(*r); } void TextSimulation::p_stdout(const ustring& str) { cout << str; } void TextSimulation::p_stderr(const ustring& str) { cerr << str; } ustring TextSimulation::readline() { string str; getline(cin, str); return str; } void TextSimulation::parse_command(TextSimulation& sim, const ustring& str) { typedef void (TextSimulation::*f_ptr)(const Tokens&); map command_handlers; command_handlers["RUN"] = &TextSimulation::on_run; command_handlers["STOP"] = &TextSimulation::on_stop; command_handlers["PAUSE"] = &TextSimulation::on_pause; command_handlers["CONFIGURE-CPU-POLICY"] = &TextSimulation::on_configure_cpu_policy; command_handlers["HELP"] = &TextSimulation::on_help; command_handlers["GET"] = &TextSimulation::on_get; command_handlers["SET"] = &TextSimulation::on_set; command_handlers["SHOW"] = &TextSimulation::on_show; command_handlers["ADD"] = &TextSimulation::on_add; command_handlers["REMOVE"] = &TextSimulation::on_remove; command_handlers["QUIT"] = &TextSimulation::on_quit; Tokens arguments = tokenize(str); if(arguments.size() == 0) return; ustring key = arguments[0].uppercase(); if(command_handlers.find(key) == command_handlers.end()) { p_stderr(_("\nERROR: command not supported\n")); return; } arguments.erase(arguments.begin()); (sim.*(command_handlers[key]))(arguments); } // ** Please do NOT delete this code, I still use it as a reference ** //void //TextSimulation::parse_command(pair< pair, const ustring > p) //{ // // TextSimulation* obj = p.first.first; // ustring str = p.second; // //looks for the IOManager who sent the command // uint quale = 0; // for (; quale < obj->_devices.size(); quale++) // if (p.first.second == &(*obj->_devices[quale])) // break; // // if (str.length() == 0) // return; // // //CAPITALIZE alla grguments // str = str.uppercase(); // // vector arguments; // uint f = 0; // static const ustring whitespaces = " \r\b\n\t\a"; // //fills the vector with parameters // while (true) // { // f = str.find_first_of(whitespaces); // if (f > str.length()) // { // //the end of the string // arguments.push_back(str); // break; // } // else // { // //add the token // arguments.push_back(str.substr(0, f)); // //trim the initial whitespaces // str = str.substr(f + 1); // f = str.find_first_not_of(whitespaces); // str = str.substr(f); // } // } // // if (arguments.size() == 0) // return; // // bool show_help = false; // int param = 0; //check: // // if (arguments[param] == "RUN") // { // if (show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- RUN COMMAND --\nStarts the simulation. It can be continuous or step-by-step" // " depending on the mode configured with SetMode (default=continuous).\n\n" // "The output of RUN is one or more rows each of which represents the state of the " // "schedulable entities. It can be RUNNING, READY, BLOCKED, FUTURE or TERMINATED." // "\nThe row begins with the number of the instant described by the following lists of states. " // "The instant 0 represents the INITIAL STATE during which no process is running. The scheduler " // "activity begins at instant 1. Each schedulable entity is represented by its name followed " // "by its priority enclosed between round parenthesis.")); // return; // } // // try // { // obj->run(); // } // catch(UserInterruptException e) // { // obj->_devices[quale]->write_buffer(_("\nERROR: ")); // obj->_devices[quale]->write_buffer(_(e.what())); // obj->_devices[quale]->write_buffer(_("\nSimulation is now stopped")); // // } // } // else if (arguments[param] == "PAUSE") // { // if (show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- PAUSE COMMAND --\nPauses the simulation. The next call to RUN will restart it.")); // return; // } // obj->pause(); // } // else if (arguments[param] == "STOP") // { // if (show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- STOP COMMAND --\nStops the simulation. The next call to RUN will " // "bring the simulation to the FIRST instant and start it.")); // return; // } // obj->stop(); // } // else if (arguments[param] == "RESET") // { // if (show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- RESET COMMAND --\nResets the simulation jumping back to the first instant.")); // return; // } // obj->reset(); // } // else if (arguments[param] == "QUIT") // { // if (show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- QUIT COMMAND --\nExits the program.")); // return; // } // obj->_devices[quale]->write_buffer(_("\n\n*** Thank you for using SGPEM by Sirius Cybernetics Corporation ***\n\n")); // exit(1); // } // else if (arguments[param] == "HELP") // { // if (show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- Do you really want me to explain what HELP means? --" // "\n ************** YOU ARE JOKING ME !!! ************\n\n")); // exit(1); // } // if (arguments.size() == 1) // { // obj->_devices[quale]->write_buffer( "\nAvaiable commands:\nRUN\nPAUSE\nSTOP\nRESET\nQUIT\nHELP" // "\nGETMODE\nSETMODE\nSETTIMER\nGETTIMER\nJUMPTO\nGETPOLICY" // "\nSETPOLICY\nGETPOLICYATTRIBUTES" // "\n\nHELP followed by a command shows help about it." // "\n ex. HELP RUN shows help about the command RUN"); // return; // } // show_help = true; // param = 1; // goto check; // } // else if (arguments[param] == "SETMODE") // { // if (show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- SetMode COMMAND --\nPermits to change the mode of the simulation.\n\nSintax: Setmode \n\t can take values:\n" // "\n\t\tCONTINUOUS - when calling RUN the simulation will show an animation using the wait-interval set by SETTIMER\n" // "\n\t\tSTEP - when calling RUN the simulation will show only one step of the animation\n")); // return; // } // if (arguments.size() != 2) // { // obj->_devices[quale]->write_buffer(_("\nERROR: wrong number of parameters." // "\nType HELP SETMODE for the description of the sintax")); // return; // } // if (arguments[1] == "CONTINUOUS") // obj->set_mode(true); // else if (arguments[1] == "STEP") // obj->set_mode(false); // else // obj->_devices[quale]->write_buffer(_("\nERROR: the second parameter can be only CONTINUOUS or STEP")); // // } // else if (arguments[param] == "GETMODE") // { // if (show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- GetMode COMMAND --\nReturns\n\tCONTINUOUS : if the simulation is shown with an animation" // "\n\tSTEP : if if the simulation is shown step-by-step")); // return; // } // if (obj->get_mode()) // obj->_devices[quale]->write_buffer(_("\nCONTINUOUS")); // else // obj->_devices[quale]->write_buffer(_("\nSTEP")); // } // else if (arguments[param] == "SETTIMER") // { // if (show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- SetTimer COMMAND --\nPermits to change the interval between a step and the following one during a continuous animation." // "\n\nSintax: SetTimer \n\t must be an integer value > 0 and < 10000.\n")); // return; // } // if (arguments.size() != 2) // { // obj->_devices[quale]->write_buffer(_("\nERROR: wrong number of parameters." // "\nType HELP SETTIMER for the description of the sintax")); // return; // } // int num; // if (string_to_int(arguments[1], num) && num > 0 && num < 10000) // obj->set_timer(num); // else // obj->_devices[quale]->write_buffer(_( // "\nERROR: the second parameter has a wrong value." // "\nType HELP SETTIMER for the description of the sintax")); // } // else if (arguments[param] == "GETTIMER") // { // if (show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- GetTimer COMMAND --\nReturns the number of milliseconds the simulation " // "in the continuous mode waits between a step and the following one")); // return; // } // ustring ss; // int_to_string(obj->get_timer(), ss); // obj->_devices[quale]->write_buffer(ss); // } // else if (arguments[param] == "JUMPTO") // { // if (show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- JumpTo COMMAND --\nPermits to jump to a desired instant of the simulation." // " All states of the simulation before will be recalculated and printed out." // "\n\nSintax: JumpTo \n\t must be an integer value >= 0")); // return; // } // if (arguments.size() != 2) // { // obj->_devices[quale]->write_buffer(_("\nERROR: wrong number of parameters." // "\nType HELP JUMPTO for the description of the sintax")); // return; // } // int num; // if (string_to_int(arguments[1], num) && num >= 0) // obj->jump_to(num); // else // obj->_devices[quale]->write_buffer(_( // "\nERROR: the second parameter has a wrong value." // "\nType HELP JUMPTO for the description of the sintax")); // } // else if (arguments[param] == "GETPOLICY") // { // if (show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- GetPolicy COMMAND --\nReturns the name and the description of the current applied policy.")); // return; // } // obj->_devices[quale]->write_buffer(obj->get_policy()->get_description()); // } // else if(arguments[param] == "SETPOLICY") // { // if(show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- SetPolicy COMMAND --\nSelects the current applied policy." // "Syntax: SetPolicy ")); // return; // } // // // //FIXME assuming only one policy manager is present, but who cares, this // //is only temporary code... // PolicyManager* manager = PoliciesGatekeeper::get_instance().get_registered()[0]; // // vector available = manager->get_avail_policies(); // // // obj->_devices[quale]->write_buffer(arguments[1] + "\n"); // // for(vector::iterator it = available.begin(); it != available.end(); ++it) // { // if((*it)->get_name().casefold() == arguments[1].casefold()) // { // obj->stop(); // PoliciesGatekeeper::get_instance().activate_policy(&History::get_instance(), *it); // return; // } // } // // // obj->_devices[quale]->write_buffer(_( // "\nERROR: no policy found with that name." // "\nType HELP SETPOLICY for the description of the sintax")); // // } // else if(arguments[param] == "LISTPOLICIES") // { // if(show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- ListPolicies COMMAND --\nShows the name of available policies.")); // return; // } // // //FIXME assuming only one policy manager is present, but who cares, this // //is only temporary code... // PolicyManager* manager = PoliciesGatekeeper::get_instance().get_registered()[0]; // // vector available = manager->get_avail_policies(); // // for(vector::iterator it = available.begin(); it != available.end(); ++it) // { // //// Glib::ustring str; //// int_to_string((int)*it, str); //// obj->_devices[quale]->write_buffer(str + "\n"); // obj->_devices[quale]->write_buffer("\n" + (*it)->get_name()); // } // } // else if (arguments[param] == "GETPOLICYATTRIBUTES") // { // if (show_help) // { // obj->_devices[quale]->write_buffer(_( // "\n-- GetPolicyAttributes COMMAND --\nReturns the list of attributes of the current applied policy." // "\nThe description of each parameter includes:" // "\n\tthe NAME of the marameter with its type\n\tits current VALUE" // "\n\tits LOWER and UPPER bounds\n\twhether the parameter is REQUIRED")); // return; // } // // ustring temp; // // const PolicyParameters& param = obj->get_policy()->get_parameters(); // map > map_i = param.get_registered_int_parameters(); // map >::iterator i_i = map_i.begin(); // // for(; i_i != map_i.end(); i_i++) // { // obj->_devices[quale]->write_buffer("\nint\t" + i_i->second.get_name()); // int_to_string(i_i->second.get_value(), temp); // obj->_devices[quale]->write_buffer("\tvalue=" + temp); // int_to_string(i_i->second.get_lower_bound(), temp); // obj->_devices[quale]->write_buffer("\t\tlower=" + temp); // int_to_string(i_i->second.get_upper_bound(), temp); // obj->_devices[quale]->write_buffer("\t\tupper=" + temp); // if (i_i->second.is_required()) // obj->_devices[quale]->write_buffer("\t\trequired=true"); // else // obj->_devices[quale]->write_buffer("\t\trequired=false"); // } // // map > map_f = param.get_registered_float_parameters(); // map >::iterator i_f = map_f.begin(); // // for(; i_f != map_f.end(); i_f++) // { // obj->_devices[quale]->write_buffer("\nfloat\t" + i_f->second.get_name()); // float_to_string(i_f->second.get_value(), temp); // obj->_devices[quale]->write_buffer("\tvalue=" + temp); // float_to_string(i_f->second.get_lower_bound(), temp); // obj->_devices[quale]->write_buffer("\t\tlower=" + temp); // float_to_string(i_f->second.get_upper_bound(), temp); // obj->_devices[quale]->write_buffer("\t\tupper=" + temp); // if (i_f->second.is_required()) // obj->_devices[quale]->write_buffer("\t\trequired=true"); // else // obj->_devices[quale]->write_buffer("\t\trequired=false"); // } // // map > map_s = param.get_registered_string_parameters(); // map >::iterator i_s = map_s.begin(); // // for(; i_s != map_s.end(); i_s++) // { // obj->_devices[quale]->write_buffer("\nustring\t" + i_s->second.get_name()); // obj->_devices[quale]->write_buffer("\tvalue=" + i_s->second.get_value()); // if (i_s->second.is_required()) // obj->_devices[quale]->write_buffer(" required=true"); // else // obj->_devices[quale]->write_buffer(" required=false"); // } // // } // else // { // obj->_devices[quale]->write_buffer(_("\nCommand not recognized: ")); // obj->_devices[quale]->write_buffer(arguments[param]); // obj->_devices[quale]->write_buffer(_("\nTyper HELP for a list of avaiable commands.")); // return; // } //} void TextSimulation::update() { // History& h = History::get_instance(); // int when, arr; // ustring temp; // // when = h.get_current_time(); // smart_ptr ll = h.get_simulation_status_at(when); // // for (uint dev = 0; dev < _devices.size(); dev++) // { // int_to_string(when, temp); // if (when < 10) // _devices[dev]->write_buffer("\n "); // else // _devices[dev]->write_buffer("\n"); // _devices[dev]->write_buffer(temp + ") [RUNS]"); // // //insert the RUNNING ONE // smart_ptr running = h.get_scheduled_at(when); // if (running) // { // arr = running->get_schedulable()->get_arrival_time(); // int_to_string(arr, temp); // _devices[dev]->write_buffer(" " + running->get_schedulable()->get_name() + "_(" + temp + ")"); // } // // _devices[dev]->write_buffer(" --[READY]"); // //insert the READY ones // for (uint i = 0; i < ll->size(); i++) // if (ll->get_item_at(i)->get_state() == DynamicSchedulable::state_ready) // { // arr = ll->get_item_at(i)->get_schedulable()->get_arrival_time(); // int_to_string(arr, temp); // _devices[dev]->write_buffer(" " + ll->get_item_at(i)->get_schedulable()->get_name() + "_(" + temp + ")"); // } // // _devices[dev]->write_buffer(" --[BLOCKED]"); // //insert the BLOCKED ones // for (uint i = 0; i < ll->size(); i++) // if (ll->get_item_at(i)->get_state() == DynamicSchedulable::state_blocked) // { // arr = ll->get_item_at(i)->get_schedulable()->get_arrival_time(); // int_to_string(arr, temp); // _devices[dev]->write_buffer(" " + ll->get_item_at(i)->get_schedulable()->get_name() + "_(" + temp + ")"); // } // // _devices[dev]->write_buffer(" --[FUTURE]"); // //insert the FUTURE ones // for (uint i = 0; i < ll->size(); i++) // if (ll->get_item_at(i)->get_state() == DynamicSchedulable::state_future) // { // arr = ll->get_item_at(i)->get_schedulable()->get_arrival_time(); // int_to_string(arr, temp); // _devices[dev]->write_buffer(" " + ll->get_item_at(i)->get_schedulable()->get_name() + "_(" + temp + ")"); // } // // _devices[dev]->write_buffer(" --[TERM]"); // //insert the TERMINATED ones // for (uint i = 0; i < ll->size(); i++) // if (ll->get_item_at(i)->get_state() == DynamicSchedulable::state_terminated) // { // arr = ll->get_item_at(i)->get_schedulable()->get_arrival_time(); // int_to_string(arr, temp); // _devices[dev]->write_buffer(" " + ll->get_item_at(i)->get_schedulable()->get_name() + "_(" + temp + ")"); // } // // } } void TextSimulation::_io_loop(pair pun) { while(true) { //reads the command ustring str; //the sgpem cursor appears only in the console //if (!pun.first->_devices[pun.second]->is_full_duplex()) pun.first->_devices[pun.second]->write_buffer("\nSGPEM=> "); str = pun.first->_devices[pun.second]->read_command(); pair< pair, const ustring > p (pair(pun.first, &(*pun.first->_devices[pun.second])), str); //if (pun.first->_devices[pun.second]->is_full_duplex()) //if the IOManager can read AND write at the same time then create a new thread //thath will write to it while going on reading the next command //Thread::create( sigc::bind(&TextSimulation::parse_command, p), true); //else //no read is possible: only write // FIXME what was the purpose of this (_io_loop()) method // need to comment out to make the code compile //pun.first->parse_command(p); } }