Microsimulation API
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 // these are the "private" static variables and types of the Sim class
34 //
37 
39 
40 static bool running = false;
41 
43 
44 enum ActionType {
45  A_Event,
46  A_Init,
47  A_Stop,
48  A_Ignore
49 };
50 
51 struct Action {
52  Time time;
54  ProcessId pid;
55  const Event * event;
56 
57  Action(Time t, ActionType at, ProcessId p, const Event * e = 0) throw()
58  : time(t), type(at), pid(p), event(e) {};
59 
60  bool operator < (const Action & a) const throw() {
61  return time < a.time;
62  }
63 };
64 
65 typedef heap<Action> a_table_t;
66 
68 
69 struct PDescr {
70  Process * process;
71  bool terminated;
73 
75  : process(p), terminated(false), available_at(INIT_TIME) {}
76 };
77 
78 typedef std::vector<PDescr> PsTable;
80 
81  void Rprint_actions() {
82  Rprintf("\n[");
83  for (a_table_t::iterator it = actions.begin(); it != actions.end(); it++)
84  Rprintf("(time=%f,%s), ",it->time, it->event->str().c_str());
85  Rprintf("]\n");
86  }
87 
88 
89 
90 class SimImpl {
91 public:
92  static void schedule(Time t, ActionType i, ProcessId p,
93  const Event * e = 0) throw() {
94  if (e != 0) {
95  ++(e->refcount);
96  }
97  actions.insert(Action(current_time + t, i, p, e ));
98  }
99  static void schedule_now(ActionType i, ProcessId p,
100  const Event * e = 0) throw() {
101  if (e != 0) {
102  ++(e->refcount);
103  }
104  actions.insert(Action(current_time, i, p, e ));
105  }
106 };
107 
108 ProcessId Sim::create_process(Process * p) throw() {
109  processes.push_back(PDescr(p));
110  ProcessId newpid = processes.size() - 1;
111  SimImpl::schedule_now(A_Init, newpid);
112  return newpid;
113 }
114 
115 void Sim::clear() throw() {
116  running = false;
119  processes.clear();
121  for(a_table_t::iterator a = actions.begin(); a != actions.end(); ++a) {
122  const Event * e = (*a).event;
123  if (e != 0 && --(e->refcount) == 0)
124  delete(e);
125  }
126  actions.clear();
127 }
128 
130 
131 void Sim::ignore_event(EventPredicate pred) throw() {
132  for (ForwardIterator it = actions.begin(); it != actions.end(); it++) {
133  if ((*it).type == A_Event) {
134  const Event * e = (*it).event;
135  if (e != 0) {
136  if(pred(e)) {
137  (*it).type = A_Ignore;
138  }
139  }
140  }
141  }
142 }
143 
144 
145 //
146 // this is the simulator main loop.
147 //
148 void Sim::run_simulation() {
149  //
150  // prevents anyone from re-entering the main loop. Note that this
151  // isn't meant to be thread-safe, it works if some process calls
152  // Sim::run_simulation() within their process_event() function.
153  //
154  static bool lock = false;
155  if (lock) return;
156  lock = true;
157  running = true;
158 
159  //
160  // while there is at least a scheduled action
161  //
162  while (running && !actions.empty()) {
163  //
164  // I'm purposely excluding any kind of checks in this version
165  // of the simulator.
166  //
167  // I should say something like this:
168  // assert(current_time <= (*a).first);
169  //
170  Action action = actions.pop_first();
171  if (action.type == A_Ignore) {
172  if (action.event != 0)
173  if (--(action.event->refcount) == 0)
174  delete(action.event);
175  }
176  else {
177  current_time = action.time;
179  break;
180  current_process = action.pid;
181  //
182  // right now I don't check if current_process is indeed a
183  // valid process. Keep in mind that this is the heart of the
184  // simulator main loop, therefore efficiency is crucial.
185  // Perhaps I should check. This is somehow a design choice.
186  //
187  PDescr & pd = processes[current_process];
188 
189  if (pd.terminated) {
190  if (error_handler)
192  action.event);
193  } else if (current_time < pd.available_at) {
194  if (error_handler)
195  error_handler->handle_busy(current_process, action.event);
196  } else {
197  switch (action.type) {
198  case A_Event:
199  pd.process->process_event(action.event);
200  break;
201  case A_Init:
202  pd.process->initialize();
203  break;
204  case A_Stop:
205  pd.process->stop();
206  //
207  // here we must use processes[current_process] instead
208  // of pd since pd.process->stop() might have added or
209  // removed processes, and therefore resized the
210  // processes vector, rendering pd invalid
211  //
212  processes[current_process].terminated = true;
213  break;
214  default:
215  //
216  // add paranoia checks/logging here?
217  //
218  break;
219  }
220  // here we must use processes[current_process] instead of
221  // pd. Same reason as above. the "processes" vector might
222  // have been modified and, as a consequence, resized. So,
223  // pd may no longer be considered a valid reference.
224  //
225  processes[current_process].available_at = current_time;
226  }
227 
228  if (action.event != 0)
229  if (--(action.event->refcount) == 0)
230  delete(action.event);
231  }
232  }
233  lock = false;
234  running = false;
235 }
236 
237 void Sim::set_stop_time(Time t) throw() {
238  stop_time = t;
239 }
240 
241 void Sim::stop_process() throw() {
243 }
244 
245 int Sim::stop_process(ProcessId pid) throw() {
246  if (processes[pid].terminated) return -1;
248  return 0;
249 }
250 
251 void Sim::stop_simulation() throw() {
252  running = false;
253 }
254 
255 void Sim::advance_delay(Time delay) throw() {
256  if (!running) return;
257  current_time += delay;
258 }
259 
260 ProcessId Sim::this_process() throw() {
261  return current_process;
262 }
263 
264 Time Sim::clock() throw() {
265  return current_time;
266 }
267 
268 void Sim::self_signal_event(const Event * e) throw() {
270 }
271 
272 void Sim::self_signal_event(const Event * e, Time d) throw() {
274 }
275 
276 void Sim::signal_event(ProcessId pid, const Event * e) throw() {
278 }
279 
280 void Sim::signal_event(ProcessId pid, const Event * e, Time d) throw() {
281  SimImpl::schedule(d, A_Event, pid, e);
282 }
283 
284 void Sim::set_error_handler(SimErrorHandler * eh) throw() {
285  error_handler = eh;
286 }
287 
289  if (process_id == NULL_PROCESSID) {
290  return process_id = Sim::create_process(this);
291  } else {
292  return NULL_PROCESSID;
293  }
294  }
295 
296 ProcessWithPId::ProcessWithPId() throw(): process_id(NULL_PROCESSID) {}
297 
298 ProcessId ProcessWithPId::pid() const throw() {
299  return process_id;
300 }
301 
302 } // 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