ssim.cc
Go to the documentation of this file.
// -*-C++-*-
//
// This file is part of SSim, a simple discrete-event simulator.
// See http://www.inf.usi.ch/carzaniga/ssim/
//
// Copyright (C) 1998-2005 University of Colorado
// Copyright (C) 2012 Antonio Carzaniga
//
// Authors: Antonio Carzaniga <firstname.lastname@usi.ch>
// See AUTHORS for full details.
//
// SSim 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 3 of the License, or (at your
// option) any later version.
//
// SSim 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 SSim. If not, see <http://www.gnu.org/licenses/>.
//
#include <vector>
#include <siena/ssim.h>
#include <heap.h>
#include <R.h>
namespace ssim {
// these are the "private" static variables and types of the Sim class
//
static Time stop_time = INIT_TIME;
static Time current_time = INIT_TIME;
static ProcessId current_process = NULL_PROCESSID;
static bool running = false;
static SimErrorHandler * error_handler = 0;
enum ActionType {
A_Event,
A_Init,
A_Stop,
A_Ignore
};
struct Action {
Time time;
ActionType type;
ProcessId pid;
const Event * event;
Action(Time t, ActionType at, ProcessId p, const Event * e = 0) throw()
: time(t), type(at), pid(p), event(e) {};
bool operator < (const Action & a) const throw() {
return time < a.time;
}
};
typedef heap<Action> a_table_t;
static a_table_t actions;
struct PDescr {
Process * process;
bool terminated;
Time available_at;
PDescr(Process * p)
: process(p), terminated(false), available_at(INIT_TIME) {}
};
typedef std::vector<PDescr> PsTable;
static PsTable processes;
void Rprint_actions() {
Rprintf("\n[");
for (a_table_t::iterator it = actions.begin(); it != actions.end(); it++)
Rprintf("(time=%f,%s), ",it->time, it->event->str().c_str());
Rprintf("]\n");
}
class SimImpl {
public:
static void schedule(Time t, ActionType i, ProcessId p,
const Event * e = 0) throw() {
if (e != 0) {
++(e->refcount);
}
actions.insert(Action(current_time + t, i, p, e ));
}
static void schedule_now(ActionType i, ProcessId p,
const Event * e = 0) throw() {
if (e != 0) {
++(e->refcount);
}
actions.insert(Action(current_time, i, p, e ));
}
};
ProcessId Sim::create_process(Process * p) throw() {
processes.push_back(PDescr(p));
ProcessId newpid = processes.size() - 1;
SimImpl::schedule_now(A_Init, newpid);
return newpid;
}
void Sim::clear() throw() {
running = false;
current_time = INIT_TIME;
current_process = NULL_PROCESSID;
processes.clear();
if (error_handler) error_handler->clear();
for(a_table_t::iterator a = actions.begin(); a != actions.end(); ++a) {
const Event * e = (*a).event;
if (e != 0 && --(e->refcount) == 0)
delete(e);
}
actions.clear();
}
typedef a_table_t::iterator ForwardIterator;
void Sim::ignore_event(EventPredicate pred) throw() {
for (ForwardIterator it = actions.begin(); it != actions.end(); it++) {
if ((*it).type == A_Event) {
const Event * e = (*it).event;
if (e != 0) {
if(pred(e)) {
(*it).type = A_Ignore;
}
}
}
}
}
//
// this is the simulator main loop.
//
void Sim::run_simulation() {
//
// prevents anyone from re-entering the main loop. Note that this
// isn't meant to be thread-safe, it works if some process calls
// Sim::run_simulation() within their process_event() function.
//
static bool lock = false;
if (lock) return;
lock = true;
running = true;
//
// while there is at least a scheduled action
//
while (running && !actions.empty()) {
//
// I'm purposely excluding any kind of checks in this version
// of the simulator.
//
// I should say something like this:
// assert(current_time <= (*a).first);
//
Action action = actions.pop_first();
if (action.type == A_Ignore) {
if (action.event != 0)
if (--(action.event->refcount) == 0)
delete(action.event);
}
else {
current_time = action.time;
if (stop_time != INIT_TIME && current_time > stop_time)
break;
current_process = action.pid;
//
// right now I don't check if current_process is indeed a
// valid process. Keep in mind that this is the heart of the
// simulator main loop, therefore efficiency is crucial.
// Perhaps I should check. This is somehow a design choice.
//
PDescr & pd = processes[current_process];
if (pd.terminated) {
if (error_handler)
error_handler->handle_terminated(current_process,
action.event);
} else if (current_time < pd.available_at) {
if (error_handler)
error_handler->handle_busy(current_process, action.event);
} else {
switch (action.type) {
case A_Event:
pd.process->process_event(action.event);
break;
case A_Init:
pd.process->initialize();
break;
case A_Stop:
pd.process->stop();
//
// here we must use processes[current_process] instead
// of pd since pd.process->stop() might have added or
// removed processes, and therefore resized the
// processes vector, rendering pd invalid
//
processes[current_process].terminated = true;
break;
default:
//
// add paranoia checks/logging here?
//
break;
}
// here we must use processes[current_process] instead of
// pd. Same reason as above. the "processes" vector might
// have been modified and, as a consequence, resized. So,
// pd may no longer be considered a valid reference.
//
processes[current_process].available_at = current_time;
}
if (action.event != 0)
if (--(action.event->refcount) == 0)
delete(action.event);
}
}
lock = false;
running = false;
}
void Sim::set_stop_time(Time t) throw() {
stop_time = t;
}
void Sim::stop_process() throw() {
SimImpl::schedule_now(A_Stop, current_process);
}
int Sim::stop_process(ProcessId pid) throw() {
if (processes[pid].terminated) return -1;
SimImpl::schedule_now(A_Stop, pid);
return 0;
}
void Sim::stop_simulation() throw() {
running = false;
}
void Sim::advance_delay(Time delay) throw() {
if (!running) return;
current_time += delay;
}
ProcessId Sim::this_process() throw() {
return current_process;
}
Time Sim::clock() throw() {
return current_time;
}
void Sim::self_signal_event(const Event * e) throw() {
SimImpl::schedule_now(A_Event, current_process, e);
}
void Sim::self_signal_event(const Event * e, Time d) throw() {
SimImpl::schedule(d, A_Event, current_process, e);
}
void Sim::signal_event(ProcessId pid, const Event * e) throw() {
SimImpl::schedule_now(A_Event, pid, e);
}
void Sim::signal_event(ProcessId pid, const Event * e, Time d) throw() {
SimImpl::schedule(d, A_Event, pid, e);
}
void Sim::set_error_handler(SimErrorHandler * eh) throw() {
error_handler = eh;
}
ProcessId ProcessWithPId::activate() throw() {
if (process_id == NULL_PROCESSID) {
return process_id = Sim::create_process(this);
} else {
return NULL_PROCESSID;
}
}
ProcessWithPId::ProcessWithPId() throw(): process_id(NULL_PROCESSID) {}
ProcessId ProcessWithPId::pid() const throw() {
return process_id;
}
} // namespace ssim
ssim::INIT_TIME
const Time INIT_TIME
beginning of time
Definition: ssim.h:79
ssim::heap::end
iterator end()
Definition: heap.h:68
ssim::ForwardIterator
a_table_t::iterator ForwardIterator
Definition: ssim.cc:129
ssim::actions
static a_table_t actions
Definition: ssim.cc:67
ssim::ActionType
ActionType
Definition: ssim.cc:44
ssim::PDescr::available_at
Time available_at
Definition: ssim.cc:72
ssim::Action::operator<
bool operator<(const Action &a) const
Definition: ssim.cc:60
it
GNU Free Documentation License March Inc Temple MA USA Everyone is permitted to copy and distribute verbatim copies of this license but changing it is not allowed PREAMBLE The purpose of this License is to make a or other written document free in the sense of with or without modifying it
Definition: fdl.txt:15
ssim::PDescr::process
Process * process
Definition: ssim.cc:70
ssim::Sim::this_process
static ProcessId this_process()
returns the current process
Definition: ssim.cc:260
ssim::a_table_t
heap< Action > a_table_t
Definition: ssim.cc:65
ssim::Sim::signal_event
static void signal_event(ProcessId p, const Event *e)
signal an event to the given process immediately
Definition: ssim.cc:276
ssim::EventPredicate
std::function< bool(const Event *)> EventPredicate
Definition: ssim.h:118
ssim::heap
Definition: heap.h:40
ssim::stop_time
static Time stop_time
Definition: ssim.cc:35
ssim::PDescr::PDescr
PDescr(Process *p)
Definition: ssim.cc:74
ssim::Sim::create_process
static ProcessId create_process(Process *)
creates a new process
Definition: ssim.cc:108
ssim::SimImpl::schedule_now
static void schedule_now(ActionType i, ProcessId p, const Event *e=0)
Definition: ssim.cc:99
ssim::Sim::set_error_handler
static void set_error_handler(SimErrorHandler *)
registers a handler for simulation errors.
Definition: ssim.cc:284
ssim::heap::pop_first
T pop_first()
Definition: heap.h:89
ssim::ProcessWithPId::pid
ProcessId pid() const
process id of this process.
Definition: ssim.cc:298
ssim::Sim::stop_simulation
static void stop_simulation()
stops execution of the simulation
Definition: ssim.cc:251
ssim::Process
Virtual class (interface) representing processes running within the simulator.
Definition: ssim.h:125
ssim::Action::time
Time time
Definition: ssim.cc:52
ssim::running
static bool running
Definition: ssim.cc:40
ssim::ProcessId
int ProcessId
process identifier type
Definition: ssim.h:55
ssim::heap::clear
void clear()
Definition: heap.h:71
ssim::Action
Definition: ssim.cc:51
ssim::SimErrorHandler
an error handler for simulation errors.
Definition: ssim.h:251
ssim::heap::begin
iterator begin()
Definition: heap.h:67
ssim::Sim::advance_delay
static void advance_delay(Time)
advance the execution time of the current process.
Definition: ssim.cc:255
ssim::processes
static PsTable processes
Definition: ssim.cc:79
ssim::Sim::ignore_event
static void ignore_event(EventPredicate pred)
Definition: ssim.cc:131
ssim::A_Ignore
@ A_Ignore
Definition: ssim.cc:48
ssim::Event
basic event in the simulation.
Definition: ssim.h:106
ssim::heap::iterator
std::vector< T >::iterator iterator
Definition: heap.h:43
ssim::Sim::set_stop_time
static void set_stop_time(Time t=INIT_TIME)
stops the execution of the simulation at the given time
Definition: ssim.cc:237
ssim::A_Event
@ A_Event
Definition: ssim.cc:45
ssim::SimErrorHandler::clear
virtual void clear()
handles a clear operation.
Definition: ssim.h:263
ssim::heap::insert
void insert(const T &x)
Definition: heap.h:74
ssim::Action::pid
ProcessId pid
Definition: ssim.cc:54
ssim::current_time
static Time current_time
Definition: ssim.cc:36
ssim::ProcessWithPId::activate
ProcessId activate()
activates this process within the simulator.
Definition: ssim.cc:288
ssim::A_Stop
@ A_Stop
Definition: ssim.cc:47
ssim::heap::empty
bool empty()
Definition: heap.h:66
ssim::SimErrorHandler::handle_terminated
virtual void handle_terminated(ProcessId p, const Event *e)
handles terminated-process conditions.
Definition: ssim.h:301
ssim::Sim::clear
static void clear()
clears out internal data structures
Definition: ssim.cc:115
ssim::ProcessWithPId::ProcessWithPId
ProcessWithPId()
Definition: ssim.cc:296
ssim::Action::event
const Event * event
Definition: ssim.cc:55
ssim::Sim::self_signal_event
static void self_signal_event(const Event *e)
signal an event to the current process immediately
Definition: ssim.cc:268
ssim::current_process
static ProcessId current_process
Definition: ssim.cc:38
ssim::PsTable
std::vector< PDescr > PsTable
Definition: ssim.cc:78
ssim::Sim::run_simulation
static void run_simulation()
starts execution of the simulation
Definition: ssim.cc:148
ssim::Sim::clock
static Time clock()
returns the current virtual time for the current process
Definition: ssim.cc:264
ssim::SimErrorHandler::handle_busy
virtual void handle_busy(ProcessId p, const Event *e)
handles busy-process conditions.
Definition: ssim.h:282
ssim.h
heap.h
ssim::Action::type
ActionType type
Definition: ssim.cc:53
ssim::Time
double Time
virtual time type
Definition: ssim.h:75
ssim::Sim::stop_process
static void stop_process()
stops the execution of the current process
Definition: ssim.cc:241
ssim
name space for the Siena simulator.
Definition: microsimulation.cc:3
ssim::Rprint_actions
void Rprint_actions()
Definition: ssim.cc:81
ssim::PDescr::terminated
bool terminated
Definition: ssim.cc:71
ssim::SimImpl::schedule
static void schedule(Time t, ActionType i, ProcessId p, const Event *e=0)
Definition: ssim.cc:92
ssim::Action::Action
Action(Time t, ActionType at, ProcessId p, const Event *e=0)
Definition: ssim.cc:57
ssim::PDescr
Definition: ssim.cc:69
ssim::NULL_PROCESSID
const ProcessId NULL_PROCESSID
no process will be identified by NULL_PROCESSID
Definition: ssim.h:59
ssim::ProcessWithPId::process_id
ProcessId process_id
Definition: ssim.h:238
ssim::A_Init
@ A_Init
Definition: ssim.cc:46
ssim::error_handler
static SimErrorHandler * error_handler
Definition: ssim.cc:42