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();
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();
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