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