File:  [gforth] / gforth / engine / signals.c
Revision 1.42: download - view: text, annotated - select for diffs
Sat Dec 31 15:29:26 2011 UTC (10 years, 7 months ago) by anton
Branches: MAIN
CVS tags: HEAD
updated copyright years

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

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