1 //==============================================================================================
2 //
3 // This file is part of LiDIA --- a library for computational number theory
4 //
5 // Copyright (c) 1994--2001 the LiDIA Group. All rights reserved.
6 //
7 // See http://www.informatik.tu-darmstadt.de/TI/LiDIA/
8 //
9 //----------------------------------------------------------------------------------------------
10 //
11 // $Id$
12 //
13 // Author : Markus Maurer (MM)
14 // Changes : See CVS log
15 //
16 //==============================================================================================
17
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22 #include "LiDIA/lidia_signal.h"
23
24
25
26 #ifdef LIDIA_NAMESPACE
27 namespace LiDIA {
28 #endif
29
30
31
32 const int lidia_signal::default_stack_size = 16;
33
34 lidia_signal::signal_stack lidia_signal::signals[] = {
35 #ifdef LIDIA_SIGHUP
36 { LIDIA_SIGHUP, 0, 2, -1, 0, NULL },
37 #endif
38 #ifdef LIDIA_SIGINT
39 { LIDIA_SIGINT, 2, 4, -1, 0, NULL },
40 #endif
41 #ifdef LIDIA_SIGQUIT
42 { LIDIA_SIGQUIT, 6, 2, -1, 0, NULL },
43 #endif
44 #ifdef LIDIA_SIGILL
45 { LIDIA_SIGILL, 8, 2, -1, 0, NULL },
46 #endif
47 #ifdef LIDIA_SIGTRAP
48 { LIDIA_SIGTRAP, 10, 2, -1, 0, NULL },
49 #endif
50 #ifdef LIDIA_SIGIOT
51 { LIDIA_SIGIOT, 12, 2, -1, 0, NULL },
52 #endif
53 #ifdef LIDIA_SIGABRT
54 { LIDIA_SIGABRT, 14, 2, -1, 0, NULL },
55 #endif
56 #ifdef LIDIA_SIGEMT
57 { LIDIA_SIGEMT, 16, 2, -1, 0, NULL },
58 #endif
59 #ifdef LIDIA_SIGTFPE
60 { LIDIA_SIGFPE, 18, 2, -1, 0, NULL },
61 #endif
62 #ifdef LIDIA_SIGKILL
63 { LIDIA_SIGKILL, 20, 2, -1, 0, NULL },
64 #endif
65 #ifdef LIDIA_SIGBUS
66 { LIDIA_SIGBUS, 22, 2, -1, 0, NULL },
67 #endif
68 #ifdef LIDIA_SIGSEGV
69 { LIDIA_SIGSEGV, 24, 4, -1, 0, NULL },
70 #endif
71 #ifdef LIDIA_SIGSYS
72 { LIDIA_SIGSYS, 28, 2, -1, 0, NULL },
73 #endif
74 #ifdef LIDIA_SIGPIPE
75 { LIDIA_SIGPIPE, 30, 2, -1, 0, NULL },
76 #endif
77 #ifdef LIDIA_SIGALRM
78 { LIDIA_SIGALRM, 32, 2, -1, 0, NULL },
79 #endif
80 #ifdef LIDIA_SIGTERM
81 { LIDIA_SIGTERM, 34, 2, -1, 0, NULL },
82 #endif
83 #ifdef LIDIA_SIGUSR1
84 { LIDIA_SIGUSR1, 36, 2, -1, 0, NULL },
85 #endif
86 #ifdef LIDIA_SIGUSR2
87 { LIDIA_SIGUSR2, 38, 2, -1, 0, NULL },
88 #endif
89 #ifdef LIDIA_SIGCLD
90 { LIDIA_SIGCLD, 40, 2, -1, 0, NULL },
91 #endif
92 #ifdef LIDIA_SIGCHLD
93 { LIDIA_SIGCHLD, 42, 2, -1, 0, NULL },
94 #endif
95 #ifdef LIDIA_SIGPWR
96 { LIDIA_SIGPWR, 44, 2, -1, 0, NULL },
97 #endif
98 #ifdef LIDIA_SIGWINCH
99 { LIDIA_SIGWINCH, 46, 2, -1, 0, NULL },
100 #endif
101 #ifdef LIDIA_SIGURG
102 { LIDIA_SIGURG, 48, 2, -1, 0, NULL },
103 #endif
104 #ifdef LIDIA_SIGPOLL
105 { LIDIA_SIGPOLL, 50, 2, -1, 0, NULL },
106 #endif
107 #ifdef LIDIA_SIGIO
108 { LIDIA_SIGIO, 52, 2, -1, 0, NULL },
109 #endif
110 #ifdef LIDIA_SIGSTOP
111 { LIDIA_SIGSTOP, 54, 2, -1, 0, NULL },
112 #endif
113 #ifdef LIDIA_SIGTSTP
114 { LIDIA_SIGTSTP, 56, 2, -1, 0, NULL },
115 #endif
116 #ifdef LIDIA_SIGCONT
117 { LIDIA_SIGCONT, 58, 2, -1, 0, NULL },
118 #endif
119 #ifdef LIDIA_SIGTTIN
120 { LIDIA_SIGTTIN, 60, 2, -1, 0, NULL },
121 #endif
122 #ifdef LIDIA_SIGTTOU
123 { LIDIA_SIGTTOU, 62, 2, -1, 0, NULL },
124 #endif
125 #ifdef LIDIA_SIGVTALRM
126 { LIDIA_SIGVTALRM, 64, 2, -1, 0, NULL },
127 #endif
128 #ifdef LIDIA_SIGPROF
129 { LIDIA_SIGPROF, 66, 2, -1, 0, NULL },
130 #endif
131 #ifdef LIDIA_SIGXCPU
132 { LIDIA_SIGXCPU, 68, 2, -1, 0, NULL },
133 #endif
134 #ifdef LIDIA_SIGXFSZ
135 { LIDIA_SIGXFSZ, 70, 2, -1, 0, NULL },
136 #endif
137 #ifdef LIDIA_SIGWAITING
138 { LIDIA_SIGWAITING, 72, 2, -1, 0, NULL },
139 #endif
140 { 0, 0, 0, 0, 0, NULL }
141 };
142
143
144
145 //
146 // Function: static lidia_signal::allocate
147 //
148 // Parameters and Method:
149 //
150 // s == NULL
151 // allocates new_size elements for s
152 //
153 // old_size <= new_size:
154 // enlarges s to new_size elements
155 // with elements 0,...,old_size-1
156 // unchanged
157 //
158 // old_size > new_size:
159 // reduces s to new_size elements
160 // with deleting the elements
161 // new_size,...,old_size-1
162 //
163
164 void
allocate(lidia_signal_handler_t * & s,int old_size,int new_size)165 lidia_signal::allocate (lidia_signal_handler_t * &s,
166 int old_size,
167 int new_size)
168 {
169 #ifdef HAVE_POSIX_SIGNALS
170 if (old_size > new_size) {
171 old_size = new_size;
172 }
173
174 if (s == NULL) {
175 s = new lidia_signal_handler_t[new_size];
176 }
177 else {
178 lidia_signal_handler_t *t;
179 int i;
180
181 t = new lidia_signal_handler_t[new_size];
182
183 for (i = 0; i < old_size; i++)
184 t[i] = s[i];
185
186 delete [] s;
187 s = t;
188 }
189 #endif // HAVE_POSIX_SIGNALS
190 }
191
192
193 //
194 // Function: lidia_signal::print_stack_index
195 //
196 // Parameter: The index of a stack in the
197 // stack array lidia_signal::signals
198 //
199 // Must be a valid index. No check.
200 //
201 // Method: Prints the content of signals[index].
202 //
203
204 void
print_stack_index(int index)205 lidia_signal::print_stack_index (int index)
206 {
207 #ifdef HAVE_POSIX_SIGNALS
208 std::cout << "signal : " << signals[index].sig << "\n";
209 std::cout << "stack pointer : " << signals[index].sp << "\n";
210 std::cout << "stack size : " << signals[index].ss << "\n";
211
212 #if 0
213 int i;
214 std::cout << "stack : ";
215
216 if (signals[index].sp < 0)
217 std::cout << "empty\n";
218 else {
219 for (i = 0; i <= signals[index].sp; i++)
220 std::cout << " (" << signals[index].stack[i] << ")";
221 std::cout << "\n";
222 }
223 #endif
224 std::cout.flush();
225 #endif // HAVE_POSIX_SIGNALS
226 }
227
228
229
230 //
231 // Function: lidia_signal::print_stack
232 //
233 // Parameter: A signal
234 //
235 // Method: Searches for the index of the stack of the signal.
236 // If found, calls print_stack_index(index) to display
237 // the content of the stack. Otherwise calls the
238 // lidia_error_handler.
239 //
240
241 void
print_stack(int sig)242 lidia_signal::print_stack (int sig)
243 {
244 #ifdef HAVE_POSIX_SIGNALS
245 int i;
246 int sig_found;
247
248 sig_found = 0;
249
250 for (i = 0; signals[i].sig && !sig_found; ++i) {
251 if (signals[i].sig == sig) {
252 // mark found
253 sig_found = 1;
254
255 // display stack
256 lidia_signal::print_stack_index(i);
257 }
258 }
259
260 if (!sig_found) {
261 lidia_error_handler("lidia_signal::print_stack",
262 "Signal not found in signal list.");
263 }
264 #endif // HAVE_POSIX_SIGNALS
265 }
266
267
268
269 //
270 // Function: static lidia_signal::install_handler
271 //
272 // Parameter: sig, the signal for which a handler
273 // should be installed
274 // handler, the new handler for sig
275 //
276 // Method:
277 //
278 // Searches for signal sig in the list of signals
279 // and puts the handler on top of the stack.
280 // If the signal was found:
281 //
282 // * First install for sig:
283 // store current handler for sig in stack[0]
284 // and set stack[1] = handler
285 //
286 // * At least second call for sig:
287 // verify, that the current handler for sig
288 // is on top of the stack;
289 // increase stack pointer sp and
290 // store stack[sp] = handler;
291 //
292 // If the signal was not found:
293 // call the lidia_error_handler
294 //
295
296 void
install_handler(int sig,lidia_signal_handler_t handler)297 lidia_signal::install_handler (int sig, lidia_signal_handler_t handler)
298 {
299 #ifdef HAVE_POSIX_SIGNALS
300 int i, sig_found;
301 lidia_signal_handler_t h;
302
303 struct sigaction iact, oact;
304
305
306 sig_found = 0;
307
308 // Search for signal sig in the list of signals.
309
310 for (i = 0; signals[i].sig && !sig_found; ++i) {
311 if (signals[i].sig == sig) {
312 // mark found
313 sig_found = 1;
314
315 // store current handler in h
316 // and set new handler for sig
317 // h = sigset(sig, handler);
318
319 iact.sa_handler = handler;
320 sigemptyset(&iact.sa_mask);
321 iact.sa_flags = 0;
322 #ifdef SA_RESTART
323 iact.sa_flags |= SA_RESTART;
324 #endif
325 sigaction(sig, &iact, &oact);
326 h = oact.sa_handler;
327
328 // allocate space for stack
329 // when called for the first time
330 if (signals[i].ss == 0) {
331 signals[i].ss = lidia_signal::default_stack_size;
332 lidia_signal::allocate(signals[i].stack, 0, signals[i].ss);
333 }
334
335 // First install for sig:
336 // store current handler for sig in stack[0]
337 // and set stack[1] = handler
338 if (signals[i].sp == -1) {
339 signals[i].sp = 1;
340 signals[i].stack[0] = h;
341 signals[i].stack[1] = handler;
342 }
343
344 // At least second call for sig:
345 // verify, that the current handler for sig
346 // is on top of the stack;
347 else if (h != signals[i].stack[signals[i].sp]) {
348 lidia_error_handler("lidia_signal::install_handler",
349 "Inconsistent signal stack.");
350 }
351 else {
352 // increase stack pointer
353 ++signals[i].sp;
354
355 // double stack space, if end is reached
356 if (signals[i].sp == signals[i].ss) {
357 lidia_signal::allocate(signals[i].stack,
358 signals[i].ss,
359 2*signals[i].ss);
360 signals[i].ss *= 2;
361 }
362
363 // store handler on top of stack
364 signals[i].stack[signals[i].sp] = handler;
365 }
366 // end if (signals[i].sp == -1)
367 }
368 // end if (signals[i].sig == sig)
369 }
370 // end for (i = 0; signals[i].sig; ++i)
371
372
373 if (!sig_found) {
374 lidia_error_handler("lidia_signal::install_handler",
375 "signal not found in signal list.");
376 }
377 #endif // HAVE_POSIX_SIGNALS
378 }
379 // end install_handler
380
381
382
383
384 //
385 // Function: static lidia_signal::uninstall_handler
386 //
387 // Parameter: sig, the signal for which the current
388 // handler should be uninstalled
389 //
390 // Method:
391 //
392 // Removes the current handler for sig from the top
393 // of the stack, decreases the stack pointer and
394 // reinstalls the previous handler for sig which is
395 // now on top of the stack.
396 //
397 // If the stack does not contain a lidia signal handler
398 // anymore (stack pointer = 0), the user defined signal
399 // handler in stack[0] is remove from top of stack.
400 // If the user now installs a new handler for sig and
401 // calls lidia functions, which again install
402 // their own handlers for sig, the new user handler
403 // is stored in stack[0] by the lidia_signal::install_handler
404 // function (see above).
405 //
406
407 void
uninstall_handler(int sig)408 lidia_signal::uninstall_handler (int sig)
409 {
410 #ifdef HAVE_POSIX_SIGNALS
411 int i, sig_found;
412 lidia_signal_handler_t h;
413
414 struct sigaction iact, oact;
415
416
417 sig_found = 0;
418
419 for (i = 0; signals[i].sig && !sig_found; ++i) {
420 // search for signal
421 if (signals[i].sig == sig) {
422 // mark found
423 sig_found = 1;
424
425 // no handler installed for sig
426 if (signals[i].sp == -1) {
427 lidia_warning_handler("lidia_signal::uninstall_handler",
428 "uninstall without previous install.");
429 }
430 // found installed handler
431 else {
432 // store current handler in h
433 // and install second handler from stack
434 // h = sigset(sig, signals[i].stack[signals[i].sp-1]);
435
436 iact.sa_handler = signals[i].stack[signals[i].sp-1];
437 sigemptyset(&iact.sa_mask);
438 iact.sa_flags = 0;
439 #ifdef SA_RESTART
440 iact.sa_flags |= SA_RESTART;
441 #endif
442 sigaction(sig, &iact, &oact);
443 h = oact.sa_handler;
444
445 // current handler is not on top of stack
446 if (h != signals[i].stack[signals[i].sp]) {
447 lidia_error_handler("lidia_signal::uninstall_handler",
448 "Inconsistent signal stack.");
449 }
450
451 // remove handler from top of the stack
452 --signals[i].sp;
453
454 // stack contains no lidia signal handler anymore:
455 // remove user handler from stack
456 if (signals[i].sp == 0) {
457 --signals[i].sp;
458 }
459 }
460 }
461 }
462 #endif // HAVE_POSIX_SIGNALS
463 }
464
465
466
lidia_signal(int sig,lidia_signal_handler_t handler)467 lidia_signal::lidia_signal (int sig, lidia_signal_handler_t handler)
468 {
469 signal_num = sig;
470 lidia_signal::install_handler(sig, handler);
471 }
472
473
474
~lidia_signal()475 lidia_signal::~lidia_signal ()
476 {
477 lidia_signal::uninstall_handler(signal_num);
478 }
479
480
481
482 #ifdef LIDIA_NAMESPACE
483 } // end of namespace LiDIA
484 #endif
485