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 // these are the "private" static variables and types of the Sim class
34 //
35 static Time stop_time = INIT_TIME;
36 static Time current_time = INIT_TIME;
37
38 static ProcessId current_process = NULL_PROCESSID;
39
40 static bool running = false;
41
42 static SimErrorHandler * error_handler = 0;
43
44 enum ActionType {
45 A_Event,
46 A_Init,
47 A_Stop,
48 A_Ignore
49 };
50
51 struct Action {
52 Time time;
53 ActionType type;
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
67 static a_table_t actions;
68
69 struct PDescr {
70 Process * process;
71 bool terminated;
72 Time available_at;
73
74 PDescr(Process * p)
75 : process(p), terminated(false), available_at(INIT_TIME) {}
76 };
77
78 typedef std::vector<PDescr> PsTable;
79 static PsTable processes;
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;
117 current_time = INIT_TIME;
118 current_process = NULL_PROCESSID;
119 processes.clear();
120 if (error_handler) error_handler->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
129 typedef a_table_t::iterator ForwardIterator;
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;
178 if (stop_time != INIT_TIME && current_time > stop_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)
191 error_handler->handle_terminated(current_process,
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() {
242 SimImpl::schedule_now(A_Stop, current_process);
243 }
244
245 int Sim::stop_process(ProcessId pid) throw() {
246 if (processes[pid].terminated) return -1;
247 SimImpl::schedule_now(A_Stop, pid);
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() {
269 SimImpl::schedule_now(A_Event, current_process, e);
270 }
271
272 void Sim::self_signal_event(const Event * e, Time d) throw() {
273 SimImpl::schedule(d, A_Event, current_process, e);
274 }
275
276 void Sim::signal_event(ProcessId pid, const Event * e) throw() {
277 SimImpl::schedule_now(A_Event, pid, e);
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
288 ProcessId ProcessWithPId::activate() throw() {
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::Process::initialize
virtual void initialize(void)
action executed when the process is initialized.
Definition: ssim.h:138
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::SimImpl
Definition: ssim.cc:90
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::Process::stop
virtual void stop(void)
executed when the process is explicitly stopped.
Definition: ssim.h:203
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::Event::refcount
unsigned refcount
Definition: ssim.h:110
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::Process::process_event
virtual void process_event(const Event *msg)
action executed in response to an event signaled to this process.
Definition: ssim.h:194
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