File:  [gforth] / gforth / engine / signals.c
Revision 1.37: download - view: text, annotated - select for diffs
Sun Dec 16 15:22:05 2007 UTC (16 years, 3 months ago) by anton
Branches: MAIN
CVS tags: HEAD
Some bugfixes and cleanups by Jorge Acereda <AE069F38-47DD-4037-9434-89A9489456EF@gmail.com>

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

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