/[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 61 - (show annotations) (download) (as text)
Mon Nov 14 02:37:20 2005 UTC (18 years, 10 months ago) by jds
File MIME type: text/x-csrc
File size: 10349 byte(s)
Minor bug fixes, extend unit tests to solver:

minor doc changes - compiler/func.h, general/list.h, solver/mtx.h, utilities/mem.h
solver/example - upgraded examples so they run under current system
solver/slv_common.[ch] - added unit tests, minor bug fixes, extended vector_data functions
utilities/ascDynaLoad.c - bug fix on *nix so dlopen, dlsym not called with NULL arguments
1 /*
2 * Signal handling protocol definitions for ASCEND
3 * May 27, 1997
4 * By Benjamin Andrew Allan
5 * Version: $Revision: 1.9 $
6 * Version control file: $RCSfile: ascSignal.c,v $
7 * Date last modified: $Date: 1999/01/19 12:23:20 $
8 * Last modified by: $Author: mthomas $
9 * Part of Ascend
10 *
11 * This file is part of the Ascend Programming System.
12 *
13 * Copyright (C) 1997 Benjamin Andrew Allan
14 *
15 * The Ascend Programming System is free software; you can redistribute
16 * it and/or modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of the
18 * License, or (at your option) any later version.
19 *
20 * ASCEND is distributed in hope that it will be
21 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with the program; if not, write to the Free Software Foundation,
27 * Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named
28 * COPYING.
29 *
30 */
31 /*
32 * Start of making signal handling in ASCEND
33 * code somewhat sane. Still needs to somehow
34 * support the management of jmp_buf's so that
35 * handlers will longjmp to the right place.
36 *
37 * A better alternative is to make all our code check/return
38 * status flags based on a variable set by the trap
39 * and cleared by recipient.
40 */
41 /*
42 * ChangeLog
43 *
44 * 10/15/2005 - Changed ascresetneeded() so that any previously
45 * registered handlers are reset before return.
46 * - Added Asc_SignalRecover() to standard handler
47 * Asc_SignalTrap() so handlers are reset if necessary. (JDS)
48 */
49
50 #include <stdio.h>
51 #include "utilities/ascConfig.h"
52 #ifndef NO_SIGNAL_TRAPS
53 #include <signal.h>
54 #include <setjmp.h>
55 #endif /* NO_SIGNAL_TRAPS*/
56 #ifdef __WIN32__
57 #include <process.h>
58 #else
59 #include <unistd.h>
60 #endif
61 #include "utilities/ascSignal.h"
62 #include "general/list.h"
63
64
65 static jmp_buf f_test_env; /* for local testing of signal handling */
66
67 #ifndef NO_SIGNAL_TRAPS
68 /* test buf for initialization */
69 jmp_buf g_fpe_env;
70 jmp_buf g_seg_env;
71 jmp_buf g_int_env;
72
73 /* for future use */
74 jmp_buf g_foreign_code_call_env;
75
76 #endif /* NO_SIGNAL_TRAPS*/
77
78 static int f_reset_needed = -2;
79 /* has value 0 or 1 after Init is called.
80 * and if Init is called without the value -2 in f_reset_needed,
81 * it will fail.
82 */
83 static struct gl_list_t *f_fpe_traps = NULL;
84 static struct gl_list_t *f_int_traps = NULL;
85 static struct gl_list_t *f_seg_traps = NULL;
86 /*
87 * Batch of globals because we don't want an array of
88 * all possible signals, most of which are NULL entries.
89 * Each list holds the stack of pointers to signal handlers.
90 */
91
92 /* function to throw an interrupt. system dependent. */
93 static int testdooley2(int sig)
94 {
95 raise(sig);
96
97 return 0;
98 }
99
100 /* function to catch an interrupt */
101 static void testctrlc(int signum)
102 {
103 FPRINTF(ASCERR," signal %d caught ",signum);
104 if (signum == SIGFPE) {
105 FPRESET;
106 }
107 longjmp(f_test_env, signum);
108 }
109
110 /*
111 * So far the following seem to need reset trapped signals after
112 * a longjmp, or unconditionally.
113 * HPUX cc -Aa -D_HPUX_SOURCE
114 * Solaris cc
115 * AIX xlc
116 * IRIX cc
117 * Windows
118 *
119 * The following retain the last trap set with or without a call to longjmp
120 * and so don't need resetting of traps.
121 * SunOS4 acc
122 * OSF32 cc
123 * NetBSD gcc 2.4.5 -ansi
124 */
125 /* This function tests the signal reseting of compilers using SIGINT.
126 * It should not be called except when starting a process.
127 * Return 0 for no reset needed, 1 for reset needed, and
128 * -1 if the test fails (presuming program doesn't exit first.)
129 * Side effects:
130 * - a line is sent to ASCERR
131 * - SIGINT is set to SIG_DFL if no handler was previously registered
132 * - SIGFPE may be set to SIG_DFL if no handler was previously registered
133 */
134 static int ascresetneeded(void) {
135 static int c=0;
136 static int result;
137 SigHandler lasttrap;
138 volatile SigHandler savedtrap;
139
140 result = 0;
141
142 /* test interrupt */
143 savedtrap = signal(SIGINT, testctrlc);
144 PRINTF("Testing signal %d %p\t%p\t", SIGINT, savedtrap, testctrlc);
145 if (setjmp(f_test_env) == 0) {
146 testdooley2(SIGINT);
147 } else {
148 c++;
149 }
150 if (c != 1) {
151 PRINTF("Signal test failed. ASCEND unlikely to work on this hardware.\n");
152 result = -1;
153 }
154 lasttrap = signal(SIGINT, (NULL != savedtrap) ? savedtrap : SIG_DFL);
155 PRINTF("%p\n",lasttrap);
156 if (lasttrap != testctrlc) {
157 result = 1;
158 }
159
160 if (result != 0) {
161 return result;
162 }
163
164 c = 0;
165 /* passed interrupt, check fpe */
166 savedtrap=signal(SIGFPE, testctrlc);
167 PRINTF("Testing signal %d %p\t%p\t",SIGFPE, savedtrap, testctrlc);
168 if (setjmp(f_test_env)==0) {
169 testdooley2(SIGFPE);
170 } else {
171 c++;
172 }
173 if (c != 1) {
174 PRINTF("Signal test failed. ASCEND unlikely to work on this hardware.\n");
175 result = -1;
176 }
177 lasttrap = signal(SIGFPE, (NULL != savedtrap) ? savedtrap : SIG_DFL);
178 PRINTF("%p\n",lasttrap);
179 if (lasttrap != testctrlc) {
180 result = 1;
181 }
182
183 return result;
184 }
185
186 static
187 void initstack (struct gl_list_t *traps, int sig)
188 {
189 SigHandler old;
190 old = signal(sig,SIG_DFL);
191 if (old != SIG_ERR && old != SIG_DFL) {
192 gl_append_ptr(traps,(VOIDPTR)old);
193 (void)signal(sig,old);
194 }
195 }
196 /*
197 * Returns 0 if successful, 1 if out of memory, 2 otherwise.
198 * Does not establish any traps, just the structures for
199 * maintaining them. Pushes the existing traps, if any, on
200 * the bottom of the created stacks.
201 * Cannot be called twice successfully.
202 */
203 int Asc_SignalInit(void)
204 {
205 if ((f_reset_needed != -2) || (FALSE == gl_pool_initialized())) {
206 return 2;
207 }
208 f_fpe_traps = gl_create(MAX_TRAP_DEPTH);
209 f_int_traps = gl_create(MAX_TRAP_DEPTH);
210 f_seg_traps = gl_create(MAX_TRAP_DEPTH);
211 if (f_fpe_traps == NULL || f_int_traps == NULL || f_seg_traps == NULL) {
212 return 1;
213 }
214 #ifndef NO_SIGNAL_TRAPS
215 /* push the old ones if any, on the stack. */
216 initstack(f_fpe_traps, SIGFPE);
217 initstack(f_int_traps, SIGINT);
218 initstack(f_seg_traps, SIGSEGV);
219
220 f_reset_needed = ascresetneeded();
221 if (f_reset_needed < 0) {
222 f_reset_needed = 1;
223 return 2;
224 }
225 #endif /* NO_SIGNAL_TRAPS */
226 return 0;
227 }
228
229 /*
230 * clears and destroys the stacks of signal handlers.
231 */
232 void Asc_SignalDestroy(void)
233 {
234 gl_destroy(f_fpe_traps);
235 gl_destroy(f_int_traps);
236 gl_destroy(f_seg_traps);
237 f_fpe_traps = f_int_traps = f_seg_traps = NULL;
238 }
239
240 static void reset_trap(int signum, struct gl_list_t *tlist)
241 {
242 SigHandler tp;
243 if (tlist != NULL && gl_length(tlist) > 0L) {
244 tp = (SigHandler)gl_fetch(tlist, gl_length(tlist));
245 if (tp != SIG_ERR) {
246 (void)signal(signum,tp);
247 }
248 } else {
249 (void)signal(signum,SIG_DFL);
250 }
251 }
252 /* This function reinstalls all the signal handlers this module
253 * has been informed of. This should be called after every
254 * trapped exception and at any other time when the status of
255 * exception handlers may have become not well defined.
256 * The most recently pushed handler is installed for each supported
257 * signal. If nothing on stack, SIG_DFL gets installed.
258 *_Note that if somebody installs a handler without going through
259 * our push/pop, theirs is liable to be forgotten.
260 */
261 void Asc_SignalRecover(int force) {
262 if (force || f_reset_needed > 0) {
263 #ifndef NO_SIGNAL_TRAPS
264 reset_trap(SIGFPE, f_fpe_traps);
265 reset_trap(SIGINT, f_int_traps);
266 reset_trap(SIGSEGV, f_seg_traps);
267 #endif /* NO_SIGNAL_TRAPS */
268 }
269 }
270
271 /*
272 * append a pointer to the list given, if the list is not full.
273 */
274 static int push_trap(struct gl_list_t *tlist, SigHandler tp)
275 {
276 if (tlist == NULL) {
277 return -1;
278 }
279 if (gl_length(tlist) == gl_capacity(tlist)) {
280 return 1;
281 }
282 gl_append_ptr(tlist,(VOIDPTR)tp);
283 return 0;
284 }
285
286 /*
287 * Adds a handler to the stack of signal handlers for the given signal.
288 * There is a maximum stack limit, so returns 1 if limit exceeded.
289 * Returns -1 if stack of signal requested does not exist.
290 * Pushing a NULL handler does NOT change anything at all.
291 * On a successful return, the handler has been installed and will
292 * remain installed until a Asc_SignalHandlerPop or another push.
293 */
294 int Asc_SignalHandlerPush(int signum, SigHandler tp)
295 {
296 int err;
297 if (tp == NULL) {
298 return 0;
299 }
300 switch (signum) {
301 case SIGFPE:
302 err = push_trap(f_fpe_traps,tp);
303 break;
304 case SIGINT:
305 err = push_trap(f_int_traps,tp);
306 break;
307 case SIGSEGV:
308 err = push_trap(f_seg_traps,tp);
309 break;
310 default:
311 return -1;
312 }
313 if (err != 0) {
314 FPRINTF(ASCERR,"Asc_Signal (%d) stack limit exceeded.\n",signum);
315 return err;
316 }
317 (void)signal(signum, tp); /* install */
318 return 0;
319 }
320
321 /*
322 * Returns: 0 -ok, 2 NULL list input, 1 empty list input,
323 * -1 mismatched input tp and stack data.
324 */
325 static int pop_trap(struct gl_list_t *tlist, SigHandler tp)
326 {
327 SigHandler oldtrap;
328
329 if (tlist == NULL) {
330 return 2;
331 }
332 if (gl_length(tlist) == 0) {
333 return 1;
334 }
335 oldtrap = (SigHandler)gl_fetch(tlist,gl_length(tlist));
336 gl_delete(tlist,gl_length(tlist),0);
337 return (-(oldtrap != tp));
338 }
339
340 int Asc_SignalHandlerPop(int signum, SigHandler tp)
341 {
342 int err;
343 switch (signum) {
344 case SIGFPE:
345 err = pop_trap(f_fpe_traps,tp);
346 break;
347 case SIGINT:
348 err = pop_trap(f_int_traps,tp);
349 break;
350 case SIGSEGV:
351 err = pop_trap(f_seg_traps,tp);
352 break;
353 default:
354 return -1;
355 }
356 if (err != 0 && tp != NULL) {
357 FPRINTF(ASCERR,"Asc_Signal (%d) stack pop mismatch.\n",signum);
358 return err;
359 }
360 Asc_SignalRecover(TRUE);
361 return 0;
362 }
363
364 void Asc_SignalTrap(int sigval) {
365 #ifndef NO_SIGNAL_TRAPS
366 switch(sigval) {
367 case SIGFPE:
368 FPRINTF(ASCERR,"Asc_SignalTrap: SIGFPE caught\n");
369 FPRESET;
370 longjmp(g_fpe_env,sigval);
371 break;
372 case SIGINT:
373 FPRINTF(ASCERR,"Asc_SignalTrap: SIGINT (Ctrl-C) caught\n");
374 longjmp(g_int_env,sigval);
375 break;
376 case SIGSEGV:
377 FPRINTF(ASCERR,"Asc_SignalTrap: SIGSEGV (bad address) caught\n");
378 longjmp(g_seg_env,sigval);
379 break;
380 default:
381 FPRINTF(ASCERR,"Asc_SignalTrap: Installed on unexpected signal (# %d).\n", sigval);
382 FPRINTF(ASCERR,"Asc_SignalTrap: Returning ... who knows where.");
383 break;
384 }
385 return;
386 #else
387 UNUSED_PARAMETER(sigval);
388 #endif /* NO_SIGNAL_TRAPS */
389 }

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