File:  [gforth] / gforth / engine / signals.c
Revision 1.24: download - view: text, annotated - select for diffs
Sun Feb 2 11:05:50 2003 UTC (19 years, 6 months ago) by anton
Branches: MAIN
CVS tags: HEAD
portability bugfixes
use SA_ONSTACK for all program-generated signals
updated README

    1: /* signal handling
    2: 
    3:   Copyright (C) 1995,1996,1997,1998,2000 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
   20: 
   21: */
   22: 
   23: 
   24: #include "config.h"
   25: #include "forth.h"
   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 <sys/types.h>
   35: #include <signal.h>
   36: #include "io.h"
   37: 
   38: #ifndef HAVE_STACK_T
   39: /* Darwin uses "struct sigaltstack" instead of "stack_t" */
   40: typedef struct sigaltstack stack_t;
   41: #endif
   42: 
   43: #define DEFAULTCOLS 80
   44: #if defined(MSDOS) || defined (_WIN32)
   45: #define DEFAULTROWS 25
   46: #else
   47: #define DEFAULTROWS 24
   48: #endif
   49: 
   50: UCell cols=DEFAULTCOLS;
   51: UCell rows=DEFAULTROWS;
   52: 
   53: #ifndef SA_NODEFER
   54: #define SA_NODEFER 0
   55: /* systems that don't have SA_NODEFER hopefully don't block anyway */
   56: #endif
   57: 
   58: #ifndef SA_ONSTACK
   59: #define SA_ONSTACK 0
   60: #endif
   61: 
   62: #ifdef SA_SIGINFO
   63: void install_signal_handler(int sig, void (*handler)(int, siginfo_t *, void *))
   64:      /* installs three-argument signal handler for sig */
   65: {
   66:   struct sigaction action;
   67: 
   68:   action.sa_sigaction=handler;
   69:   sigemptyset(&action.sa_mask);
   70:   action.sa_flags=SA_RESTART|SA_NODEFER|SA_SIGINFO|SA_ONSTACK; /* pass siginfo */
   71:   sigaction(sig, &action, NULL);
   72: }
   73: #endif
   74: 
   75: typedef void Sigfunc(int);
   76: 
   77: Sigfunc *bsd_signal(int signo, Sigfunc *func)
   78: {
   79:   struct sigaction act, oact;
   80: 
   81:   act.sa_handler=func;
   82:   sigemptyset(&act.sa_mask);
   83:   act.sa_flags=SA_NODEFER; /* SA_ONSTACK does not work for graceful_exit */
   84:   if (sigaction(signo,&act,&oact) < 0)
   85:     return SIG_ERR;
   86:   else
   87:     return oact.sa_handler;
   88: }
   89: 
   90: static void
   91: graceful_exit (int sig)
   92: {
   93:   deprep_terminal();
   94:   fprintf (stderr, "\n\n%s.\n", strsignal (sig));
   95:   exit (0x80|sig);
   96: }
   97: 
   98: jmp_buf throw_jmp_buf;
   99: 
  100: static void 
  101: signal_throw(int sig)
  102: {
  103:   int code;
  104: 
  105:   switch (sig) {
  106:   case SIGINT: code=-28; break;
  107:   case SIGFPE: code=-55; break;
  108: #ifdef SIGBUS
  109:   case SIGBUS: code=-23; break;
  110: #endif
  111:   case SIGSEGV: code=-9; break;
  112:   default: code=-256-sig; break;
  113:   }
  114:   longjmp(throw_jmp_buf,code); /* !! or use siglongjmp ? */
  115: }
  116: 
  117: #ifdef SA_SIGINFO
  118: static void
  119: sigaction_throw(int sig, siginfo_t *info, void *_)
  120: {
  121:   signal_throw(sig);
  122: }
  123: 
  124: static void fpe_handler(int sig, siginfo_t *info, void *_)
  125:      /* handler for SIGFPE */
  126: {
  127:   int code;
  128: 
  129:   switch(info->si_code) {
  130: #ifdef FPE_INTDIV
  131:   case FPE_INTDIV: code=-10; break; /* integer divide by zero */
  132: #endif
  133: #ifdef FPE_INTOVF
  134:   case FPE_INTOVF: code=-11; break; /* integer overflow */
  135: #endif
  136:   case FPE_FLTDIV: code=-42; break; /* floating point divide by zero */
  137:   case FPE_FLTOVF: code=-43; break; /* floating point overflow  */
  138:   case FPE_FLTUND: code=-54; break; /* floating point underflow  */
  139:   case FPE_FLTRES: code=-41; break; /* floating point inexact result  */
  140: #if 0 /* defined by Unix95, but unnecessary */
  141:   case FPE_FLTINV: /* invalid floating point operation  */
  142:   case FPE_FLTSUB: /* subscript out of range  */
  143: #endif
  144:   default: code=-55; break;
  145:   }
  146:   longjmp(throw_jmp_buf,code);
  147: }
  148: 
  149: 
  150: #define SPILLAGE 128
  151: /* if there's a SIGSEGV within SPILLAGE bytes of some stack, we assume
  152:    that this stack has over/underflowed */
  153: 
  154: #define JUSTUNDER(addr1,addr2) (((UCell)((addr2)-1-(addr1)))<SPILLAGE)
  155: /* true is addr1 is just under addr2 */
  156: 
  157: #define JUSTOVER(addr1,addr2) (((UCell)((addr1)-(addr2)))<SPILLAGE)
  158: 
  159: #define NEXTPAGE(addr) ((Address)((((UCell)(addr)-1)&-pagesize)+pagesize))
  160: 
  161: static void segv_handler(int sig, siginfo_t *info, void *_)
  162: {
  163:   int code=-9;
  164:   Address addr=info->si_addr;
  165:   ImageHeader *h=gforth_header;
  166: 
  167:   if (JUSTUNDER(addr, h->data_stack_base))
  168:     code=-3;
  169:   else if (JUSTOVER(addr, NEXTPAGE(h->data_stack_base+h->data_stack_size)))
  170:     code=-4;
  171:   else if (JUSTUNDER(addr, h->return_stack_base))
  172:     code=-5;
  173:   else if (JUSTOVER(addr, NEXTPAGE(h->return_stack_base+h->return_stack_size)))
  174:     code=-6;
  175:   else if (JUSTUNDER(addr, h->fp_stack_base))
  176:     code=-44;
  177:   else if (JUSTOVER(addr, NEXTPAGE(h->fp_stack_base+h->fp_stack_size)))
  178:     code=-45;
  179:   longjmp(throw_jmp_buf,code);
  180: }
  181: 
  182: #endif /* defined(SA_SIGINFO) */
  183: 
  184: #ifdef SIGCONT
  185: static void termprep(int sig)
  186: {
  187:   bsd_signal(sig,termprep);
  188:   terminal_prepped=0;
  189: }
  190: #endif
  191: 
  192: void get_winsize()
  193: {
  194: #ifdef TIOCGWINSZ
  195:   struct winsize size;
  196:   size.ws_row = size.ws_col = 0;
  197:   
  198:   if (ioctl (1, TIOCGWINSZ, (char *) &size) >= 0) {
  199:     rows = size.ws_row;
  200:     cols = size.ws_col;
  201:   }
  202: #else
  203:   char *s;
  204:   if ((s=getenv("LINES"))) {
  205:     rows=atoi(s);
  206:   }
  207:   if ((s=getenv("COLUMNS"))) {
  208:     rows=atoi(s);
  209:   }
  210: #endif
  211:   if (rows==0)
  212:     rows=DEFAULTROWS;
  213:   if (rows==0)
  214:     cols=DEFAULTCOLS;
  215: }
  216: 
  217: #ifdef SIGWINCH
  218: static void change_winsize(int sig)
  219: {
  220:   /* signal(sig,change_winsize); should not be necessary with bsd_signal */
  221: #ifdef TIOCGWINSZ
  222:   get_winsize();
  223: #endif
  224: }
  225: #endif
  226: 
  227: void install_signal_handlers(void)
  228: {
  229: 
  230: #if 0
  231: /* these signals are handled right by default, no need to handle them;
  232:    they are listed here just for fun */
  233:   static short sigs_to_default [] = {
  234: #ifdef SIGCHLD
  235:     SIGCHLD,
  236: #endif
  237: #ifdef SIGINFO
  238:     SIGINFO,
  239: #endif
  240: #ifdef SIGIO
  241:     SIGIO,
  242: #endif
  243: #ifdef SIGLOST
  244:     SIGLOST,
  245: #endif
  246: #ifdef SIGKILL
  247:     SIGKILL,
  248: #endif
  249: #ifdef SIGSTOP
  250:     SIGSTOP,
  251: #endif
  252: #ifdef SIGPWR
  253:     SIGPWR,
  254: #endif
  255: #ifdef SIGMSG
  256:     SIGMSG,
  257: #endif
  258: #ifdef SIGDANGER
  259:     SIGDANGER,
  260: #endif
  261: #ifdef SIGMIGRATE
  262:     SIGMIGRATE,
  263: #endif
  264: #ifdef SIGPRE
  265:     SIGPRE,
  266: #endif
  267: #ifdef SIGVIRT
  268:     SIGVIRT,
  269: #endif
  270: #ifdef SIGGRANT
  271:     SIGGRANT,
  272: #endif
  273: #ifdef SIGRETRACT
  274:     SIGRETRACT,
  275: #endif
  276: #ifdef SIGSOUND
  277:     SIGSOUND,
  278: #endif
  279: #ifdef SIGSAK
  280:     SIGSAK,
  281: #endif
  282: #ifdef SIGTSTP
  283:     SIGTSTP,
  284: #endif
  285: #ifdef SIGTTIN
  286:     SIGTTIN,
  287: #endif
  288: #ifdef SIGTTOU
  289:     SIGTTOU,
  290: #endif
  291: #ifdef SIGSTKFLT
  292:     SIGSTKFLT,
  293: #endif
  294: #ifdef SIGUNUSED
  295:     SIGUNUSED,
  296: #endif
  297:   };
  298: #endif
  299: 
  300:   static short sigs_to_throw [] = {
  301: #ifdef SIGBREAK
  302:     SIGBREAK,
  303: #endif
  304: #ifdef SIGINT
  305:     SIGINT,
  306: #endif
  307: #ifdef SIGILL
  308:     SIGILL,
  309: #endif
  310: #ifdef SIGEMT
  311:     SIGEMT,
  312: #endif
  313: #ifdef SIGFPE
  314:     SIGFPE,
  315: #endif
  316: #ifdef SIGIOT
  317:     SIGIOT,
  318: #endif
  319: #ifdef SIGSEGV
  320:     SIGSEGV,
  321: #endif
  322: #ifdef SIGALRM
  323:     SIGALRM,
  324: #endif
  325: #ifdef SIGPIPE
  326:     SIGPIPE,
  327: #endif
  328: #ifdef SIGPOLL
  329:     SIGPOLL,
  330: #endif
  331: #ifdef SIGPROF
  332:     SIGPROF,
  333: #endif
  334: #ifdef SIGBUS
  335:     SIGBUS,
  336: #endif
  337: #ifdef SIGSYS
  338:     SIGSYS,
  339: #endif
  340: #ifdef SIGTRAP
  341:     SIGTRAP,
  342: #endif
  343: #ifdef SIGURG
  344:     SIGURG,
  345: #endif
  346: #ifdef SIGUSR1
  347:     SIGUSR1,
  348: #endif
  349: #ifdef SIGUSR2
  350:     SIGUSR2,
  351: #endif
  352: #ifdef SIGVTALRM
  353:     SIGVTALRM,
  354: #endif
  355: #ifdef SIGXFSZ
  356:     SIGXFSZ,
  357: #endif
  358:   };
  359:   static short sigs_to_quit [] = {
  360: #ifdef SIGQUIT
  361:     SIGQUIT,
  362: #endif
  363: #ifdef SIGHUP
  364:     SIGHUP,
  365: #endif
  366: #ifdef SIGABRT
  367:     SIGABRT,
  368: #endif
  369: #ifdef SIGTERM
  370:     SIGTERM,
  371: #endif
  372: #ifdef SIGXCPU
  373:     SIGXCPU,
  374: #endif
  375:   };
  376:   int i;
  377:   void (*throw_handler)() = die_on_signal ? graceful_exit : signal_throw;
  378: #ifdef SIGSTKSZ 
  379:   stack_t sigstack;
  380:   int sas_retval=-1;
  381: 
  382:   sigstack.ss_size=SIGSTKSZ;
  383:   /* Actually the stack should only be ss_size large, and according to
  384:      SUSv2 ss_sp should point to the start of the stack, but
  385:      unfortunately Irix 6.5 (at least) expects ss_sp to point to the
  386:      end, so we work around this issue by accomodating everyone. */
  387:   if ((sigstack.ss_sp = my_alloc(sigstack.ss_size*2)) != NULL) {
  388:     sigstack.ss_sp += sigstack.ss_size;
  389:     sigstack.ss_flags=0;
  390:     sas_retval=sigaltstack(&sigstack,(stack_t *)0);
  391:   }
  392:   if (debug)
  393:     fprintf(stderr,"sigaltstack: %s\n",strerror(sas_retval));
  394: #endif
  395: 
  396: #define DIM(X)		(sizeof (X) / sizeof *(X))
  397: /*
  398:   for (i = 0; i < DIM (sigs_to_ignore); i++)
  399:     signal (sigs_to_ignore [i], SIG_IGN);
  400: */
  401:   for (i = 0; i < DIM (sigs_to_throw); i++)
  402:     bsd_signal(sigs_to_throw[i], throw_handler);
  403:   for (i = 0; i < DIM (sigs_to_quit); i++)
  404:     bsd_signal(sigs_to_quit [i], graceful_exit);
  405: #ifdef SA_SIGINFO
  406:   if (!die_on_signal) {
  407: #ifdef SIGFPE
  408:     install_signal_handler(SIGFPE, fpe_handler);
  409: #endif
  410: #ifdef SIGSEGV
  411:     install_signal_handler(SIGSEGV, segv_handler);
  412: #endif
  413:     /* use SA_ONSTACK for all signals that could come from executing
  414:        wrong code */
  415: #ifdef SIGILL
  416:     install_signal_handler(SIGILL, sigaction_throw);
  417: #endif
  418: #ifdef SIGBUS
  419:     install_signal_handler(SIGBUS, sigaction_throw);
  420: #endif
  421: #ifdef SIGTRAP
  422:     install_signal_handler(SIGTRAP, sigaction_throw);
  423: #endif
  424:   }
  425: #endif /* defined(SA_SIGINFO) */
  426: #ifdef SIGCONT
  427:     bsd_signal(SIGCONT, termprep);
  428: #endif
  429: #ifdef SIGWINCH
  430:     bsd_signal(SIGWINCH, change_winsize);
  431: #endif
  432: }

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