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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 101 - (show annotations) (download) (as text)
Sat Dec 10 04:22:07 2005 UTC (15 years, 4 months ago) by jds
File MIME type: text/x-chdr
File size: 12436 byte(s)
A little more progress killing compiler warnings.
1 /*
2 * Signal handling protocol definitions for ASCEND
3 * May 27, 1997
4 * By Benjamin Andrew Allan
5 * Version: $Revision: 1.6 $
6 * Version control file: $RCSfile: ascSignal.h,v $
7 * Date last modified: $Date: 1998/01/10 18:00:05 $
8 * Last modified by: $Author: ballan $
9 * Part of Ascend
10 *
11 * This file is part of the Ascend Programming System.
12 * This file standardizes the handling of signals because some OS
13 * reset signals to SIG_DFL when a trap goes off while others
14 * process the signal but leave the trapping function in place.
15 * We want the second behavior and this gives it to us.
16 *
17 * Copyright (C) 1997 Benjamin Andrew Allan
18 *
19 * The Ascend Programming System is free software; you can redistribute
20 * it and/or modify it under the terms of the GNU General Public License as
21 * published by the Free Software Foundation; either version 2 of the
22 * License, or (at your option) any later version.
23 *
24 * ASCEND is distributed in hope that it will be
25 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with the program; if not, write to the Free Software Foundation,
31 * Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named
32 * COPYING.
33 */
34
35 /** @file
36 * Signal handling protocol definitions for ASCEND.
37 *
38 * This module implements limited support for managing signal handlers.
39 * This includes:
40 * - a standard signal handler - Asc_SignalTrap()
41 * - global jmp_buf's for use with Asc_SignalTrap()
42 * - functions for managing nested signal handlers
43 *
44 * The following signal types are currently supported:
45 * - SIGFPE - floating point exception
46 * - SIGINT - CTRL-C interactive attention request
47 * - SIGSEGV - segmentation fault
48 *
49 * The signal handler manager uses gl_list_t lists, so the list
50 * system must be initialized before calling Asc_SignalInit().<br><br>
51 *
52 * A simple use of these facilities to trap floating point exceptions
53 * might be as follows:
54 * <pre>
55 * Asc_SignalInit();
56 * Asc_SignalHandlerPush(SIGFPE, Asc_SignalTrap);
57 * if (setjmp(g_fpe_env)==0) {
58 * y = sqrt(x);
59 * } else {
60 * y = sqrt(-x);
61 * }
62 * Asc_SignHandlerPop(SIGFPE,Asc_SignalTrap);
63 * Asc_SignalDestroy();
64 * </pre>
65 * This example uses the built-in signal handler Asc_SignalTrap()
66 * and the global <code>jmp_buf</code> g_fpe_env. After initializing
67 * the signal manager and registering the handler, <code>setjmp</code>
68 * is used to select normal and exception paths. The <code>setjmp</code>
69 * returns 0 when initially called and the sqrt(x) is calculated. If
70 * x is negative, a SIGFPE exception occurs and the handler is called. It
71 * uses <code>lngjmp</code> and returns to the if statement, and now
72 * <setjmp> returns non-zero and the <code>else</code> clause is executed.
73 * Finally, the handler is removed and the signal manager cleaned up.<br><br>
74 *
75 * The stack mechanism also allows nested handlers to be registered. It is
76 * important to note that nested handlers for the same signal type cannot
77 * both use Asc_SignalTrap() as the handler. This is because different
78 * <code>jmp_buf</code> variables must be used and Asc_SignalTrap() uses
79 * the same global <code>jmp_buf</code> each time. However, you can use
80 * custome <code>jmp_buf</code>'s and handlers:
81 * <pre>
82 * Asc_SignalInit();
83 * Asc_SignalHandlerPush(SIGFPE, Asc_SignalTrap);
84 * if (setjmp(g_fpe_env) == 0) {
85 * y = sqrt(x);
86 * Asc_SignalHandlerPush(SIGFPE, my_handler);
87 * if (setjmp(my_jmp_buf) == 0) {
88 * y = z/x;
89 * } else {
90 * Asc_Panic(1, NULL, "Div by zero error.");
91 * }
92 * Asc_SignHandlerPop(SIGFPE, my_handler);
93 * } else {
94 * y = sqrt(-x);
95 * }
96 * Asc_SignHandlerPop(SIGFPE,Asc_SignalTrap);
97 * Asc_SignalDestroy();
98 * </pre>
99 * Here, exceptions in the sqrt(x) calculation are handled by the standard
100 * Asc_SignalTrap(), while the division is handled by my_handler.<br><br>
101 *
102 * Avoid mixing use of the signal manager with direct calls to signal().
103 * Once Asc_SignalInit() has been called, use of signal() directly is likely
104 * to be lost or to corrupt the managed handlers.<br><br>
105 *
106 * Another warning: setjmp is expensive if called inside a fast loop.
107 * <pre>
108 * Requires: #include "utilities/ascConfig.h"
109 * </pre>
110 * @todo utilities/ascSignal stores function pointers in gl_lists as data
111 * pointers (i.e. VOIDPTR). These are not guaranteed interchangable
112 * and so arrays of function pointers or some other conforming
113 * implementation should be used.
114 */
115
116 #ifndef ASC_ASCSIGNAL_H
117 #define ASC_ASCSIGNAL_H
118
119 #ifndef lint
120 static CONST char ascSignalRCS[] = "$Id: ascSignal.h,v 1.6 1998/01/10 18:00:05 ballan Exp $";
121 #endif
122
123 #include <signal.h>
124 #include <setjmp.h>
125 #include "utilities/ascConfig.h"
126 #ifdef __WIN32__
127 #include <process.h>
128 #else
129 #include <unistd.h>
130 #endif
131 #include "general/list.h"
132
133 typedef void (*SigHandler)(int);
134 /**< Signature of a signal handling function. */
135
136 #define MAX_TRAP_DEPTH 40L
137 /**< The maximum number of traps that can be nested. */
138
139 extern jmp_buf g_fpe_env; /**< Standard signal jmp_buf - floating point error. */
140 extern jmp_buf g_seg_env; /**< Standard signal jmp_buf - segmentation fault. */
141 extern jmp_buf g_int_env; /**< Standard signal jmp_buf - interactive attention (<CTRL>C). */
142
143 extern jmp_buf g_foreign_code_call_env;
144 /**<
145 * Not currently in use. Should be when we get to a unified
146 * standard for signal handling.
147 * @todo Implement use of g_foreign_code_call_env?
148 */
149
150 extern void Asc_SignalTrap(int sigval);
151 /**<
152 * Standard signal handler.
153 * This is the trap that should be used for most applications in
154 * ASCEND. It prints a message then calls longjmp(GLOBAL, sigval)
155 * where GLOBAL is one of g_fpe_env, g_seg_env, or g_int_env.
156 * Because the jmp_buf is global, so you can't nest calls to
157 * setjmp where both use this trap function.<br><br>
158 *
159 * Trivial Example:
160 * <pre>
161 * Asc_SignalHandlerPush(SIGFPE,Asc_SignalTrap);
162 * if (setjmp(g_fpe_env)==0) {
163 * y = sqrt(x);
164 * } else {
165 * y = sqrt(-x);
166 * }
167 * Asc_SignHandlerPop(SIGFPE,Asc_SignalTrap);
168 *
169 * For x < 0 the else is called because setjmp returns nonzero
170 * when the body of the 'if' signals range error.
171 * </pre>
172 * Remember always to use Asc_SignalHandlerPush() and
173 * Asc_SignalHandlerPop(). You can write an alternate function
174 * to use instead of AscSignalTrap() if need be. The signals
175 * SIGFPE, SIGINT, SIGSEGV are understood.<br><br>
176 *
177 * Note - this handler does not reinstall itself. After an exception,
178 * you need to reinstall the handler (if desired) using
179 * Asc_SignalRecover().
180 *
181 * @todo Should utilities/ascSignal.c:Asc_SignalTrap() reinstall itself
182 * after it catches an expection using Asc_SignalRecover()?
183 * @param sigval Holds the signal type code when called during
184 * an exception.
185 */
186
187 extern int Asc_SignalInit(void);
188 /**<
189 * Initializes the signal manager.
190 * This should be called before using any of the signal handling
191 * functions in this module. It initializes the internal stacks
192 * for mangaging signal handlers. This function does not install
193 * any signal handlers (although any existing handlers are left
194 * in place). Calling this function more than once will have no
195 * effect and an error code will be returned.<br><br>
196 *
197 * The signal handler manager uses gl_list_t lists, so the list
198 * system must be initialized before calling Asc_SignalInit().
199 *
200 * @return Returns 0 if successful, 1 if memory could not be
201 * allocated, and 2 if an error occurred.
202 */
203
204 extern void Asc_SignalDestroy(void);
205 /**<
206 * Cleans up and destroys the stacks of signal handlers.
207 * It does not change the status of any registered signal handlers
208 * That is, any handlers registered when this function is called
209 * will still be registered. It is important to call
210 * Asc_SignalHandlerPop() for each occurrence of Asc_SignalHandlerPush()
211 * before calling this function. Otherwise, any signal handlers
212 * that were installed before Asc_SignalInit() was called will be lost.
213 */
214
215 extern void Asc_SignalRecover(int force);
216 /**<
217 * Reinstalls the most recently pushed handler that has been
218 * installed for each supported signal type. This should be called
219 * after every trapped exception and at any other time when the
220 * status of exception handlers may have become not well-defined.
221 * If no handler has been pushed for a given signal type, SIG_DFL is
222 * installed. Note that the standard handler function Asc_SignalTrap()
223 * does not call this function. If you use the standard handler and
224 * you want it reinstalled after an exception, be sure to call this
225 * function after the longjmp return. This call is not particularly
226 * cheap if it does the reinstallation.<br><br>
227 *
228 * This module tests on startup for whether the OS reverts to
229 * SIG_DFL when a trap function is called. If it does NOT then
230 * this function will simply return unless force != 0. You don't
231 * want to call this function with force == 1 normally after a
232 * caught exception. However, if you're not sure of the handler
233 * installation status and want to make sure the handlers are
234 * installed, call with force == 1. Also, gdb or other
235 * debuggers which intercept and screw up signals may require
236 * applying force (manually) to ensure that the signals get
237 * reinstalled.
238 *
239 * @param force If non-zero, the most recent handlers are
240 * reinstalled even if not required by the
241 * compiler/platform.
242 */
243
244 extern int Asc_SignalHandlerPush(int signum, SigHandler func);
245 /**<
246 * Adds a handler to the stack of signal handlers for the given signal.
247 * There is a maximum stack limit, so returns 1 if limit exceeded.
248 * Returns -1 if stack of signal requested does not exist.
249 * Pushing a NULL handler func does NOT change anything at all.
250 * On a successful return, the handler has been installed and will
251 * remain installed until a Asc_SignalHandlerPop() or another push.
252 * The handler will remain installed as long as Asc_SignalRecover()
253 * is used properly after every exception.
254 *
255 * @param signum The signal type that func should handle.
256 * @param func The signal handler to register for signum signal types.
257 * @return Returns 1 if the stack limit is exceeded, -1 if managing
258 * of signals for the specified signum is not supported or
259 * initialized, or 0 if the function completes successfully.
260 * @todo Shouldn't utilities/ascSignal.c:Asc_SignalHandlerPush() return
261 * an error code on a NULL func? It seems too easy for someone to
262 * accidentally push a NULL without realizing it, and then later
263 * popping an unintended handler.
264 */
265
266 extern int Asc_SignalHandlerPop(int signum, SigHandler func);
267 /**<
268 * Removes the last-pushed handler from the stack for signum signal types.
269 * If the removed handler is the same as func, it is uninstalled and
270 * replaced with the handler now at the top of the stack. If not, non-zero
271 * is returned and you need to call Asc_SignalRecover() to uninstall the
272 * current handler if desired. Note that the top handler is popped off
273 * the stack whether it matches func or not. Non-zero is also returned if
274 * the stack is empty. A side effect is that all managed signal types will
275 * have the registered handlers reinstalled.
276 *
277 * @param signum The signal type whose top-most handler should be replaced.
278 * @param func The handler function that should be at the top of the
279 * stack (and currently installed) for signals of type signum.
280 * @return Returns non-zero if func is not the replaced handler or if
281 * the stack is empty, 0 if the function completed successfully.
282 * @todo Does it make more sense for utilities/ascSignal.c:Asc_SignalHanderPop()
283 * to fail completely if func is not the top-most handler? It is not
284 * clear why the function should pop the top handler no matter what, but
285 * only call Asc_SignalRecover() if it matches func.
286 */
287
288 #endif /* ASC_ASCSIGNAL_H */
289

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