/[ascend]/trunk/ascend/utilities/ascSignal.h
ViewVC logotype

Contents of /trunk/ascend/utilities/ascSignal.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2011 - (show annotations) (download) (as text)
Tue Apr 28 08:58:48 2009 UTC (15 years, 8 months ago) by jpye
File MIME type: text/x-chdr
File size: 12460 byte(s)
Moving libascend components from #/base/generic into #/ascend
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 @file
21 Signal handling protocol definitions for ASCEND.
22
23 This file standardizes the handling of signals because some OS
24 reset signals to SIG_DFL when a trap goes off while others
25 process the signal but leave the trapping function in place.
26 We want the second behavior and this gives it to us.
27
28 This module implements limited support for managing signal handlers.
29 This includes:
30 - a standard signal handler - Asc_SignalTrap()
31 - global jmp_buf's for use with Asc_SignalTrap()
32 - functions for managing nested signal handlers
33
34 The following signal types are currently supported:
35 - SIGFPE - floating point exception
36 - SIGINT - CTRL-C interactive attention request
37 - SIGSEGV - segmentation fault
38
39 A simple use of these facilities to trap floating point exceptions
40 might be as follows:
41 <pre>
42 Asc_SignalInit();
43 Asc_SignalHandlerPush(SIGFPE, Asc_SignalTrap);
44 if (setjmp(g_fpe_env)==0) {
45 y = sqrt(x);
46 } else {
47 y = sqrt(-x);
48 }
49 Asc_SignHandlerPop(SIGFPE,Asc_SignalTrap);
50 Asc_SignalDestroy();
51 </pre>
52
53 This example uses the built-in signal handler Asc_SignalTrap()
54 and the global <code>jmp_buf</code> g_fpe_env. After initializing
55 the signal manager and registering the handler, <code>setjmp</code>
56 is used to select normal and exception paths. The <code>setjmp</code>
57 returns 0 when initially called and the sqrt(x) is calculated. If
58 x is negative, a SIGFPE exception occurs and the handler is called. It
59 uses <code>lngjmp</code> and returns to the if statement, and now
60 'setjmp' returns non-zero and the <code>else</code> clause is executed.
61 Finally, the handler is removed and the signal manager cleaned up.<br><br>
62
63 The stack mechanism also allows nested handlers to be registered. It is
64 important to note that nested handlers for the same signal type cannot
65 both use Asc_SignalTrap() as the handler. This is because different
66 <code>jmp_buf</code> variables must be used and Asc_SignalTrap() uses
67 the same global <code>jmp_buf</code> each time. However, you can use
68 custome <code>jmp_buf</code>'s and handlers:
69
70 <pre>
71 Asc_SignalInit();
72 Asc_SignalHandlerPush(SIGFPE, Asc_SignalTrap);
73 if (setjmp(g_fpe_env) == 0) {
74 y = sqrt(x);
75 Asc_SignalHandlerPush(SIGFPE, my_handler);
76 if (setjmp(my_jmp_buf) == 0) {
77 y = z/x;
78 } else {
79 Asc_Panic(1, NULL, "Div by zero error.");
80 }
81 Asc_SignHandlerPop(SIGFPE, my_handler);
82 } else {
83 y = sqrt(-x);
84 }
85 Asc_SignHandlerPop(SIGFPE,Asc_SignalTrap);
86 Asc_SignalDestroy();
87 </pre>
88
89 Here, exceptions in the sqrt(x) calculation are handled by the standard
90 Asc_SignalTrap(), while the division is handled by my_handler.<br><br>
91
92 Avoid mixing use of the signal manager with direct calls to signal().
93 Once Asc_SignalInit() has been called, use of signal() directly is likely
94 to be lost or to corrupt the managed handlers.<br><br>
95
96 Another warning: setjmp is expensive if called inside a fast loop.
97
98 Requires:
99 #include "utilities/ascConfig.h"
100 *//*
101 by Benjamin Andrew Allan, May 27, 1997
102 Last in CVS: $Revision: 1.6 $ $Date: 1998/01/10 18:00:05 $ $Author: ballan $
103 */
104
105 #ifndef ASC_ASCSIGNAL_H
106 #define ASC_ASCSIGNAL_H
107
108 #include "config.h"
109 #ifndef ASC_SIGNAL_TRAPS
110
111 /* if our wizzband PITA signal handing isn't turned on, at least allow
112 use of feenableexcept(FE_EXCEPT_ALL) here and there.
113 */
114 # ifndef ASC_SIGNAL_TRAPS
115 # ifdef HAVE_C99FPE
116 # if __GNUC__ && !defined(_GNU_SOURCE)
117 # define _GNU_SOURCE /* enables feenableexcept (http://gcc.gnu.org/ml/fortran/2005-10/msg00365.html) */
118 # endif
119 # include <fenv.h>
120 # endif
121 # endif
122
123 #else
124 /*-------------- rest of file is conditional on ASC_SIGNAL_TRAPS--------------*/
125
126 #include "ascConfig.h"
127
128 #include <general/except.h>
129
130 #include <signal.h>
131
132 #ifdef __WIN32__
133 # include <process.h>
134 #else
135 # include <unistd.h>
136 #endif
137
138 #ifdef __WIN32__
139 # define FPRESET _fpreset()
140 #else
141 # define FPRESET (void)0
142 #endif
143
144 typedef void SigHandlerFn(int);
145 /**< Signature of a signal handling function. */
146
147 #define MAX_TRAP_DEPTH 40L
148 /**< The maximum number of traps that can be nested. */
149
150 ASC_DLLSPEC JMP_BUF g_fpe_env; /**< Standard signal jmp_buf - floating point error. */
151 ASC_DLLSPEC JMP_BUF g_seg_env; /**< Standard signal jmp_buf - segmentation fault. */
152 ASC_DLLSPEC JMP_BUF g_int_env; /**< Standard signal jmp_buf - interactive attention (<CTRL>C). */
153
154 #if 0
155 extern jmp_buf g_foreign_code_call_env;
156 /**<
157 Not currently in use. Should be when we get to a unified
158 standard for signal handling.
159 @todo Implement use of g_foreign_code_call_env?
160 */
161 #endif
162
163 ASC_DLLSPEC void Asc_SignalTrap(int sigval);
164 /**<
165 * Standard signal handler.
166 * This is the trap that should be used for most applications in
167 * ASCEND. It prints a message then calls longjmp(GLOBAL, sigval)
168 * where GLOBAL is one of g_fpe_env, g_seg_env, or g_int_env.
169 * Because the jmp_buf is global, so you can't nest calls to
170 * setjmp where both use this trap function.<br><br>
171 *
172 * Trivial Example:
173 * <pre>
174 * Asc_SignalHandlerPush(SIGFPE,Asc_SignalTrap);
175 * if (setjmp(g_fpe_env)==0) {
176 * y = sqrt(x);
177 * } else {
178 * y = sqrt(-x);
179 * }
180 * Asc_SignHandlerPop(SIGFPE,Asc_SignalTrap);
181 *
182 * For x < 0 the else is called because setjmp returns nonzero
183 * when the body of the 'if' signals range error.
184 * </pre>
185 * Remember always to use Asc_SignalHandlerPush() and
186 * Asc_SignalHandlerPop(). You can write an alternate function
187 * to use instead of AscSignalTrap() if need be. The signals
188 * SIGFPE, SIGINT, SIGSEGV are understood.<br><br>
189 *
190 * Note - this handler does not reinstall itself. After an exception,
191 * you need to reinstall the handler (if desired) using
192 * Asc_SignalRecover().
193 *
194 * @todo Should utilities/ascSignal.c:Asc_SignalTrap() reinstall itself
195 * after it catches an expection using Asc_SignalRecover()?
196 * @param sigval Holds the signal type code when called during
197 * an exception.
198 */
199
200 ASC_DLLSPEC int Asc_SignalInit(void);
201 /**<
202 * Initializes the signal manager.
203 * This should be called before using any of the signal handling
204 * functions in this module. It initializes the internal stacks
205 * for mangaging signal handlers. This function does not install
206 * any signal handlers (although any existing handlers are left
207 * in place). Calling this function more than once will have no
208 * effect and an error code will be returned.<br><br>
209 *
210 * @return Returns 0 if successful, 1 if memory could not be
211 * allocated, and 2 if an error occurred.
212 */
213
214 ASC_DLLSPEC void Asc_SignalDestroy(void);
215 /**<
216 * Cleans up and destroys the stacks of signal handlers.
217 * It does not change the status of any registered signal handlers
218 * That is, any handlers registered when this function is called
219 * will still be registered. It is important to call
220 * Asc_SignalHandlerPop() for each occurrence of Asc_SignalHandlerPush()
221 * before calling this function. Otherwise, any signal handlers
222 * that were installed before Asc_SignalInit() was called will be lost.
223 */
224
225 ASC_DLLSPEC void Asc_SignalRecover(int force);
226 /**<
227 * Reinstalls the most recently pushed handler that has been
228 * installed for each supported signal type. This should be called
229 * after every trapped exception and at any other time when the
230 * status of exception handlers may have become not well-defined.
231 * If no handler has been pushed for a given signal type, SIG_DFL is
232 * installed. Note that the standard handler function Asc_SignalTrap()
233 * does not call this function. If you use the standard handler and
234 * you want it reinstalled after an exception, be sure to call this
235 * function after the longjmp return. This call is not particularly
236 * cheap if it does the reinstallation.<br><br>
237 *
238 * This module tests on startup for whether the OS reverts to
239 * SIG_DFL when a trap function is called. If it does NOT then
240 * this function will simply return unless force != 0. You don't
241 * want to call this function with force == 1 normally after a
242 * caught exception. However, if you're not sure of the handler
243 * installation status and want to make sure the handlers are
244 * installed, call with force == 1. Also, gdb or other
245 * debuggers which intercept and screw up signals may require
246 * applying force (manually) to ensure that the signals get
247 * reinstalled.
248 *
249 * @param force If non-zero, the most recent handlers are
250 * reinstalled even if not required by the
251 * compiler/platform.
252 */
253
254 ASC_DLLSPEC int Asc_SignalHandlerPushDefault(int signum);
255 ASC_DLLSPEC int Asc_SignalHandlerPush(int signum, SigHandlerFn *func);
256 /**<
257 * Adds a handler to the stack of signal handlers for the given signal.
258 * There is a maximum stack limit, so returns 1 if limit exceeded.
259 * Returns -1 if stack of signal requested does not exist.
260 * Pushing a NULL handler func does NOT change anything at all.
261 * On a successful return, the handler has been installed and will
262 * remain installed until a Asc_SignalHandlerPop() or another push.
263 * The handler will remain installed as long as Asc_SignalRecover()
264 * is used properly after every exception.
265 *
266 * @param signum The signal type that func should handle.
267 * @param func The signal handler to register for signum signal types.
268 * @return Returns 1 if the stack limit is exceeded, -1 if managing
269 * of signals for the specified signum is not supported or
270 * initialized, or 0 if the function completes successfully.
271 * @todo Shouldn't utilities/ascSignal.c:Asc_SignalHandlerPush() return
272 * an error code on a NULL func? It seems too easy for someone to
273 * accidentally push a NULL without realizing it, and then later
274 * popping an unintended handler.
275 */
276
277 ASC_DLLSPEC int Asc_SignalHandlerPopDefault(int signum);
278 ASC_DLLSPEC int Asc_SignalHandlerPop(int signum, SigHandlerFn *func);
279 /**<
280 * Removes the last-pushed handler from the stack for signum signal types.
281 * If the removed handler is the same as func, it is uninstalled and
282 * replaced with the handler now at the top of the stack. If not, non-zero
283 * is returned and you need to call Asc_SignalRecover() to uninstall the
284 * current handler if desired. Note that the top handler is popped off
285 * the stack whether it matches func or not. Non-zero is also returned if
286 * the stack is empty. A side effect is that all managed signal types will
287 * have the registered handlers reinstalled.
288 *
289 * @param signum The signal type whose top-most handler should be replaced.
290 * @param func The handler function that should be at the top of the
291 * stack (and currently installed) for signals of type signum.
292 * @return Returns non-zero if func is not the replaced handler or if
293 * the stack is empty, 0 if the function completed successfully.
294 * @todo Does it make more sense for utilities/ascSignal.c:Asc_SignalHanderPop()
295 * to fail completely if func is not the top-most handler? It is not
296 * clear why the function should pop the top handler no matter what, but
297 * only call Asc_SignalRecover() if it matches func.
298 */
299
300 /** Output the contents of the specified stack. For debugging. */
301 ASC_DLLSPEC void Asc_SignalPrintStack(int signum);
302
303 /** Return the length of the specified stack. For debugging. */
304 ASC_DLLSPEC int Asc_SignalStackLength(int signum);
305
306 /** For debugging.
307 @return handler at top of specified stack, or NULL if stack is empty.
308 */
309 ASC_DLLSPEC SigHandlerFn *Asc_SignalStackTop(int signum);
310
311 #endif /* ASC_SIGNAL_TRAPS */
312
313 #endif /* ASC_ASCSIGNAL_H */
314

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