/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. */ #include #include #ifdef CYGWIN # include #else #ifdef LINUX # include #else # ifdef BSD # include # endif #endif #endif #ifdef SOLARIS # include # include # include #endif #ifdef MACOSX #include #include #endif #ifdef LINUXPPC #define MACUNIX #endif #ifdef MACOSX #ifndef MACINTEL #define MACUNIX #endif /* The following are needed for OS X 10.1 for backward compatability. The * signal sa_flags are set to use them to get signal handling working on * 10.2 and later systems. */ #ifdef OLD_MACOSX #ifndef SA_NODEFER #define SA_NODEFER 0x0010 /* don't mask the signal we're delivering */ #endif #ifndef SA_NOCLDWAIT #define SA_NOCLDWAIT 0x0020 /* don't keep zombies around */ #endif #ifndef SA_SIGINFO #define SA_SIGINFO 0x0040 /* signal handler with SA_SIGINFO args */ #endif #endif #endif #define import_spp #define import_kernel #define import_knames #define import_xwhen #include /* 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; #ifdef LINUX # define fcancel(fp) #else # ifdef BSD # define fcancel(fp) ((fp)->_r = (fp)->_w = 0) #else # ifdef MACOSX # define fcancel(fp) ((fp)->_r = (fp)->_w = 0) #else # ifdef SOLARIS # define fcancel(fp) ((fp)->_cnt=BUFSIZ,(fp)->_ptr=(fp)->_base) #endif #endif #endif #endif #if (defined(MACOSX) && defined(OLD_MACOSX)) void ex_handler ( int, int, struct sigcontext * ); #else void ex_handler ( int, siginfo_t *, void * ); #endif static long setsig(); 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 * (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 MACOSX #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 (); /* 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 (code, handler) int code; SIGFUNC handler; { struct sigaction sig; long status; sigemptyset (&sig.sa_mask); #ifdef MACOSX 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). */ #if (defined(MACOSX) && defined(OLD_MACOSX)) void ex_handler (unix_signal, info, scp) int unix_signal; #ifdef OLD_MACOSX void *info; #else siginfo_t *info; #endif #ifdef MACINTEL ucontext_t *scp; #else struct sigcontext *scp; #endif #else void ex_handler ( int unix_signal, siginfo_t *info, void *ucp ) #endif { XINT next_epa, epa, x_vex; int vex; #ifndef LINUX64 extern int sfpucw_(); #endif 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. */ #if defined(MACOSX) || defined(CYGWIN) /* Clear the exception bits (ppc and x86). */ feclearexcept (FE_ALL_EXCEPT); #else #ifdef LINUX /* setfpucw (0x1372); */ { #ifdef MACUNIX /* This is for Linux on a Mac, e.g., LinuxPPC (not MacOSX). */ int fpucw = _FPU_IEEE; /* if (unix_signal == SIGFPE) kernel_panic ("unrecoverable floating exception"); else sfpucw_ (&fpucw); if (unix_signal == SIGPIPE && !ignore_sigint) sigset (SIGINT, (SIGFUNC) ex_handler); */ sfpucw_ (&fpucw); #else #ifdef LINUX64 /* XINT fpucw = 0x336; SFPUCW (&fpucw); */ fpu_control_t cw = (_FPU_EXTENDED | _FPU_MASK_PM | _FPU_MASK_UM | _FPU_MASK_ZM | _FPU_MASK_DM); _FPU_SETCW(cw); #else int fpucw = 0x336; sfpucw_ (&fpucw); #endif #endif } #endif #endif #ifdef SOLARIS fpsetsticky (0x0); fpsetmask (FP_X_INV | FP_X_OFL | FP_X_DZ); #endif /* 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); } #ifdef LINUX64 int gfpucw_ (XINT *xcw) { fpu_control_t cw; _FPU_GETCW(cw); *xcw = cw; return cw; } int sfpucw_ (XINT *xcw) { fpu_control_t cw = *xcw; _FPU_SETCW(cw); return cw; } #endif