File:  [gforth] / gforth / engine / signals.c
Revision 1.49: download - view: text, annotated - select for diffs
Sat Mar 24 01:17:52 2012 UTC (12 years ago) by pazsan
Branches: MAIN
CVS tags: HEAD
More consistent use of %p, sigaltstack is back

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

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