/[ascend]/trunk/base/generic/utilities/ascSignal.c
ViewVC logotype

Contents of /trunk/base/generic/utilities/ascSignal.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 526 - (show annotations) (download) (as text)
Fri Apr 21 13:47:31 2006 UTC (14 years, 7 months ago) by johnpye
File MIME type: text/x-csrc
File size: 12695 byte(s)
Fixed up a problem with ordering of headers with Python.h.
Removed psyco initialisation, pending evidence that it actually does something :-)
Disabled python 'director' error message callbacks, trying to debug a segfault.
Added ability to disable GCC Visibility, scons WITH_GCCVISIBILITY=0.
Turned off runtime signal tests for SIG_INT and SIG_FPE (makes using GDB a pain), see base/generic/utilities/ascSignal.[ch].
1 /* ASCEND modelling environment
2 Copyright (C) 1997 Benjamin Andrew Allan
3 Copyright (C) 2006 Carnegie Mellon University
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 *//**
20 * Signal handling protocol definitions for ASCEND
21 * Start of making signal handling in ASCEND
22 * code somewhat sane. Still needs to somehow
23 * support the management of jmp_buf's so that
24 * handlers will longjmp to the right place.
25 *
26 * A better alternative is to make all our code check/return
27 * status flags based on a variable set by the trap
28 * and cleared by recipient.
29 *//*
30 * May 27, 1997
31 * By Benjamin Andrew Allan
32 * Version: $Revision: 1.9 $
33 * Version control file: $RCSfile: ascSignal.c,v $
34 * Date last modified: $Date: 1999/01/19 12:23:20 $
35 * Last modified by: $Author: mthomas $
36 *
37 * ChangeLog
38 *
39 * 10/15/2005 - Changed ascresetneeded() so that any previously
40 * registered handlers are reset before return.
41 * - Added Asc_SignalRecover() to standard handler
42 * Asc_SignalTrap() so handlers are reset if necessary. (JDS)
43 * 12/10/2005 - Changed storage of signal handlers from gl_list's
44 * to local arrays. gl_list's can't legally hold
45 * function pointers. (JDS)
46 */
47
48 #include <stdio.h>
49 #include "ascConfig.h"
50
51 #ifndef NO_SIGNAL_TRAPS
52 # include <signal.h>
53 # include <setjmp.h>
54 #endif /* NO_SIGNAL_TRAPS*/
55
56 #ifdef __WIN32__
57 # include <process.h>
58 #else
59 # include <unistd.h>
60 #endif
61
62 #include "ascMalloc.h"
63 #include "ascSignal.h"
64
65 #if !defined(NO_SIGINT_TRAP) || !defined(NO_SIGSEGV_TRAP)
66 static jmp_buf f_test_env; /* for local testing of signal handling */
67 #endif
68
69 #ifndef NO_SIGNAL_TRAPS
70 /* test buf for initialization */
71 jmp_buf g_fpe_env;
72 jmp_buf g_seg_env;
73 jmp_buf g_int_env;
74
75 /* for future use */
76 jmp_buf g_foreign_code_call_env;
77
78 #endif /* NO_SIGNAL_TRAPS*/
79
80 static int f_reset_needed = -2;
81 /* has value 0 or 1 after Init is called.
82 * and if Init is called without the value -2 in f_reset_needed,
83 * it will fail.
84 */
85 static SigHandler *f_fpe_traps = NULL; /**< array for pushed SIGFPE handlers */
86 static int f_fpe_top_of_stack = -1; /**< top of SIGFPE stack, -1 for empty */
87
88 static SigHandler *f_int_traps = NULL; /**< array for pushed SIGINT handlers */
89 static int f_int_top_of_stack = -1; /**< top of SIGFPE stack, -1 for empty */
90
91 static SigHandler *f_seg_traps = NULL; /**< array for pushed SIGSEGV handlers */
92 static int f_seg_top_of_stack = -1; /**< top of SIGFPE stack, -1 for empty */
93
94 #ifndef NO_SIGSEGV_TRAP
95 /* function to throw an interrupt. system dependent. */
96 static int testdooley2(int sig){
97 raise(sig);
98 return 0;
99 }
100 #endif
101
102 #if !defined(NO_SIGINT_TRAP) || !defined(NO_SIGSEGV_TRAP)
103 /* function to catch an interrupt */
104 static void testcatch(int signum){
105 FPRINTF(ASCERR," signal %d caught ",signum);
106 if (signum == SIGFPE) {
107 FPRESET;
108 }
109 longjmp(f_test_env, signum);
110 }
111 #endif
112
113 /*
114 * So far the following seem to need reset trapped signals after
115 * a longjmp, or unconditionally.
116 * HPUX cc -Aa -D_HPUX_SOURCE
117 * Solaris cc
118 * AIX xlc
119 * IRIX cc
120 * Windows
121 *
122 * The following retain the last trap set with or without a call to longjmp
123 * and so don't need resetting of traps.
124 * SunOS4 acc
125 * OSF32 cc
126 * NetBSD gcc 2.4.5 -ansi
127 */
128 /* This function tests the signal reseting of compilers using SIGINT.
129 * It should not be called except when starting a process.
130 * Return 0 for no reset needed, 1 for reset needed, and
131 * -1 if the test fails (presuming program doesn't exit first.)
132 * Side effects:
133 * - a line is sent to ASCERR
134 * - SIGINT is set to SIG_DFL if no handler was previously registered
135 * - SIGFPE may be set to SIG_DFL if no handler was previously registered
136 */
137 static int ascresetneeded(void) {
138 static int result = 0;
139
140 #if !defined(NO_SIGINT_TRAP) || !defined(NO_SIGSEGV_TRAP)
141 SigHandler lasttrap;
142 volatile SigHandler savedtrap;
143 static int c=0;
144 #endif
145
146 #ifndef NO_SIGINT_TRAP
147
148 /* test interrupt */
149 savedtrap = signal(SIGINT, testcatch);
150 CONSOLE_DEBUG("Testing signal SIGINT (signum = %d) %p\t%p\t", SIGINT, savedtrap, testcatch);
151 if (setjmp(f_test_env) == 0) {
152 testdooley2(SIGINT);
153 } else {
154 c++;
155 }
156 if (c != 1) {
157 CONSOLE_DEBUG("SIGINT test failed");
158 ERROR_REPORTER_NOLINE(ASC_PROG_ERROR,"Signal (SIGINT) test failed. ASCEND unlikely to work on this hardware.");
159 result = -1;
160 }
161 lasttrap = signal(SIGINT, (NULL != savedtrap) ? savedtrap : SIG_DFL);
162 CONSOLE_DEBUG("%p",lasttrap);
163 if (lasttrap != testcatch) {
164 result = 1;
165 }
166
167 if (result != 0) {
168 return result;
169 }
170
171 c = 0;
172 #else
173 CONSOLE_DEBUG("SIGINT trap bypassed: compile-time settings");
174 #endif
175
176 #ifndef NO_SIGSEGV_TRAP
177 /* passed interrupt, check fpe */
178 savedtrap=signal(SIGFPE, testcatch);
179 CONSOLE_DEBUG("Testing signal %d %p\t%p\t",SIGFPE, savedtrap, testcatch);
180 if (setjmp(f_test_env)==0) {
181 testdooley2(SIGFPE);
182 } else {
183 c++;
184 }
185 if (c != 1) {
186 CONSOLE_DEBUG("SIGFPE test failed");
187 ERROR_REPORTER_NOLINE(ASC_PROG_ERROR,"Signal test failed. ASCEND unlikely to work on this hardware.");
188 result = -1;
189 }
190 lasttrap = signal(SIGFPE, (NULL != savedtrap) ? savedtrap : SIG_DFL);
191 CONSOLE_DEBUG("%p\n",lasttrap);
192 if (lasttrap != testcatch) {
193 result = 1;
194 }
195 #else
196 CONSOLE_DEBUG("SIGSEGV trap bypassed: compile-time settings\n");
197 #endif
198
199 return result;
200 }
201
202 static
203 void initstack (SigHandler *traps, int *stackptr, int sig)
204 {
205 SigHandler old;
206 old = signal(sig,SIG_DFL);
207 if (old != SIG_ERR && old != SIG_DFL) {
208 traps[0] = old;
209 *stackptr = 0;
210 (void)signal(sig,old);
211 }
212 }
213 /*
214 * Returns 0 if successful, 1 if out of memory, 2 otherwise.
215 * Does not establish any traps, just the structures for
216 * maintaining them. Pushes the existing traps, if any, on
217 * the bottom of the created stacks.
218 * Cannot be called twice successfully.
219 */
220 int Asc_SignalInit(void)
221 {
222 if (f_reset_needed != -2) {
223 return 2;
224 }
225
226 /* initialize SIGFPE stack */
227 if (f_fpe_traps == NULL) {
228 f_fpe_traps = (SigHandler *)asccalloc(MAX_TRAP_DEPTH,sizeof(SigHandler));
229 if (f_fpe_traps == NULL) {
230 return 1;
231 }
232 }
233 f_fpe_top_of_stack = -1;
234
235 /* initialize SIGINT stack */
236 if (f_int_traps == NULL) {
237 f_int_traps = (SigHandler *)asccalloc(MAX_TRAP_DEPTH,sizeof(SigHandler));
238 if (f_int_traps == NULL) {
239 ascfree(f_fpe_traps);
240 f_fpe_traps = NULL;
241 return 1;
242 }
243 }
244 f_int_top_of_stack = -1;
245
246 /* initialize SIGSEGV stack */
247 if (f_seg_traps == NULL) {
248 f_seg_traps = (SigHandler *)asccalloc(MAX_TRAP_DEPTH,sizeof(SigHandler));
249 if (f_seg_traps == NULL) {
250 ascfree(f_fpe_traps);
251 f_fpe_traps = NULL;
252 ascfree(f_int_traps);
253 f_int_traps = NULL;
254 return 1;
255 }
256 }
257 f_seg_top_of_stack = -1;
258
259 #ifndef NO_SIGNAL_TRAPS
260 /* push the old ones if any, on the stack. */
261 initstack(f_fpe_traps, &f_fpe_top_of_stack, SIGFPE);
262
263 # ifndef NO_SIGINT_TRAP
264 initstack(f_int_traps, &f_int_top_of_stack, SIGINT);
265 # endif
266
267 # ifndef NO_SIGSEGV_TRAP
268 initstack(f_seg_traps, &f_seg_top_of_stack, SIGSEGV);
269 # endif
270
271 f_reset_needed = ascresetneeded();
272 if (f_reset_needed < 0) {
273 f_reset_needed = 1;
274 return 2;
275 }
276 #endif /* NO_SIGNAL_TRAPS */
277 return 0;
278 }
279
280 /*
281 * clears and destroys the stacks of signal handlers.
282 */
283 void Asc_SignalDestroy(void)
284 {
285 ascfree(f_fpe_traps);
286 ascfree(f_int_traps);
287 ascfree(f_seg_traps);
288 f_fpe_traps = f_int_traps = f_seg_traps = NULL;
289 f_fpe_top_of_stack = f_int_top_of_stack = f_seg_top_of_stack = -1;
290 }
291
292 static void reset_trap(int signum, SigHandler *tlist, int tos)
293 {
294 SigHandler tp;
295 if ((tlist != NULL) && (tos >= 0) && (tos < MAX_TRAP_DEPTH)) {
296 tp = tlist[tos];
297 if (tp != SIG_ERR) {
298 (void)signal(signum,tp);
299 }
300 } else {
301 (void)signal(signum,SIG_DFL);
302 }
303 }
304 /* This function reinstalls all the signal handlers this module
305 * has been informed of. This should be called after every
306 * trapped exception and at any other time when the status of
307 * exception handlers may have become not well defined.
308 * The most recently pushed handler is installed for each supported
309 * signal. If nothing on stack, SIG_DFL gets installed.
310 *_Note that if somebody installs a handler without going through
311 * our push/pop, theirs is liable to be forgotten.
312 */
313 void Asc_SignalRecover(int force)
314 {
315 if (force || f_reset_needed > 0) {
316 #ifndef NO_SIGNAL_TRAPS
317 reset_trap(SIGFPE, f_fpe_traps, f_fpe_top_of_stack);
318 reset_trap(SIGINT, f_int_traps, f_int_top_of_stack);
319 reset_trap(SIGSEGV, f_seg_traps, f_seg_top_of_stack);
320 #endif /* NO_SIGNAL_TRAPS */
321 }
322 }
323
324 /*
325 * append a pointer to the list given, if the list is not full.
326 */
327 static int push_trap(SigHandler *tlist, int *stackptr, SigHandler tp)
328 {
329 if (tlist == NULL) {
330 CONSOLE_DEBUG("TLIST IS NULL");
331 return -1;
332 }
333 if (stackptr == NULL) {
334 CONSOLE_DEBUG("STACKPTR IS NULL");
335 return -1;
336 }
337 if (tp == NULL) {
338 CONSOLE_DEBUG("TP IS NULL");
339 return 2;
340 }
341 if (*stackptr > MAX_TRAP_DEPTH-1) {
342 CONSOLE_DEBUG("TLIST LENGTH = CAPACITY");
343 return 1;
344 }
345 ++(*stackptr);
346 tlist[*stackptr] = tp;
347 return 0;
348 }
349
350 /*
351 * Adds a handler to the stack of signal handlers for the given signal.
352 * There is a maximum stack limit, so returns 1 if limit exceeded.
353 * Returns -1 if stack of signal requested does not exist.
354 * Pushing a NULL handler does NOT change anything at all.
355 * On a successful return, the handler has been installed and will
356 * remain installed until a Asc_SignalHandlerPop or another push.
357 */
358 int Asc_SignalHandlerPush(int signum, SigHandler tp)
359 {
360 int err;
361 if (tp == NULL) {
362 return 0;
363 }
364 switch (signum) {
365 case SIGFPE:
366 /*ERROR_REPORTER_DEBUG("PUSH SIGFPE");*/
367 err = push_trap(f_fpe_traps, &f_fpe_top_of_stack, tp);
368 break;
369 case SIGINT:
370 /*ERROR_REPORTER_DEBUG("PUSH SIGINT");*/
371 err = push_trap(f_int_traps, &f_int_top_of_stack, tp);
372 break;
373 case SIGSEGV:
374 /*ERROR_REPORTER_DEBUG("PUSH SIGSEGV");*/
375 err = push_trap(f_seg_traps, &f_seg_top_of_stack, tp);
376 break;
377 default:
378 return -1;
379 }
380 if (err != 0) {
381 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"Asc_Signal (%d) stack limit exceeded.",signum);
382 return err;
383 }
384 (void)signal(signum, tp); /* install */
385 return 0;
386 }
387
388 /*
389 * Returns: 0 -ok, 2 NULL list input, 1 empty list input,
390 * -1 mismatched input tp and stack data.
391 */
392 static int pop_trap(SigHandler *tlist, int *stackptr, SigHandler tp)
393 {
394 SigHandler oldtrap;
395
396 if ((tlist == NULL) || (stackptr == NULL)) {
397 return 2;
398 }
399 if (*stackptr < 0) {
400 return 1;
401 }
402 oldtrap = tlist[*stackptr];
403 tlist[*stackptr] = NULL;
404 --(*stackptr);
405 return (-(oldtrap != tp));
406 }
407
408 int Asc_SignalHandlerPop(int signum, SigHandler tp)
409 {
410 int err;
411 switch (signum) {
412 case SIGFPE:
413 /*ERROR_REPORTER_DEBUG("POP SIGFPE");*/
414 err = pop_trap(f_fpe_traps, &f_fpe_top_of_stack, tp);
415 break;
416 case SIGINT:
417 /*ERROR_REPORTER_DEBUG("POP SIGINT");*/
418 err = pop_trap(f_int_traps, &f_int_top_of_stack, tp);
419 break;
420 case SIGSEGV:
421 /*ERROR_REPORTER_DEBUG("POP SIGSEGV");*/
422 err = pop_trap(f_seg_traps, &f_seg_top_of_stack, tp);
423 break;
424 default:
425 CONSOLE_DEBUG("popping invalid signal type (signum = %d)", signum);
426 return -1;
427 }
428 if (err != 0 && tp != NULL) {
429 CONSOLE_DEBUG("stack pop mismatch");
430 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"Asc_Signal (%d) stack pop mismatch.",signum);
431 return err;
432 }
433 Asc_SignalRecover(TRUE);
434 return 0;
435 }
436
437 void Asc_SignalTrap(int sigval) {
438 #ifndef NO_SIGNAL_TRAPS
439 switch(sigval) {
440 case SIGFPE:
441 CONSOLE_DEBUG("SIGFPE caught");
442 FPRESET;
443 longjmp(g_fpe_env,sigval);
444 break;
445 case SIGINT:
446 CONSOLE_DEBUG("SIGINT (Ctrl-C) caught");
447 longjmp(g_int_env,sigval);
448 break;
449 case SIGSEGV:
450 CONSOLE_DEBUG("SIGSEGV caught");
451 longjmp(g_seg_env,sigval);
452 break;
453 default:
454 CONSOLE_DEBUG("Installed on unexpected signal (sigval = %d).", sigval);
455 CONSOLE_DEBUG("Returning ... who knows where :-)");
456 break;
457 }
458 return;
459 #else
460 UNUSED_PARAMETER(sigval);
461 #endif /* NO_SIGNAL_TRAPS */
462 }

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22