// 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 #include using namespace sgpem; using std::vector; DynamicProcess::DynamicProcess(StaticProcess* core) : DynamicSchedulable(*core) {} DynamicProcess::DynamicProcess(const DynamicProcess &other) : Schedulable(), DynamicSchedulable(other), Process() { typedef vector::const_iterator ThreadIt; const vector& other_threads = other._dynamic_threads; for(ThreadIt it = other_threads.begin(); it != other_threads.end(); ++it) _dynamic_threads.push_back(new DynamicThread(*(*it))); } std::vector DynamicProcess::get_threads() { return vector(_dynamic_threads.begin(), _dynamic_threads.end()); } Schedulable::state DynamicProcess::get_state() const { 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... 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; int 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 // Now check if a "hole" happens: if result == state_future, but 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: // (d2) int elapsed_time = get_total_cpu_time() - get_remaining_time(); if(result == state_future && next_thread_starts_at > elapsed_time ) result = state_terminated; return result; } void DynamicProcess::remove_thread(Thread* thread) { assert(thread != NULL); vector::iterator it; it = std::find(_dynamic_threads.begin(), _dynamic_threads.end(), thread); if(it != _dynamic_threads.end()) { _dynamic_threads.erase(it); // FIXME remove me and leave the responsibility for deletion to the caller // (which is?) delete *it; } } void DynamicProcess::add_thread(DynamicThread* thread) { assert(thread != NULL); _dynamic_threads.push_back(thread); } void DynamicProcess::serialize(SerializeVisitor& translator) const { //FIXME write this code. I'm predictable, I know }