Microsimulation API

/home/marcle/src/R/microsimulation/src/tprocess.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) 2003-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 <siena/tprocess.h>
26
27 #if TPROCESS_IMPL==0
28 #else
29
30 #include <cassert>
31 #include <cstdio>
32
33 #if TPROCESS_IMPL==1
34 #include <ucontext.h>
35 #else
36 #include <setjmp.h>
37 #include <signal.h>
38 #endif
39
40 #include <siena/ssim.h>
41
42 namespace ssim {
43
44 static TProcess * current_tprocess = 0;
45
46 unsigned long TProcess::DefaultStackSize = 8 * 1024;
47
48 #if TPROCESS_IMPL==1
49 static ucontext_t resume_ctx;
50 #else
51 static jmp_buf resume_ctx;
52 #endif
53
54 TProcess::TProcess(unsigned long size) {
55 mystack_size = size;
56 mystack = new char[mystack_size];
57 }
58
59 TProcess::TProcess() {
60 mystack_size = DefaultStackSize;
61 mystack = new char[mystack_size];
62 }
63
64 TProcess::~TProcess() {
65 delete(mystack);
66 }
67
68 void TProcess::resume() {
69 #if TPROCESS_IMPL==1
70 if (swapcontext(&resume_ctx, &running_ctx) < 0) {
71 //
72 // Error handling goes here
73 //
74 // ...work in progress...
75 perror("TProcess::resume: swapcontext failed");
76 }
77 #else
78 if (!setjmp(resume_ctx)) {
79 longjmp(running_ctx, 1);
80 }
81 #endif
82 //
83 // returning from pause();
84 //
85 }
86
87 void TProcess::pause() {
88 #if TPROCESS_IMPL==1
89 if (swapcontext(&running_ctx, &resume_ctx) < 0) {
90 //
91 // Error handling goes here
92 //
93 // ...work in progress...
94 perror("TProcess::pause: swapcontext failed");
95 return;
96 }
97 #else
98 if (!setjmp(running_ctx)) {
99 longjmp(resume_ctx, 1);
100 }
101 #endif
102 //
103 // returning from resume();
104 //
105 current_tprocess = this;
106 }
107
108 #if TPROCESS_IMPL==1
109 void TProcess::starter() {
110 TProcess * p = current_tprocess;
111 p->main();
112 Sim::stop_process();
113 p->pause();
114 // we should never get to this point, because the simulator should
115 // never call process_event or process_timeout after we call
116 // Sim::stop_process()
117 assert(false);
118 }
119 #else
120 void TProcess::starter(int) {
121 TProcess * p = current_tprocess;
122 if (setjmp(p->running_ctx)) {
123 p->main();
124 Sim::stop_process();
125 p->pause();
126 // we should never get to this point, because the simulator should
127 // never call process_event or process_timeout after we call
128 // Sim::stop_process()
129 assert(false);
130 }
131 }
132 #endif
133
134 void TProcess::initialize() {
135 //
136 // this method creates the "execution context" for the thread that
137 // executes this TProcess. We can use two types of
138 // implementations. The first one is based on the "ucontext"
139 // functions makecontext(), getcontext(), and swapcontext(). The
140 // second implementation is based on a combination of POSIX
141 // functions.
142 // Breaking Change: this method was called init().
143 //
144 #if TPROCESS_IMPL==1
145 // this method uses makecontext and swapcontext and is pretty
146 // straightforward.
147 //
148 if (getcontext(&running_ctx)) { // first we create a running context
149 perror("TProcess::initialize: getcontext failed for running_ctx");
150 return;
151 }
152 running_ctx.uc_link = NULL;
153 running_ctx.uc_stack.ss_sp = mystack;
154 running_ctx.uc_stack.ss_size = mystack_size;
155 running_ctx.uc_stack.ss_flags = 0;
156 current_tprocess = this;
157 makecontext(&running_ctx, TProcess::starter, 0);
158
159 if (swapcontext(&resume_ctx, &running_ctx) < 0) {
160 perror("TProcess::initialize: swapcontext failed");
161 return;
162 }
163 #else
164 // this method exploits a signal handler to create a different
165 // execution context (on a different stack), and then uses
166 // setjmp/longjmp to switch contexts.
167 //
168 stack_t stack_descr;
169 struct sigaction sa;
170
171 stack_descr.ss_flags = 0; // set things up to use the new stack
172 stack_descr.ss_size = mystack_size;
173 stack_descr.ss_sp = mystack;
174 sigaltstack(&stack_descr, 0);
175
176 sa.sa_handler = TProcess::starter; // set up the custom signal
177 sa.sa_flags = SA_ONSTACK; // handler to engage the starter
178 sigemptyset(&sa.sa_mask);
179 sigaction(SIGUSR1, &sa, 0);
180
181 current_tprocess = this; // point the starter to this TProcess
182 raise(SIGUSR1); // object and fire up the starter
183
184 resume(); // switch to the newly created context
185 #endif
186 //
187 // returning from pause();
188 //
189 }
190
191 void TProcess::process_event(const Event * msg) {
192 ev = msg;
193 resume();
194 }
195
196 const Event * TProcess::wait_for_event(Time timeout) {
197 Timeout * te = 0;
198 if (timeout != INIT_TIME) {
199 te = new Timeout();
200 Sim::self_signal_event(te, timeout);
201 }
202 const Event * msg;
203 do {
204 current_tprocess->pause();
205 msg = current_tprocess->ev;
206 current_tprocess->ev = 0;
207 //
208 // we iterate to skip previously signaled Timeout
209 //
210 } while (dynamic_cast<const Timeout *>(msg) != 0 && msg != te);
211
212 return msg;
213 }
214
215 void TProcess::stop() { };
216
217 }; // namespace ssim
218
219 #endif // TPROCESS_IMPL == 0
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::Sim::stop_process
static void stop_process()
stops the execution of the current process
Definition: ssim.cc:243
tprocess.h
ssim::Time
double Time
virtual time type
Definition: ssim.h:79
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