aboutsummaryrefslogtreecommitdiff
path: root/unix/os/zxwhen.c
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /unix/os/zxwhen.c
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'unix/os/zxwhen.c')
-rw-r--r--unix/os/zxwhen.c499
1 files changed, 499 insertions, 0 deletions
diff --git a/unix/os/zxwhen.c b/unix/os/zxwhen.c
new file mode 100644
index 00000000..e0730f38
--- /dev/null
+++ b/unix/os/zxwhen.c
@@ -0,0 +1,499 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+ */
+
+#include <stdio.h>
+#include <signal.h>
+
+#ifdef CYGWIN
+# include <mingw/fenv.h>
+#else
+#ifdef LINUX
+# include <fpu_control.h>
+#else
+# ifdef BSD
+# include <floatingpoint.h>
+# endif
+#endif
+#endif
+
+#ifdef SOLARIS
+# include <sys/siginfo.h>
+# include <sys/ucontext.h>
+# include <ieeefp.h>
+#endif
+
+#ifdef MACOSX
+#include <math.h>
+#include <fenv.h>
+#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 <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;
+
+#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 <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 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