// src/backend/concrete_history.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 "dynamic_process.hh" #include "dynamic_thread.hh" #include "dynamic_resource.hh" #include "dynamic_request.hh" #include "dynamic_sub_request.hh" #include "static_process.hh" #include "static_thread.hh" #include "static_resource.hh" #include "static_request.hh" #include "static_sub_request.hh" #include "concrete_history.hh" #include #include #include #include #include #include #include using namespace sgpem; using namespace std; using memory::smart_ptr; using memory::deletor; // --------------- // For all you evil-doers on Earth, this is your mighty punishment! template static bool deep_remove(std::vector& v, const T& obj) { typedef typename std::vector Vector; for (typename Vector::iterator it = v.begin(); it != v.end(); it++) if (**it == obj) { delete *it; v.erase(it); return true; } return false; } template static T* deep_find(const std::vector& v, const T& obj) { typedef typename std::vector Vector; for (typename Vector::const_iterator it = v.begin(); it != v.end(); it++) if (**it == obj) { return *it; } return NULL; } // ----------------- ConcreteHistory::ConcreteHistory() : History(), _snapshots(), _sealed(false) { _snapshots.push_back(new ConcreteEnvironment()); } ConcreteHistory::~ConcreteHistory() { for_each(_snapshots.begin(), _snapshots.end(), deletor()); } ConcreteHistory::ConcreteHistory(const ConcreteHistory& h) : History(h), _sealed(h._sealed) { typedef Snapshots::const_iterator SnapIt; for (SnapIt it = h._snapshots.begin(); it != h._snapshots.end(); ++it) _snapshots.push_back(new ConcreteEnvironment(*(*it))); } void ConcreteHistory::append_new_environment(ConcreteEnvironment* environment) { _snapshots.push_back(environment); notify_change(); } ConcreteHistory::size_t ConcreteHistory::get_size() const { return _snapshots.size(); } const ConcreteEnvironment& ConcreteHistory::get_last_environment() const { // Should always be true: assert(_snapshots.size() > 0); return get_environment_at(get_front()); } const ConcreteEnvironment& ConcreteHistory::get_environment_at(position index) const throw(std::out_of_range) { return *_snapshots.at(index); } void ConcreteHistory::remove(resource_key_t resource_key) { // Pay attention that initial isn't deleted by reset() ConcreteEnvironment& initial = *_snapshots.front(); ConcreteEnvironment::Resources& resources = initial.get_resources(); ConcreteEnvironment::Resources::iterator found = resources.find(resource_key); if (found == resources.end()) return; reset(false); delete found->second; resources.erase(found); // Delete the queue associated with the resource. ConcreteEnvironment::SubRequestQueues& srq = initial.get_subrequest_queues(); ConcreteEnvironment::SubRequestQueues::iterator qfound = srq.find(resource_key); // There is always one! assert(qfound != srq.end()); srq.erase(qfound); // Now search and erase subrequest that had a ref to the // removed resource typedef std::vector Threads; typedef std::vector Requests; typedef std::vector SubRequests; // Listening to "The Thing That Should Not Be"... // all hail the cyclomatic complexity! ConcreteEnvironment::Processes& processes = initial.get_processes(); typedef ConcreteEnvironment::Processes::iterator ProcIt; for (ProcIt it1 = processes.begin(); it1 != processes.end(); it1++) { Threads& threads = down_cast(**it1).get_dynamic_threads(); for (Threads::iterator it2 = threads.begin(); it2 != threads.end(); it2++) { Requests& reqs = (*it2)->get_dynamic_requests(); for (Requests::iterator it3 = reqs.begin(); it3 != reqs.end(); it3++) { SubRequests& subr = (*it3)->get_dynamic_subrequests(); SubRequests::iterator it4 = subr.begin(); while (it4 != subr.end()) if ((*it4)->get_resource_key() == resource_key) { delete *it4; it4 = subr.erase(it4); } else it4++; } } } //~ end monstrous construct, "The Thing That Should Not Be" // Chtulhu ftaghn. There are worse things in life. Mother-in-laws, // for example. Or hangovers. Or being read poetry by a Vogon. // Although the above construct really rates between the first tens. notify_change(); } void ConcreteHistory::remove(Process& process) { // Pay attention that initial isn't deleted by reset() ConcreteEnvironment& initial = *_snapshots.front(); ConcreteEnvironment::Processes& processes = initial.get_processes(); bool found = deep_remove(processes, process); if (found) reset(true); } void ConcreteHistory::remove(Thread& thread) { DynamicThread& dyn_thr = down_cast(thread); // Pay attention that initial isn't deleted by reset() ConcreteEnvironment& initial = *_snapshots.front(); ConcreteEnvironment::Processes& processes = initial.get_processes(); Process* found = deep_find(processes, dyn_thr.get_process()); if (found == NULL) return; // not found, just return. DynamicProcess& dynamic_found = down_cast(*found); bool removed = deep_remove(dynamic_found.get_dynamic_threads(), dyn_thr); if (removed) reset(true); } void ConcreteHistory::remove(Request& request) { DynamicRequest& dyn_req = down_cast(request); DynamicThread& dyn_thr = dyn_req.get_thread(); DynamicProcess& dyn_proc = dyn_thr.get_process(); // Pay attention that initial isn't deleted by reset() ConcreteEnvironment& initial = *_snapshots.front(); ConcreteEnvironment::Processes& processes = initial.get_processes(); Process* proc_ref = deep_find(processes, dyn_proc); DynamicProcess* dyn_proc_ref = down_cast(proc_ref); if (dyn_proc_ref == NULL) return; // not found, just return. DynamicThread* thr_ref = deep_find(dyn_proc_ref->get_dynamic_threads(), dyn_thr); if (thr_ref == NULL) return; // not found, just return. bool removed = deep_remove(thr_ref->get_dynamic_requests(), dyn_req); if (removed) reset(true); } void ConcreteHistory::remove(SubRequest& subrequest) { // this function makes one relevant assumption: // the initial environment does contain empty request queues only. DynamicSubRequest& dyn_sub = down_cast(subrequest); DynamicRequest& dyn_req = dyn_sub.get_request(); DynamicThread& dyn_thr = dyn_req.get_thread(); DynamicProcess& dyn_proc = dyn_thr.get_process(); // Pay attention that initial isn't deleted by reset() ConcreteEnvironment& initial = *_snapshots.front(); ConcreteEnvironment::Processes& processes = initial.get_processes(); Process* proc_ref = deep_find(processes, dyn_proc); DynamicProcess* dyn_proc_ref = down_cast(proc_ref); if (dyn_proc_ref == NULL) return; // not found, just return. DynamicThread* thr_ref = deep_find(dyn_proc_ref->get_dynamic_threads(), dyn_thr); if (thr_ref == NULL) return; // not found, just return. DynamicRequest* req_ref = deep_find(thr_ref->get_dynamic_requests(), dyn_req); if (req_ref == NULL) return; // not found, just return. bool removed = deep_remove(req_ref->get_dynamic_subrequests(), dyn_sub); if (removed) reset(true); } void ConcreteHistory::clear() { reset(false); assert(_snapshots.size() == 1); delete _snapshots.front(); _snapshots.front() = new ConcreteEnvironment(); notify_change(); } ConcreteHistory::ResourcePair ConcreteHistory::add_resource(const Glib::ustring& name, bool preemptable, size_t places, size_t availability) { reset(false); typedef ConcreteEnvironment::Resources Resources; typedef ConcreteEnvironment::SubRequestQueue SubRequestQueue; // And preemptable and availability?? FIXME! StaticResource* core = new StaticResource(name, places); DynamicResource* resource = new DynamicResource(core); ConcreteEnvironment::Resources& resources = _snapshots.front()->get_resources(); // alakazam! Black magic at work... get a unique index for this resource resource_key_t index = 0; while (resources.find(index) != resources.end()) index++; // Found a hole in the map, fill it like little Hans, // its finger and the spilling dam. Resources::iterator temp = resources.insert(pair(index, resource)).first; // The same for request queues. SubRequestQueue emptysrq; _snapshots.front()->get_subrequest_queues().insert(pair(index, emptysrq)); notify_change(); return *temp; } void ConcreteHistory::edit_resource(Resource& resource, const Glib::ustring& name, bool preemptable, size_t places, size_t availability) { // And preemptable and availability?? FIXME! DynamicResource* res = down_cast(&resource); StaticResource& core = res->get_core(); core.set_name(name); core.set_places(places); reset(true); } DynamicProcess& ConcreteHistory::add_process(const Glib::ustring& name, time_t arrival_time, prio_t base_priority) { reset(false); StaticProcess* core = new StaticProcess(name, arrival_time, base_priority); DynamicProcess* proc = new DynamicProcess(core); ConcreteEnvironment::Processes& processes = _snapshots.front()->get_processes(); processes.push_back(proc); notify_change(); return *proc; } void ConcreteHistory::edit_process(Process& process, const Glib::ustring& name, time_t arrival_time, prio_t base_priority) { DynamicProcess* proc = down_cast(&process); StaticProcess& core = proc->get_core(); core.set_name(name); core.set_arrival_time(arrival_time); core.set_priority(base_priority); reset(true); } DynamicThread& ConcreteHistory::add_thread(const Glib::ustring& name, Process& parent, time_t cpu_time, time_t arrival_time, prio_t base_priority) { reset(false); DynamicProcess& parent_process = down_cast(parent); StaticProcess& parent_core = parent_process.get_core(); StaticThread* core = new StaticThread(name, parent_core, cpu_time, arrival_time, base_priority); DynamicThread* thread = new DynamicThread(core, &parent_process); notify_change(); return *thread; } void ConcreteHistory::edit_thread(Thread& thread, const Glib::ustring& name, time_t cpu_time, time_t arrival_time, prio_t base_priority) { DynamicThread* thre = down_cast(&thread); StaticThread& core = thre->get_core(); core.set_name(name); core.set_total_cpu_time(cpu_time); core.set_arrival_time(arrival_time); core.set_priority(base_priority); reset(true); } DynamicRequest& ConcreteHistory::add_request(Thread& owner, time_t instant) { reset(false); DynamicThread& dyn_owner = down_cast(owner); StaticThread& owner_core = dyn_owner.get_core(); StaticRequest* core = new StaticRequest(&owner_core, instant); DynamicRequest* req = new DynamicRequest(core, &dyn_owner); dyn_owner.get_requests().push_back(req); notify_change(); return *req; } void ConcreteHistory::edit_request(Request& request, time_t instant) { DynamicRequest* req = down_cast(&request); StaticRequest& core = req->get_core(); core.set_instant(instant); reset(true); } DynamicSubRequest& ConcreteHistory::add_subrequest(Request& request, resource_key_t resource_key, time_t duration) { reset(false); DynamicRequest& dyn_request = down_cast(request); StaticSubRequest* core = new StaticSubRequest(resource_key, duration); DynamicSubRequest* subreq = new DynamicSubRequest(core, &dyn_request); dyn_request.get_subrequests().push_back(subreq); notify_change(); return *subreq; } void ConcreteHistory::edit_subrequest(SubRequest& subrequest, resource_key_t resource_key, time_t duration) { DynamicSubRequest* sreq = down_cast(&subrequest); StaticSubRequest& core = sreq->get_core(); core.set_resource_key(resource_key); core.set_length(duration); reset(true); } void ConcreteHistory::reset() { reset(true); } void ConcreteHistory::set_front(position p) { position old_front = _front; if (p > _snapshots.size() - 1) _front = _snapshots.size() - 1; else _front = p; if(old_front != _front) notify_change(); } void ConcreteHistory::reset(bool notify) { assert(_snapshots.size() > 0); Snapshots::iterator it = _snapshots.begin(); it++; // Skip first environment that we saved for_each(it, _snapshots.end(), deletor()); _snapshots.resize(1); // Truncate to keep only our "model" _front = 0; _sealed = false; if (notify) notify_change(); } bool ConcreteHistory::is_sealed() const { return _sealed; } bool ConcreteHistory::seal() { bool t = _sealed; _sealed = true; return t; }