File:  [gforth] / gforth / engine / signals.c
Revision 1.5: download - view: text, annotated - select for diffs
Thu Jul 20 13:29:43 2000 UTC (23 years, 8 months ago) by anton
Branches: MAIN
CVS tags: HEAD
signal handling bugfix (not yet portability tested)

    1: /* signal handling
    2: 
    3:   Copyright (C) 1995,1996,1997,1998 Free Software Foundation, Inc.
    4: 
    5:   This file is part of Gforth.
    6: 
    7:   Gforth is free software; you can redistribute it and/or
    8:   modify it under the terms of the GNU General Public License
    9:   as published by the Free Software Foundation; either version 2
   10:   of the License, or (at your option) any later version.
   11: 
   12:   This program is distributed in the hope that it will be useful,
   13:   but WITHOUT ANY WARRANTY; without even the implied warranty of
   14:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15:   GNU General Public License for more details.
   16: 
   17:   You should have received a copy of the GNU General Public License
   18:   along with this program; if not, write to the Free Software
   19:   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   20: 
   21: */
   22: 
   23: 
   24: #define _GNU_SOURCE
   25: 
   26: #include <stdio.h>
   27: #include <setjmp.h>
   28: #include <string.h>
   29: #include <stdlib.h>
   30: #if !defined(apollo) && !defined(MSDOS)
   31: #include <sys/ioctl.h>
   32: #endif
   33: /* #include <asm/signal.h> */
   34: #include <signal.h>
   35: #include "config.h"
   36: #include "forth.h"
   37: #include "io.h"
   38: 
   39: 
   40: #define DEFAULTCOLS 80
   41: #if defined(MSDOS) || defined (_WIN32)
   42: #define DEFAULTROWS 25
   43: #else
   44: #define DEFAULTROWS 24
   45: #endif
   46: 
   47: UCell cols=DEFAULTCOLS;
   48: UCell rows=DEFAULTROWS;
   49: 
   50: #ifdef SA_SIGINFO
   51: void install_signal_handler(int sig, void (*handler)(int, siginfo_t *, void *))
   52:      /* installs three-argument signal handler for sig */
   53: {
   54:   struct sigaction action;
   55: 
   56:   action.sa_sigaction=handler;
   57:   sigemptyset(&action.sa_mask);
   58:   action.sa_flags=SA_RESTART|SA_SIGINFO; /* pass siginfo */
   59:   sigaction(sig, &action, NULL);
   60: }
   61: #endif
   62: 
   63: typedef void Sigfunc(int);
   64: 
   65: Sigfunc *bsd_signal(int signo, Sigfunc *func)
   66: {
   67:   struct sigaction act, oact;
   68: 
   69:   act.sa_handler=func;
   70:   sigemptyset(&act.sa_mask);
   71:   act.sa_flags=SA_NODEFER;
   72:   if (sigaction(signo,&act,&oact) < 0)
   73:     return SIG_ERR;
   74:   else
   75:     return oact.sa_handler;
   76: }
   77: 
   78: static void
   79: graceful_exit (int sig)
   80: {
   81:   deprep_terminal();
   82:   fprintf (stderr, "\n\n%s.\n", strsignal (sig));
   83:   exit (0x80|sig);
   84: }
   85: 
   86: jmp_buf throw_jmp_buf;
   87: 
   88: static void 
   89: signal_throw(int sig)
   90: {
   91:   int code;
   92: 
   93:   switch (sig) {
   94:   case SIGINT: code=-28; break;
   95:   case SIGFPE: code=-55; break;
   96: #ifdef SIGBUS
   97:   case SIGBUS: code=-23; break;
   98: #endif
   99:   case SIGSEGV: code=-9; break;
  100:   default: code=-256-sig; break;
  101:   }
  102:   longjmp(throw_jmp_buf,code); /* !! or use siglongjmp ? */
  103: }
  104: 
  105: #ifdef SA_SIGINFO
  106: static void fpe_handler(int sig, siginfo_t *info, void *_)
  107:      /* handler for SIGFPE */
  108: {
  109:   int code;
  110: 
  111:   switch(info->si_code) {
  112:   case FPE_INTDIV: code=-10; break; /* integer divide by zero */
  113:   case FPE_INTOVF: code=-11; break; /* integer overflow */
  114:   case FPE_FLTDIV: code=-42; break; /* floating point divide by zero */
  115:   case FPE_FLTOVF: code=-43; break; /* floating point overflow  */
  116:   case FPE_FLTUND: code=-54; break; /* floating point underflow  */
  117:   case FPE_FLTRES: code=-41; break; /* floating point inexact result  */
  118:   case FPE_FLTINV: /* invalid floating point operation  */
  119:   case FPE_FLTSUB: /* subscript out of range  */
  120:   default: code=-55; break;
  121:   }
  122:   longjmp(throw_jmp_buf,code);
  123: }
  124: 
  125: 
  126: #define SPILLAGE 128
  127: /* if there's a SIGSEGV within SPILLAGE bytes of some stack, we assume
  128:    that this stack has over/underflowed */
  129: 
  130: #define JUSTUNDER(addr1,addr2) (((UCell)((addr2)-1-(addr1)))<SPILLAGE)
  131: /* true is addr1 is just under addr2 */
  132: 
  133: #define JUSTOVER(addr1,addr2) (((UCell)((addr1)-(addr2)))<SPILLAGE)
  134: 
  135: #define NEXTPAGE(addr) ((Address)((((UCell)(addr)-1)&-pagesize)+pagesize))
  136: 
  137: static void segv_handler(int sig, siginfo_t *info, void *_)
  138: {
  139:   int code=-9;
  140:   Address addr=info->si_addr;
  141:   ImageHeader *h=gforth_header;
  142: 
  143:   if (JUSTUNDER(addr, h->data_stack_base))
  144:     code=-3;
  145:   else if (JUSTOVER(addr, NEXTPAGE(h->data_stack_base+h->data_stack_size)))
  146:     code=-4;
  147:   else if (JUSTUNDER(addr, h->return_stack_base))
  148:     code=-5;
  149:   else if (JUSTOVER(addr, NEXTPAGE(h->return_stack_base+h->return_stack_size)))
  150:     code=-6;
  151:   else if (JUSTUNDER(addr, h->fp_stack_base))
  152:     code=-44;
  153:   else if (JUSTOVER(addr, NEXTPAGE(h->fp_stack_base+h->fp_stack_size)))
  154:     code=-45;
  155:   longjmp(throw_jmp_buf,code);
  156: }
  157: 
  158: #endif /* defined(SA_SIGINFO) */
  159: 
  160: #ifdef SIGCONT
  161: static void termprep (int sig)
  162: {
  163:   bsd_signal(sig,termprep);
  164:   terminal_prepped=0;
  165: }
  166: #endif
  167: 
  168: void get_winsize()
  169: {
  170: #ifdef TIOCGWINSZ
  171:   struct winsize size;
  172:   
  173:   if (ioctl (1, TIOCGWINSZ, (char *) &size) >= 0) {
  174:     rows = size.ws_row;
  175:     cols = size.ws_col;
  176:   }
  177: #else
  178:   char *s;
  179:   if ((s=getenv("LINES"))) {
  180:     rows=atoi(s);
  181:     if (rows==0)
  182:       rows=DEFAULTROWS;
  183:   }
  184:   if ((s=getenv("COLUMNS"))) {
  185:     rows=atoi(s);
  186:     if (rows==0)
  187:       cols=DEFAULTCOLS;
  188:   }
  189: #endif
  190: }
  191: 
  192: #ifdef SIGWINCH
  193: static void change_winsize(int sig)
  194: {
  195:   /* signal(sig,change_winsize); should not be necessary with bsd_signal */
  196: #ifdef TIOCGWINSZ
  197:   get_winsize();
  198: #endif
  199: }
  200: #endif
  201: 
  202: void install_signal_handlers(void)
  203: {
  204: 
  205: #if 0
  206: /* these signals are handled right by default, no need to handle them;
  207:    they are listed here just for fun */
  208:   static short sigs_to_default [] = {
  209: #ifdef SIGCHLD
  210:     SIGCHLD,
  211: #endif
  212: #ifdef SIGINFO
  213:     SIGINFO,
  214: #endif
  215: #ifdef SIGIO
  216:     SIGIO,
  217: #endif
  218: #ifdef SIGLOST
  219:     SIGLOST,
  220: #endif
  221: #ifdef SIGKILL
  222:     SIGKILL,
  223: #endif
  224: #ifdef SIGSTOP
  225:     SIGSTOP,
  226: #endif
  227: #ifdef SIGPWR
  228:     SIGPWR,
  229: #endif
  230: #ifdef SIGMSG
  231:     SIGMSG,
  232: #endif
  233: #ifdef SIGDANGER
  234:     SIGDANGER,
  235: #endif
  236: #ifdef SIGMIGRATE
  237:     SIGMIGRATE,
  238: #endif
  239: #ifdef SIGPRE
  240:     SIGPRE,
  241: #endif
  242: #ifdef SIGVIRT
  243:     SIGVIRT,
  244: #endif
  245: #ifdef SIGGRANT
  246:     SIGGRANT,
  247: #endif
  248: #ifdef SIGRETRACT
  249:     SIGRETRACT,
  250: #endif
  251: #ifdef SIGSOUND
  252:     SIGSOUND,
  253: #endif
  254: #ifdef SIGSAK
  255:     SIGSAK,
  256: #endif
  257: #ifdef SIGTSTP
  258:     SIGTSTP,
  259: #endif
  260: #ifdef SIGTTIN
  261:     SIGTTIN,
  262: #endif
  263: #ifdef SIGTTOU
  264:     SIGTTOU,
  265: #endif
  266: #ifdef SIGSTKFLT
  267:     SIGSTKFLT,
  268: #endif
  269: #ifdef SIGUNUSED
  270:     SIGUNUSED,
  271: #endif
  272:   };
  273: #endif
  274: 
  275:   static short sigs_to_throw [] = {
  276: #ifdef SIGBREAK
  277:     SIGBREAK,
  278: #endif
  279: #ifdef SIGINT
  280:     SIGINT,
  281: #endif
  282: #ifdef SIGILL
  283:     SIGILL,
  284: #endif
  285: #ifdef SIGEMT
  286:     SIGEMT,
  287: #endif
  288: #ifdef SIGFPE
  289:     SIGFPE,
  290: #endif
  291: #ifdef SIGIOT
  292:     SIGIOT,
  293: #endif
  294: #ifdef SIGSEGV
  295:     SIGSEGV,
  296: #endif
  297: #ifdef SIGALRM
  298:     SIGALRM,
  299: #endif
  300: #ifdef SIGPIPE
  301:     SIGPIPE,
  302: #endif
  303: #ifdef SIGPOLL
  304:     SIGPOLL,
  305: #endif
  306: #ifdef SIGPROF
  307:     SIGPROF,
  308: #endif
  309: #ifdef SIGBUS
  310:     SIGBUS,
  311: #endif
  312: #ifdef SIGSYS
  313:     SIGSYS,
  314: #endif
  315: #ifdef SIGTRAP
  316:     SIGTRAP,
  317: #endif
  318: #ifdef SIGURG
  319:     SIGURG,
  320: #endif
  321: #ifdef SIGUSR1
  322:     SIGUSR1,
  323: #endif
  324: #ifdef SIGUSR2
  325:     SIGUSR2,
  326: #endif
  327: #ifdef SIGVTALRM
  328:     SIGVTALRM,
  329: #endif
  330: #ifdef SIGXFSZ
  331:     SIGXFSZ,
  332: #endif
  333:   };
  334:   static short sigs_to_quit [] = {
  335: #ifdef SIGQUIT
  336:     SIGQUIT,
  337: #endif
  338: #ifdef SIGHUP
  339:     SIGHUP,
  340: #endif
  341: #ifdef SIGABRT
  342:     SIGABRT,
  343: #endif
  344: #ifdef SIGTERM
  345:     SIGTERM,
  346: #endif
  347: #ifdef SIGXCPU
  348:     SIGXCPU,
  349: #endif
  350:   };
  351:   int i;
  352:   void (*throw_handler)() = die_on_signal ? graceful_exit : signal_throw;
  353: 
  354: #define DIM(X)		(sizeof (X) / sizeof *(X))
  355: /*
  356:   for (i = 0; i < DIM (sigs_to_ignore); i++)
  357:     signal (sigs_to_ignore [i], SIG_IGN);
  358: */
  359:   for (i = 0; i < DIM (sigs_to_throw); i++)
  360:     bsd_signal(sigs_to_throw[i], throw_handler);
  361:   for (i = 0; i < DIM (sigs_to_quit); i++)
  362:     bsd_signal(sigs_to_quit [i], graceful_exit);
  363: #ifdef SA_SIGINFO
  364:   install_signal_handler(SIGFPE, fpe_handler);
  365:   install_signal_handler(SIGSEGV, segv_handler);
  366: #endif
  367: #ifdef SIGCONT
  368:     bsd_signal(SIGCONT, termprep);
  369: #endif
  370: #ifdef SIGWINCH
  371:     bsd_signal(SIGWINCH, change_winsize);
  372: #endif
  373: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>