home *** CD-ROM | disk | FTP | other *** search
- /*
- * This file is part of the portable Forth environment written in ANSI C.
- * Copyright (C) 1995 Dirk Uwe Zoller
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This file is version 0.9.13 of 17-July-95
- * Check for the latest version of this package via anonymous ftp at
- * roxi.rz.fht-mannheim.de:/pub/languages/forth/pfe-VERSION.tar.gz
- * or sunsite.unc.edu:/pub/languages/forth/pfe-VERSION.tar.gz
- * or ftp.cygnus.com:/pub/forth/pfe-VERSION.tar.gz
- *
- * Please direct any comments via internet to
- * duz@roxi.rz.fht-mannheim.de.
- * Thank You.
- */
- /*
- * signals.c --- Handle signals.
- * (duz 25Apr94)
- */
-
- #include "forth.h"
- #include "support.h"
- #include "compiler.h"
- #include "term.h"
-
- #include <stdlib.h>
- #include <string.h>
- #include <float.h>
- #include <signal.h>
-
- #include "nonansi.h"
- #include "missing.h"
-
- typedef void (*SigHdl) (int); /* signal handler function type */
-
- enum /* Classification of signals: The */
- { /* signal class is either a THROW code or: */
- Fatal, /* pfe terminates if such a signal arrives */
- Abort, /* executes ABORT" */
- Chandled, /* handled by C code, e.g. stop/continue */
- Default /* left alone by pfe, cannot be caught */
- };
-
- typedef struct /* all we need to know about a signal */
- {
- short sig; /* the signal */
- short cLass; /* a classification */
- char *name; /* the name of the signal */
- #ifndef HAVE_SYS_SIGLIST
- char *msg; /* a textual signal description */
- #endif
- SigHdl old; /* state of signal before we took it */
- Xt hdl; /* a forth word to handle the signal */
- }
- Siginfo;
-
- #ifdef OLDCPP
- #ifdef HAVE_SYS_SIGLIST
- #define SIG(NM,CL,MSG) { NM, CL, "NM", SIG_DFL }
- #else
- #define SIG(NM,CL,MSG) { NM, CL, "NM", MSG, SIG_DFL }
- #endif
- #else
- #ifdef HAVE_SYS_SIGLIST
- #define SIG(NM,CL,MSG) { NM, CL, #NM, SIG_DFL }
- #else
- #define SIG(NM,CL,MSG) { NM, CL, #NM, MSG, SIG_DFL }
- #endif
- #endif
-
- /*
- * With the means of the above structures and classifications we
- * describe a lot of signals to pfe conditionally. Fine if a system
- * has a signal. If not it's just as well.
- */
-
- static Siginfo siginfo[] =
- {
-
- /*
- * These are described in W.R.Stevens'
- * "Advanced Programming in the UNIX Environment"
- */
- #ifdef SIGABRT
- SIG (SIGABRT, Fatal, "abnormal termination (abort)"),
- #endif
- #ifdef SIGALRM
- SIG (SIGALRM, Abort, "time out (alarm)"),
- #endif
- #ifdef SIGBUS
- SIG (SIGBUS, THROW_ADDRESS_ALIGNMENT, NULL),
- #endif
- #ifdef SIGCHLD
- SIG (SIGCHLD, Default, "change in status of child"),
- #endif
- #ifdef SIGCONT
- SIG (SIGCONT, Default, "continue stopped process"),
- #endif
- #ifdef SIGEMT
- SIG (SIGEMT, Abort, "hardware fault (EMT)"),
- #endif
- #ifdef SIGFPE
- SIG (SIGFPE, THROW_FLOATING_POINT, NULL),
- #endif
- #ifdef SIGHUP
- SIG (SIGHUP, Fatal, "hangup"),
- #endif
- #ifdef SIGILL
- SIG (SIGILL, Abort, "illegal hardware instruction"),
- #endif
- #ifdef SIGINFO
- SIG (SIGINFO, Default, "status request from keyboard"),
- #endif
- #ifdef SIGINT
- SIG (SIGINT, THROW_USER_INTERRUPT, NULL),
- #endif
- #ifdef SIGIO
- SIG (SIGIO, Default, "asynchronous io"),
- #endif
- #ifdef SIGIOT
- SIG (SIGIOT, Abort, "hardware fault (IOT)"),
- #endif
- #ifdef SIGKILL
- SIG (SIGKILL, Default, "kill"),
- #endif
- #ifdef SIGPIPE
- SIG (SIGPIPE, Fatal, "write to pipe with no readers"),
- #endif
- #ifdef SIGPOLL
- SIG (SIGPOLL, Abort, "pollable event (poll)"),
- #endif
- #ifdef SIGPROF
- SIG (SIGPROF, Abort, "profiling time alarm (setitimer)"),
- #endif
- #ifdef SIGPWR
- SIG (SIGPWR, Default, "power fail/restart"),
- #endif
- #ifdef SIGQUIT
- SIG (SIGQUIT, Fatal, "terminal quit key"),
- #endif
- #ifdef SIGSEGV
- SIG (SIGSEGV, THROW_INVALID_MEMORY, NULL),
- #endif
- #ifdef SIGSTOP
- SIG (SIGSTOP, Default, "stop"),
- #endif
- #ifdef SIGSYS
- SIG (SIGSYS, Abort, "invalid system call"),
- #endif
- #ifdef SIGTERM
- SIG (SIGTERM, Fatal, "terminated"),
- #endif
- #ifdef SIGTRAP
- SIG (SIGTRAP, Abort, "hardware fault (trace trap)"),
- #endif
- #ifdef SIGTSTP
- SIG (SIGTSTP, Chandled, "terminal stop character"),
- #endif
- #ifdef SIGTTIN
- SIG (SIGTTIN, Chandled, "background read from control tty"),
- #endif
- #ifdef SIGTTOU
- SIG (SIGTTOU, Chandled, "background write to control tty"),
- #endif
- #ifdef SIGURG
- SIG (SIGURG, Abort, "urgent condition"),
- #endif
- #ifdef SIGUSR1
- SIG (SIGUSR1, Abort, "user defined signal 1"),
- #endif
- #ifdef SIGUSR2
- SIG (SIGUSR2, Abort, "user defined signal 2"),
- #endif
- #ifdef SIGVTALRM
- SIG (SIGVTALRM, Abort, "virtual time alarm (setitimer)"),
- #endif
- #ifdef SIGWINCH
- SIG (SIGWINCH, Chandled, "terminal window size change"),
- #endif
- #ifdef SIGXCPU
- SIG (SIGXCPU, Fatal, "CPU limit exceeded"),
- #endif
- #ifdef SIGXFSZ
- SIG (SIGXFSZ, Abort, "file size limit exceeded"),
- #endif
-
- /*
- * Signals specific to certain systems.
- */
- #ifdef SIGSTKFLT /* Linux */
- SIG (SIGSTKFLT, Abort, "SIGSTKFLT"),
- #endif
-
- #ifdef SIGBREAK /* EMX, Watcom */
- SIG (SIGBREAK, THROW_USER_INTERRUPT, NULL),
- #endif
-
- #ifdef SIGMSG /* AIX 3.2 */
- SIG (SIGMSG, Default, "input data is in the HFT ring buffer"),
- #endif
- #ifdef SIGDANGER
- SIG (SIGDANGER, Default, "system crash imminent; free up some page space"),
- #endif
- #ifdef SIGMIGRATE
- SIG (SIGMIGRATE, Default, "migrate process (see TCF)"),
- #endif
- #ifdef SIGPRE
- SIG (SIGPRE, Default, "programming exception"),
- #endif
- #ifdef SIGVIRT
- SIG (SIGVIRT, Default, "AIX virtual time alarm"),
- #endif
- #ifdef SIGGRANT
- SIG (SIGGRANT, Default, "HFT monitor mode granted"),
- #endif
- #ifdef SIGRETRACT
- SIG (SIGRETRACT, Default, "HFT monitor mode should be relinguished"),
- #endif
- #ifdef SIGSOUND
- SIG (SIGSOUND, Default, "HFT sound control has completed"),
- #endif
- #ifdef SIGSAK
- SIG (SIGSAK, Default, "secure attention key"),
- #endif
- };
-
- static int
- getinfo (int sig)
- {
- int i;
-
- for (i = 0; i < DIM (siginfo); i++)
- if (siginfo[i].sig == sig)
- return i;
-
- tHrow (THROW_ARG_TYPE);
- return i;
- }
-
- static void
- sig_handler (int sig) /* Signal handler for all signals */
- {
- Siginfo *s;
- const char *msg;
-
- #if !KEEPS_SIGNALS
- signal (sig, sig_handler); /* reinstall handler */
- #endif
- #if defined EMX || defined WC_OS2V2
- signal (sig, SIG_ACK); /* OS/2: acknowledge signal */
- #endif
- #if defined EMX
- _control87 (EM_DENORMAL | EM_INEXACT, MCW_EM);
- #endif
-
- s = &siginfo[getinfo (sig)];
- if (s->hdl)
- call_forth (s->hdl); /* a forth-handled signal */
- else
- {
- #ifdef HAVE_SYS_SIGLIST
- msg = sys_siglist[sig];
- #else
- msg = s->msg;
- #endif
- switch (s->cLass)
- {
- default: /* an ANSI-Forth defined condition */
- tHrow (s->cLass);
- case Abort: /* another catchable signal */
- tHrow (-2, msg, strlen (msg));
- case Fatal: /* a signal that kills us */
- fatal ("got signal %s, %s", s->name, msg);
- eXit (1);
- }
- }
- }
-
- /*
- * Actions to take when job control interferes or on window size change:
- */
-
- #ifdef SIGTSTP
- static void
- stop_hdl (int sig)
- {
- #if !KEEPS_SIGNALS
- signal (sig, stop_hdl);
- #endif
- on_stop ();
- swap_signals ();
- #if _BSD
- kill (getpid (), SIGSTOP);
- #else
- raise (SIGTSTP);
- #endif
- swap_signals ();
- on_continue ();
- }
- #endif
-
- #ifdef SIGWINCH
- static void
- winchg_hdl (int sig)
- {
- #if !KEEPS_SIGNALS
- signal (sig, winchg_hdl);
- #endif
- on_winchg ();
- }
- #endif
-
- /*
- * install all signal handlers:
- */
-
- void
- install_signal_handlers (void)
- {
- int i, j;
-
- for (i = 0; i < DIM (siginfo); i++)
- {
- /* some systems may have more than one name for the same signal,
- * take care not to install it twice: */
- for (j = 0; j < i; j++)
- if (siginfo[i].sig == siginfo[j].sig)
- goto cont;
- switch (siginfo[i].cLass)
- {
- default:
- siginfo[i].old = signal (siginfo[i].sig, sig_handler);
- case Chandled:
- case Default:;
- }
- cont:;
- }
- #ifdef SIGTSTP
- if (signal (SIGTSTP, SIG_IGN) == SIG_DFL)
- {
- signal (SIGTSTP, stop_hdl);
- siginfo[getinfo (SIGTSTP)].old = SIG_DFL;
- siginfo[getinfo (SIGTTIN)].old = signal (SIGTTIN, stop_hdl);
- siginfo[getinfo (SIGTTOU)].old = signal (SIGTTOU, stop_hdl);
- }
- #endif
- #ifdef SIGWINCH
- #ifdef KEEPS_SIGNALS
- signal (SIGWINCH, winchg_hdl);
- #endif
- winchg_hdl (SIGWINCH);
- #endif
- }
-
- void
- swap_signals (void)
- /* switch between pfe setting of signals and state before */
- {
- int i;
-
- for (i = 0; i < DIM (siginfo); i++)
- if (siginfo[i].cLass != Default || siginfo[i].hdl)
- siginfo[i].old = signal (siginfo[i].sig, siginfo[i].old);
- }
-
- Xt
- forth_signal (int sig, Xt xt)
- /*
- * xt != NULL: install forth word as signal handler for signal
- * xt == NULL: install pfe default signal handler for signal
- */
- {
- int i = getinfo (sig);
- Xt old;
-
- old = siginfo[i].hdl;
- siginfo[i].hdl = xt;
-
- if (siginfo[i].cLass == Default)
- if (xt == NULL)
- siginfo[i].old = signal (sig, siginfo[i].old);
- else
- siginfo[i].old = signal (sig, sig_handler);
-
- return old;
- }
-
- void
- load_signals (Wordl *wid)
- /*
- * Load constants for each signal found into the dictionary.
- */
- {
- Siginfo *s;
- char *nfa;
- Head *h;
-
- for (s = siginfo; s < siginfo + DIM (siginfo); s++)
- {
- h = make_head (s->name, strlen (s->name), &nfa, wid);
- h->cfa = constant_runtime;
- COMMA (s->sig);
- }
- }
-