1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
|
/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
*/
#include <stdio.h>
#include <signal.h>
#include <math.h>
#include <fenv.h>
#define import_spp
#define import_kernel
#define import_knames
#define import_xwhen
#include <iraf.h>
/* ZXWHEN.C -- IRAF exception handling interface. This version has been
* customized for PC-IRAF, i.e., LINUX and FreeBSD.
*
* Rewritten Aug200 to use sigaction by default on all systems (done in
* connection with the LinuxPPC port). This got rid of a lot of old kludgy
* platform-dependent code used to workaround Linux signal handling problems.
*/
/* Set the following nonzero to cause process termination with a core dump
* when the first signal occurs.
*/
int debug_sig = 0;
/* If the OS allows, cancel any buffered output. If the OS doesn't,
* do nothing.
*/
#ifdef __APPLE__
#define fcancel(fp) ((fp)->_r = (fp)->_w = 0)
#else
#define fcancel(fp)
#endif
void ex_handler ( int, siginfo_t *, void * );
static long setsig(int code, SIGFUNC handler);
static int ignore_sigint = 0;
/* Exception handling: ZXWHEN (exception, handler, old_handler)
*
* exception: X_INT, X_ARITH, X_ACV, or X_IPC
*
* handler: Either X_IGNORE or the entry point address
* of a user supplied exception handler which
* will gain control in the event of an exception.
*
* old_handler: On output, contains the value of the previous
* handler (either X_IGNORE or an EPA). Used to
* restore an old handler, or to chain handlers.
*
* An exception can be entirely disabled by calling ZXWHEN with the
* handler X_IGNORE. Otherwise, the user supplied exception handler
* gains control when the exception occurs. An exception handler is
* called with one argument, an integer code identifying the exception.
* The handler should return as its function value either X_IGNORE,
* causing normal processing to resume, or the EPA of the next handler
* to be called (normally the value of the parameter "old_handler").
* The user handler should call FATAL if error restart is desired.
*
* If the SIGINT exeception has already been set to SIG_IGN, i.e., by the
* parent process which spawned us, then it will continue to be ignored.
* It is standard procedure in UNIX to spawn a background task with SIGINT
* disabled, so that interrupts sent to the parent process are ignored by
* the child. If this is the case then SIGTERM may still be sent to the
* child to raise the X_INT exception in the high level code.
*/
#define EOMAP (-1) /* end of map array sentinel */
#define mask(s) (1 << ((s) - 1))
int last_os_exception; /* save OS code of last exception */
int last_os_hwcode; /* hardware exception code */
XINT handler_epa[] = { /* table of handler EPAs */
0, /* X_ACV */
0, /* X_ARITH */
0, /* X_INT */
0, /* X_IPC */
};
struct osexc {
int x_vex; /* UNIX signal code */
char *x_name; /* UNIX signal name string */
};
struct osexc unix_exception[] = {
{ 0, "" },
{ 0, "hangup" },
{ X_INT, "interrupt" },
{ 0, "quit" },
{ X_ACV, "illegal instruction" },
{ 0, "trace trap" },
{ X_ACV, "abort" },
{ X_ACV, "EMT exception" },
{ X_ARITH, "arithmetic exception" },
{ 0, "kill" },
{ X_ACV, "bus error" },
{ X_ACV, "segmentation violation" },
{ X_ACV, "bad arg to system call" },
{ X_IPC, "write to pipe with no reader" },
{ 0, "alarm clock" },
{ X_INT, "software terminate (interrupt)" },
{ X_ARITH, "STKFLT" },
{ EOMAP, "" }
};
/* Hardware exceptions [MACHDEP]. To customize for a new machine, replace
* the symbol MYMACHINE by the machine name, #define the name in <iraf.h>
* (i.e., hlib$libc/iraf.h), and edit the hardware exception list below.
*/
struct _hwx {
int v_code; /* Hardware exception code */
char *v_msg; /* Descriptive error message */
};
#ifdef __APPLE__
#ifdef FPE_INTDIV
#undef FPE_INTDIV
#endif
#define FPE_INTDIV (-2) /* N/A */
#ifdef FPE_INTOVF
#undef FPE_INTOVF
#endif
#define FPE_INTOVF (-2) /* N/A */
#ifdef FPE_FLTRES
#undef FPE_FLTRES
#endif
#define FPE_FLTRES FE_INEXACT /* inexact */
#ifdef FPE_FLTDIV
#undef FPE_FLTDIV
#endif
#define FPE_FLTDIV FE_DIVBYZERO /* divide-by-zero */
#ifdef FPE_FLTUND
#undef FPE_FLTUND
#endif
#define FPE_FLTUND FE_UNDERFLOW /* underflow */
#ifdef FPE_FLTOVF
#undef FPE_FLTOVF
#endif
#define FPE_FLTOVF FE_OVERFLOW /* overflow */
#ifdef FPE_FLTINV
#undef FPE_FLTINV
#endif
#define FPE_FLTINV FE_INVALID /* invalid */
#ifdef FPE_FLTSUB
#undef FPE_FLTSUB
#endif
#define FPE_FLTSUB (-2) /* N/A */
#endif
struct _hwx hwx_exception[] = {
{ FPE_INTDIV, "integer divide by zero" },
{ FPE_INTOVF, "integer overflow" },
{ FPE_FLTDIV, "floating point divide by zero" },
{ FPE_FLTOVF, "floating point overflow" },
{ FPE_FLTUND, "floating point underflow" },
{ FPE_FLTRES, "floating point inexact result" },
{ FPE_FLTINV, "floating point invalid operation" },
{ FPE_FLTSUB, "subscript out of range" },
{ EOMAP, "" }
};
/* ZXWHEN -- Post an exception handler or turn off interrupts. Return
* value of old handler, so that it may be restored by the user code if
* desired. The function EPA's are the type of value returned by ZLOCPR.
*/
int
ZXWHEN (
XINT *sig_code,
XINT *epa, /* EPA of new exception handler */
XINT *old_epa /* receives EPA of old handler */
)
{
static int first_call = 1;
int vex, uex;
SIGFUNC vvector;
extern int kernel_panic (char *errmsg);
/* Convert code for virtual exception into an index into the table
* of exception handler EPA's.
*/
switch (*sig_code) {
case X_ACV:
case X_ARITH:
case X_INT:
case X_IPC:
vex = *sig_code - X_FIRST_EXCEPTION;
break;
default:
vex = (int) 0;
kernel_panic ("zxwhen: bad exception code");
}
*old_epa = handler_epa[vex];
handler_epa[vex] = *epa;
vvector = (SIGFUNC) ex_handler;
/* Check for attempt to post same handler twice. Do not return EPA
* of handler as old_epa as this could lead to recursion.
*/
if (*epa == (XINT) X_IGNORE)
vvector = (SIGFUNC) SIG_IGN;
else if (*epa == *old_epa)
*old_epa = (XINT) X_IGNORE;
/* Set all hardware vectors in the indicated exception class.
* If interrupt (SIGINT) was disabled when we were spawned (i.e.,
* when we were first called to set SIGINT) leave it that way, else
* we will get interrupted when the user interrupts the parent.
*/
for (uex=1; unix_exception[uex].x_vex != EOMAP; uex++) {
if (unix_exception[uex].x_vex == *sig_code) {
if (uex == SIGINT) {
if (first_call) {
if (setsig (uex, vvector) == (long) SIG_IGN) {
setsig (uex, SIG_IGN);
ignore_sigint++;
}
first_call = 0;
} else if (!ignore_sigint) {
if (debug_sig)
setsig (uex, SIG_DFL);
else
setsig (uex, vvector);
}
} else {
if (debug_sig)
setsig (uex, SIG_DFL);
else
setsig (uex, vvector);
}
}
}
return (XOK);
}
/* SETSIG -- Post an exception handler for the given exception.
*/
static long
setsig (int code, SIGFUNC handler)
{
struct sigaction sig;
long status;
sigemptyset (&sig.sa_mask);
#ifdef __APPLE__
sig.sa_handler = (SIGFUNC) handler;
#else
sig.sa_sigaction = (SIGFUNC) handler;
#endif
sig.sa_flags = (SA_NODEFER|SA_SIGINFO);
status = (long) sigaction (code, &sig, NULL);
return (status);
}
/* EX_HANDLER -- Called to handle an exception. Map OS exception into
* xwhen signal, call user exception handler. A default exception handler
* posted by the IRAF Main is called if the user has not posted another
* handler. If we get the software termination signal from the CL,
* stop process execution immediately (used to kill detached processes).
*/
void
ex_handler (
int unix_signal,
siginfo_t *info,
void *ucp
)
{
XINT next_epa, epa, x_vex;
int vex;
last_os_exception = unix_signal;
last_os_hwcode = info ? info->si_code : 0;
x_vex = unix_exception[unix_signal].x_vex;
vex = x_vex - X_FIRST_EXCEPTION;
epa = handler_epa[vex];
/* Reenable/initialize the exception handler.
*/
/* Clears the exception-occurred bits in the FP status register.
*/
feclearexcept (FE_ALL_EXCEPT);
/* If signal was SIGINT, cancel any buffered standard output. */
if (unix_signal == SIGINT) {
fcancel (stdout);
}
/* Call user exception handler(s). Each handler returns with the
* "value" (epa) of the next handler, or X_IGNORE if exception handling
* is completed and processing is to continue normally. If the handler
* wishes to restart the process, i.e., initiate error recovery, then
* the handler procedure will not return.
*/
for (next_epa=epa; next_epa != (XINT) X_IGNORE;
((SIGFUNC)epa)(&x_vex,&next_epa))
epa = next_epa;
}
/* ZXGMES -- Get the machine dependent integer code and error message for the
* most recent exception. The integer code XOK is returned if no exception
* has occurred, or if we are called more than once.
*/
int
ZXGMES (
XINT *os_exception,
PKCHAR *errmsg,
XINT *maxch
)
{
register int v;
char *os_errmsg;
*os_exception = last_os_exception;
if (last_os_exception == XOK)
os_errmsg = "";
else {
os_errmsg = unix_exception[last_os_exception].x_name;
if (last_os_exception == SIGFPE) {
for (v=0; hwx_exception[v].v_code != EOMAP; v++)
if (hwx_exception[v].v_code == last_os_hwcode) {
os_errmsg = hwx_exception[v].v_msg;
break;
}
}
}
strncpy ((char *)errmsg, os_errmsg, (int)*maxch);
((char *)errmsg)[*maxch] = EOS;
last_os_exception = XOK;
return (XOK);
}
|