Microsimulation API
/home/marcle/src/R/microsimulation/src/ssim.cc
Go to the documentation of this file.
1 // -*-C++-*-
2 //
3 // This file is part of SSim, a simple discrete-event simulator.
4 // See http://www.inf.usi.ch/carzaniga/ssim/
5 //
6 // Copyright (C) 1998-2005 University of Colorado
7 // Copyright (C) 2012 Antonio Carzaniga
8 //
9 // Authors: Antonio Carzaniga <firstname.lastname@usi.ch>
10 // See AUTHORS for full details.
11 //
12 // SSim is free software: you can redistribute it and/or modify it under
13 // the terms of the GNU General Public License as published by the Free
14 // Software Foundation, either version 3 of the License, or (at your
15 // option) any later version.
16 //
17 // SSim is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with SSim. If not, see <http://www.gnu.org/licenses/>.
24 //
25 #include <vector>
26 
27 #include <siena/ssim.h>
28 #include <heap.h>
29 #include <R.h>
30 
31 namespace ssim {
32 
33 const char * Version = VERSION;
34 
35 // these are the "private" static variables and types of the Sim class
36 //
39 
41 
42 static bool running = false;
43 
45 
46 enum ActionType {
51 };
52 
53 struct Action {
57  const Event * event;
58 
59  Action(Time t, ActionType at, ProcessId p, const Event * e = 0) throw()
60  : time(t), type(at), pid(p), event(e) {};
61 
62  bool operator < (const Action & a) const throw() {
63  return time < a.time;
64  }
65 };
66 
68 
70 
71 struct PDescr {
73  bool terminated;
75 
77  : process(p), terminated(false), available_at(INIT_TIME) {}
78 };
79 
80 typedef std::vector<PDescr> PsTable;
82 
83  void Rprint_actions() {
84  Rprintf("\n[");
85  for (a_table_t::iterator it = actions.begin(); it != actions.end(); it++)
86  Rprintf("(time=%f,%s), ",it->time, it->event->str().c_str());
87  Rprintf("]\n");
88  }
89 
90 
91 
92 class SimImpl {
93 public:
94  static void schedule(Time t, ActionType i, ProcessId p,
95  const Event * e = 0) throw() {
96  if (e != 0) {
97  ++(e->refcount);
98  }
99  actions.insert(Action(current_time + t, i, p, e ));
100  }
101  static void schedule_now(ActionType i, ProcessId p,
102  const Event * e = 0) throw() {
103  if (e != 0) {
104  ++(e->refcount);
105  }
106  actions.insert(Action(current_time, i, p, e ));
107  }
108 };
109 
111  processes.push_back(PDescr(p));
112  ProcessId newpid = processes.size() - 1;
113  SimImpl::schedule_now(A_Init, newpid);
114  return newpid;
115 }
116 
117 void Sim::clear() throw() {
118  running = false;
121  processes.clear();
123  for(a_table_t::iterator a = actions.begin(); a != actions.end(); ++a) {
124  const Event * e = (*a).event;
125  if (e != 0 && --(e->refcount) == 0)
126  delete(e);
127  }
128  actions.clear();
129 }
130 
132 
133 void Sim::ignore_event(EventPredicate pred) throw() {
134  for (ForwardIterator it = actions.begin(); it != actions.end(); it++) {
135  if ((*it).type == A_Event) {
136  const Event * e = (*it).event;
137  if (e != 0) {
138  if(pred(e)) {
139  (*it).type = A_Ignore;
140  }
141  }
142  }
143  }
144 }
145 
146 
147 //
148 // this is the simulator main loop.
149 //
151  //
152  // prevents anyone from re-entering the main loop. Note that this
153  // isn't meant to be thread-safe, it works if some process calls
154  // Sim::run_simulation() within their process_event() function.
155  //
156  static bool lock = false;
157  if (lock) return;
158  lock = true;
159  running = true;
160 
161  //
162  // while there is at least a scheduled action
163  //
164  while (running && !actions.empty()) {
165  //
166  // I'm purposely excluding any kind of checks in this version
167  // of the simulator.
168  //
169  // I should say something like this:
170  // assert(current_time <= (*a).first);
171  //
172  Action action = actions.pop_first();
173  if (action.type == A_Ignore) {
174  if (action.event != 0)
175  if (--(action.event->refcount) == 0)
176  delete(action.event);
177  }
178  else {
179  current_time = action.time;
181  break;
182  current_process = action.pid;
183  //
184  // right now I don't check if current_process is indeed a
185  // valid process. Keep in mind that this is the heart of the
186  // simulator main loop, therefore efficiency is crucial.
187  // Perhaps I should check. This is somehow a design choice.
188  //
190 
191  if (pd.terminated) {
192  if (error_handler)
194  action.event);
195  } else if (current_time < pd.available_at) {
196  if (error_handler)
198  } else {
199  switch (action.type) {
200  case A_Event:
201  pd.process->process_event(action.event);
202  break;
203  case A_Init:
204  pd.process->initialize();
205  break;
206  case A_Stop:
207  pd.process->stop();
208  //
209  // here we must use processes[current_process] instead
210  // of pd since pd.process->stop() might have added or
211  // removed processes, and therefore resized the
212  // processes vector, rendering pd invalid
213  //
214  processes[current_process].terminated = true;
215  break;
216  default:
217  //
218  // add paranoia checks/logging here?
219  //
220  break;
221  }
222  // here we must use processes[current_process] instead of
223  // pd. Same reason as above. the "processes" vector might
224  // have been modified and, as a consequence, resized. So,
225  // pd may no longer be considered a valid reference.
226  //
227  processes[current_process].available_at = current_time;
228  }
229 
230  if (action.event != 0)
231  if (--(action.event->refcount) == 0)
232  delete(action.event);
233  }
234  }
235  lock = false;
236  running = false;
237 }
238 
239 void Sim::set_stop_time(Time t) throw() {
240  stop_time = t;
241 }
242 
243 void Sim::stop_process() throw() {
245 }
246 
247 int Sim::stop_process(ProcessId pid) throw() {
248  if (processes[pid].terminated) return -1;
250  return 0;
251 }
252 
253 void Sim::stop_simulation() throw() {
254  running = false;
255 }
256 
257 void Sim::advance_delay(Time delay) throw() {
258  if (!running) return;
259  current_time += delay;
260 }
261 
263  return current_process;
264 }
265 
266 Time Sim::clock() throw() {
267  return current_time;
268 }
269 
270 void Sim::self_signal_event(const Event * e) throw() {
272 }
273 
274 void Sim::self_signal_event(const Event * e, Time d) throw() {
276 }
277 
278 void Sim::signal_event(ProcessId pid, const Event * e) throw() {
280 }
281 
282 void Sim::signal_event(ProcessId pid, const Event * e, Time d) throw() {
283  SimImpl::schedule(d, A_Event, pid, e);
284 }
285 
287  error_handler = eh;
288 }
289 
291  if (process_id == NULL_PROCESSID) {
292  return process_id = Sim::create_process(this);
293  } else {
294  return NULL_PROCESSID;
295  }
296  }
297 
299 
301  return process_id;
302 }
303 
304 } // namespace ssim
ssim::ForwardIterator
a_table_t::iterator ForwardIterator
Definition: ssim.cc:131
ssim::ProcessWithPId::process_id
ProcessId process_id
Definition: ssim.h:243
ssim::Event::refcount
unsigned refcount
Definition: ssim.h:115
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:239
ssim::Sim::self_signal_event
static void self_signal_event(const Event *e)
signal an event to the current process immediately
Definition: ssim.cc:270
ssim::heap::end
iterator end()
Definition: heap.h:68
ssim::actions
static a_table_t actions
Definition: ssim.cc:69
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::error_handler
static SimErrorHandler * error_handler
Definition: ssim.cc:44
ssim::PDescr::available_at
Time available_at
Definition: ssim.cc:74
ssim::Version
const char * Version
version identifier for this ssim library
Definition: ssim.cc:33
ssim::PDescr
Definition: ssim.cc:71
ssim::PDescr::PDescr
PDescr(Process *p)
Definition: ssim.cc:76
ssim::ActionType
ActionType
Definition: ssim.cc:46
ssim::ProcessWithPId::activate
ProcessId activate()
activates this process within the simulator.
Definition: ssim.cc:290
ssim::SimErrorHandler::handle_terminated
virtual void handle_terminated(ProcessId p, const Event *e)
handles terminated-process conditions.
Definition: ssim.h:306
ssim::heap::insert
void insert(const T &x)
Definition: heap.h:74
ssim::SimImpl::schedule_now
static void schedule_now(ActionType i, ProcessId p, const Event *e=0)
Definition: ssim.cc:101
ssim::A_Ignore
@ A_Ignore
Definition: ssim.cc:50
ssim::heap::pop_first
T pop_first()
Definition: heap.h:89
ssim::heap::clear
void clear()
Definition: heap.h:71
ssim::stop_time
static Time stop_time
Definition: ssim.cc:37
ssim::Process
Virtual class (interface) representing processes running within the simulator.
Definition: ssim.h:130
ssim::Process::stop
virtual void stop(void)
executed when the process is explicitly stopped.
Definition: ssim.h:208
ssim::Action::time
Time time
Definition: ssim.cc:54
ssim::Action::pid
ProcessId pid
Definition: ssim.cc:56
ssim::A_Stop
@ A_Stop
Definition: ssim.cc:49
ssim::running
static bool running
Definition: ssim.cc:42
ssim::Sim::create_process
static ProcessId create_process(Process *)
creates a new process
Definition: ssim.cc:110
ssim::SimErrorHandler::clear
virtual void clear()
handles a clear operation.
Definition: ssim.h:268
ssim::processes
static PsTable processes
Definition: ssim.cc:81
ssim::heap::begin
iterator begin()
Definition: heap.h:67
ssim::Sim::set_error_handler
static void set_error_handler(SimErrorHandler *)
registers a handler for simulation errors.
Definition: ssim.cc:286
ssim::Process::initialize
virtual void initialize(void)
action executed when the process is initialized.
Definition: ssim.h:143
ssim::current_time
static Time current_time
Definition: ssim.cc:38
ssim::Sim::clock
static Time clock()
returns the current virtual time for the current process
Definition: ssim.cc:266
ssim::heap::empty
bool empty()
Definition: heap.h:66
ssim::heap
Definition: heap.h:40
ssim::ProcessId
int ProcessId
process identifier type
Definition: ssim.h:59
ssim::Action
Definition: ssim.cc:53
ssim::heap::iterator
std::vector< T >::iterator iterator
Definition: heap.h:43
ssim::ProcessWithPId::pid
ProcessId pid() const
process id of this process.
Definition: ssim.cc:300
ssim::Sim::stop_process
static void stop_process()
stops the execution of the current process
Definition: ssim.cc:243
ssim::PDescr::process
Process * process
Definition: ssim.cc:72
ssim::SimErrorHandler
an error handler for simulation errors.
Definition: ssim.h:256
ssim::a_table_t
heap< Action > a_table_t
Definition: ssim.cc:67
ssim::Time
double Time
virtual time type
Definition: ssim.h:79
ssim::Event
basic event in the simulation.
Definition: ssim.h:111
ssim::Sim::advance_delay
static void advance_delay(Time)
advance the execution time of the current process.
Definition: ssim.cc:257
ssim::SimImpl
Definition: ssim.cc:92
ssim::Process::process_event
virtual void process_event(const Event *msg)
action executed in response to an event signaled to this process.
Definition: ssim.h:199
ssim::current_process
static ProcessId current_process
Definition: ssim.cc:40
ssim::Action::event
const Event * event
Definition: ssim.cc:57
ssim::Rprint_actions
void Rprint_actions()
Definition: ssim.cc:83
ssim::SimImpl::schedule
static void schedule(Time t, ActionType i, ProcessId p, const Event *e=0)
Definition: ssim.cc:94
ssim::Action::Action
Action(Time t, ActionType at, ProcessId p, const Event *e=0)
Definition: ssim.cc:59
ssim::Sim::this_process
static ProcessId this_process()
returns the current process
Definition: ssim.cc:262
ssim::SimErrorHandler::handle_busy
virtual void handle_busy(ProcessId p, const Event *e)
handles busy-process conditions.
Definition: ssim.h:287
ssim::A_Event
@ A_Event
Definition: ssim.cc:47
ssim::EventPredicate
boost::function< bool(const Event *)> EventPredicate
Definition: ssim.h:123
ssim::Action::type
ActionType type
Definition: ssim.cc:55
ssim::ProcessWithPId::ProcessWithPId
ProcessWithPId()
Definition: ssim.cc:298
ssim::Sim::stop_simulation
static void stop_simulation()
stops execution of the simulation
Definition: ssim.cc:253
ssim::NULL_PROCESSID
const ProcessId NULL_PROCESSID
no process will be identified by NULL_PROCESSID
Definition: ssim.h:63
ssim::Sim::clear
static void clear()
clears out internal data structures
Definition: ssim.cc:117
ssim::INIT_TIME
const Time INIT_TIME
beginning of time
Definition: ssim.h:83
ssim.h
ssim
name space for the Siena simulator.
Definition: microsimulation.cc:8
ssim::Sim::signal_event
static void signal_event(ProcessId p, const Event *e)
signal an event to the given process immediately
Definition: ssim.cc:278
ssim::A_Init
@ A_Init
Definition: ssim.cc:48
ssim::Sim::run_simulation
static void run_simulation()
starts execution of the simulation
Definition: ssim.cc:150
heap.h
ssim::PDescr::terminated
bool terminated
Definition: ssim.cc:73
ssim::Action::operator<
bool operator<(const Action &a) const
Definition: ssim.cc:62
ssim::Sim::ignore_event
static void ignore_event(EventPredicate pred)
Definition: ssim.cc:133
ssim::PsTable
std::vector< PDescr > PsTable
Definition: ssim.cc:80