/[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 804 - (show annotations) (download) (as text)
Fri Aug 4 05:54:34 2006 UTC (13 years, 5 months ago) by johnpye
File MIME type: text/x-csrc
File size: 12658 byte(s)
In slv9, made changes to keep CONOPT from complaining. CMSlv still not working as expected though.
Decreased required version of Bison to 2.0.
Switched search path for CONOPT on Linux to the CONOPT_PATH env var
(LD_LIBRARY_PATH was being interfered with when ASC_DEV=1).
Some other debug message changes.
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.");
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 = ASC_NEW_ARRAY_CLEAR(SigHandler,MAX_TRAP_DEPTH);
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 = ASC_NEW_ARRAY_CLEAR(SigHandler,MAX_TRAP_DEPTH);
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 = ASC_NEW_ARRAY_CLEAR(SigHandler,MAX_TRAP_DEPTH);
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