// src/backend/dynamic_process.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 "static_process.hh" #include "dynamic_thread.hh" #include "serialize_visitor.hh" #include "deletor.tcc" #include #include #include using namespace sgpem; using namespace std; DynamicProcess::DynamicProcess(StaticProcess* core) : DynamicSchedulable(), _core(core) { assert(core != NULL); } DynamicProcess::DynamicProcess(const DynamicProcess &other) : Schedulable(), DynamicSchedulable(other), Process(), _core(other._core) { typedef vector::const_iterator ThreadIt; const vector& other_threads = other._dynamic_threads; for(ThreadIt it = other_threads.begin(); it != other_threads.end(); ++it) new DynamicThread(*(*it), this); } DynamicProcess::~DynamicProcess() { for_each(_dynamic_threads.begin(), _dynamic_threads.end(), memory::deletor()); } std::vector DynamicProcess::get_threads() { return vector(_dynamic_threads.begin(), _dynamic_threads.end()); } std::vector DynamicProcess::get_threads() const { return vector(_dynamic_threads.begin(), _dynamic_threads.end()); } Schedulable::state DynamicProcess::get_state() const { int total = _dynamic_threads.size(); int running = 0; int ready = 0; int blocked = 0; int terminated = 0; int future = 0; unsigned int closest = 0; vector::const_iterator it = _dynamic_threads.begin(); for(; it != _dynamic_threads.end(); it++) { if ((**it).get_state() == state_running) running++; if ((**it).get_state() == state_ready) ready++; if ((**it).get_state() == state_blocked) blocked++; if ((**it).get_state() == state_terminated) terminated++; if ((**it).get_state() == state_future) { unsigned int arrival = (**it).get_arrival_time(); // if this is the first future occurrence, record its arrival; // else record its arrival if and only if it is smaller then the recorded one if (future == 0) closest = arrival; else closest = (closest < arrival) ? closest : arrival; future++; } } assert(total > 0); assert(running == 1 || running == 0); assert(running + ready + blocked + terminated + future == total); if (running > 0) return state_running; if (ready > 0) // running == 0 return state_ready; if (blocked > 0) // running == 0 && ready == 0 return state_blocked; // Now check if a "hole" happens: if all threads are terminated // or blocked the next // thread to start, e.g. the one with the least arrival_time, has // start time greater than the current process elapsed time, then // pass from state_future to state_terminated: if (closest > get_elapsed_time()) return state_terminated; if (terminated > 0) // running == 0 && ready == 0 && blocked == 0 return state_terminated; if (future > 0) // running == 0 && ready == 0 && blocked == 0 && terminated == 0 return state_future; // I'm not sure if we can get here (maybe if there are no threads?), // but I don't like this compiler warning: 'control reaches end of non-void function' return state_future; // Since premature optimization is the root of all evil, and the // following code was very fast but also very wrong, the coder // will be punished by allowing her to code in C++ just after // having passed "Algoritmi 3" exam with full marks. /* typedef vector::const_iterator ThreadIt; static const int uninitialized = -1; assert(_dynamic_threads.size() > 0); state result = state_future; int next_thread_starts_at = uninitialized; for(ThreadIt it = _dynamic_threads.begin(); it != _dynamic_threads.end(); ++it) { state thread_state = (*it)->get_state(); // This is the logic behind the code: // If there is at least one running thread, the result is // running. If not, it may be either blocked, ready, future or terminated. // We have these cases (a state takes precedence over some other one): // (a) if a thread is running, return immediately state_running // (b) if a thread is ready, puts unconditionally result as state_ready, // and continue iterating (to see if there's a running thread) // (c) if a thread is blocked, and result is not state_ready, result // becomes state_blocked, and continue iterating (to see if there are // ready or running threads) // (d) if a thread is future, and result is not state_ready or // state_blocked, put result as state_future, and remember // when the next thread will start (d1) (see at the end of this // method for the rationale (d2)). Then continue iterating. // (e) else (if all threads are state_terminated) put result as // state_terminated. // TODO Is this OK? Must be tested... int thread_starts_at; switch(thread_state) { case state_running: // (a) return state_running; case state_ready: // (b) result = state_ready; continue; case state_blocked: // (c) result = state_blocked; continue; case state_future: // (d) result = state_future; thread_starts_at = (*it)->get_arrival_time(); if(next_thread_starts_at == uninitialized) // (d1) next_thread_starts_at = thread_starts_at; else next_thread_starts_at = std::min(thread_starts_at, next_thread_starts_at); continue; default: // (e) result = state_terminated; } } //~ "for" iterating over threads // reused hole checking system */ } void DynamicProcess::serialize(SerializeVisitor& translator) const { // translator.from_process(*_core); translator.from_process(*this); } StaticProcess& DynamicProcess::get_core() { return *_core; } const StaticProcess& DynamicProcess::get_core() const { return *_core; } std::vector& DynamicProcess::get_dynamic_threads() { return _dynamic_threads; } unsigned int DynamicProcess::get_elapsed_time() const { unsigned int result = 0; for(std::vector::const_iterator it = _dynamic_threads.begin(); it != _dynamic_threads.end(); it++) { result += (*it)->get_elapsed_time(); } return result; } int DynamicProcess::get_last_acquisition() const { int result = -1; for(std::vector::const_iterator it = _dynamic_threads.begin(); it != _dynamic_threads.end(); it++) { int acq = (*it)->get_last_acquisition(); if(result < acq) result = acq; } return result; } int DynamicProcess::get_last_release() const { int result = -1; for(std::vector::const_iterator it = _dynamic_threads.begin(); it != _dynamic_threads.end(); it++) { int acq = (*it)->get_last_release(); if(result < acq) result = acq; } return result; }