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 //
37 static Time stop_time = INIT_TIME;
38 static Time current_time = INIT_TIME;
39
40 static ProcessId current_process = NULL_PROCESSID;
41
42 static bool running = false;
43
44 static SimErrorHandler * error_handler = 0;
45
46 enum ActionType {
47 A_Event,
48 A_Init,
49 A_Stop,
50 A_Ignore
51 };
52
53 struct Action {
54 Time time;
55 ActionType type;
56 ProcessId pid;
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
67 typedef heap<Action> a_table_t;
68
69 static a_table_t actions;
70
71 struct PDescr {
72 Process * process;
73 bool terminated;
74 Time available_at;
75
76 PDescr(Process * p)
77 : process(p), terminated(false), available_at(INIT_TIME) {}
78 };
79
80 typedef std::vector<PDescr> PsTable;
81 static PsTable processes;
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
110 ProcessId Sim::create_process(Process * p) throw() {
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;
119 current_time = INIT_TIME;
120 current_process = NULL_PROCESSID;
121 processes.clear();
122 if (error_handler) error_handler->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
131 typedef a_table_t::iterator ForwardIterator;
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 //
150 void Sim::run_simulation() {
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;
180 if (stop_time != INIT_TIME && current_time > stop_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 //
189 PDescr & pd = processes[current_process];
190
191 if (pd.terminated) {
192 if (error_handler)
193 error_handler->handle_terminated(current_process,
194 action.event);
195 } else if (current_time < pd.available_at) {
196 if (error_handler)
197 error_handler->handle_busy(current_process, action.event);
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() {
244 SimImpl::schedule_now(A_Stop, current_process);
245 }
246
247 int Sim::stop_process(ProcessId pid) throw() {
248 if (processes[pid].terminated) return -1;
249 SimImpl::schedule_now(A_Stop, pid);
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
262 ProcessId Sim::this_process() throw() {
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() {
271 SimImpl::schedule_now(A_Event, current_process, e);
272 }
273
274 void Sim::self_signal_event(const Event * e, Time d) throw() {
275 SimImpl::schedule(d, A_Event, current_process, e);
276 }
277
278 void Sim::signal_event(ProcessId pid, const Event * e) throw() {
279 SimImpl::schedule_now(A_Event, pid, e);
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
286 void Sim::set_error_handler(SimErrorHandler * eh) throw() {
287 error_handler = eh;
288 }
289
290 ProcessId ProcessWithPId::activate() throw() {
291 if (process_id == NULL_PROCESSID) {
292 return process_id = Sim::create_process(this);
293 } else {
294 return NULL_PROCESSID;
295 }
296 }
297
298 ProcessWithPId::ProcessWithPId() throw(): process_id(NULL_PROCESSID) {}
299
300 ProcessId ProcessWithPId::pid() const throw() {
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