File:  [gforth] / gforth / engine / signals.c
Revision 1.52: download - view: text, annotated - select for diffs
Mon Dec 31 15:25:19 2012 UTC (8 years, 5 months ago) by anton
Branches: MAIN
CVS tags: HEAD
updated copyright year

    1: /* signal handling
    2: 
    3:   Copyright (C) 1995,1996,1997,1998,2000,2003,2006,2007,2011,2012 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: PER_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: #define NEXTPAGE2(addr) ((Address)((((UCell)(addr)-1)&-pagesize)+2*pagesize))
  196: #define NEXTPAGE3(addr) ((Address)((((UCell)(addr)-1)&-pagesize)+3*pagesize))
  197: 
  198: static void segv_handler(int sig, siginfo_t *info, void *_)
  199: {
  200:   int code=-9;
  201:   Address addr=info->si_addr;
  202: 
  203:   debugp(stderr,"\nsegv_handler %d %p %p @%p\n", sig, info, _, addr);
  204: 
  205:   if (JUSTUNDER(addr, NEXTPAGE3(gforth_UP)))
  206:     code=-3;
  207:   else if (JUSTOVER(addr, NEXTPAGE(gforth_UP->sp0)))
  208:     code=-4;
  209:   else if (JUSTUNDER(addr, NEXTPAGE2(gforth_UP->sp0)))
  210:     code=-5;
  211:   else if (JUSTOVER(addr, NEXTPAGE(gforth_UP->rp0)))
  212:     code=-6;
  213:   else if (JUSTUNDER(addr, NEXTPAGE2(gforth_UP->rp0)))
  214:     code=-44;
  215:   else if (JUSTOVER(addr, NEXTPAGE(gforth_UP->fp0)))
  216:     code=-45;
  217:   throw(code);
  218: }
  219: 
  220: #endif /* defined(SA_SIGINFO) */
  221: 
  222: #ifdef SIGCONT
  223: static void termprep(int sig)
  224: {
  225:   bsd_signal(sig,termprep);
  226:   terminal_prepped=0;
  227: }
  228: #endif
  229: 
  230: void get_winsize()
  231: {
  232: #ifdef TIOCGWINSZ
  233:   struct winsize size;
  234:   size.ws_row = size.ws_col = 0;
  235:   
  236:   if (ioctl (1, TIOCGWINSZ, (char *) &size) >= 0) {
  237:     rows = size.ws_row;
  238:     cols = size.ws_col;
  239:   }
  240: #else
  241:   char *s;
  242:   if ((s=getenv("LINES"))) {
  243:     rows=atoi(s);
  244:   }
  245:   if ((s=getenv("COLUMNS"))) {
  246:     rows=atoi(s);
  247:   }
  248: #endif
  249:   if (rows==0)
  250:     rows=DEFAULTROWS;
  251:   if (cols==0)
  252:     cols=DEFAULTCOLS;
  253: }
  254: 
  255: #ifdef SIGWINCH
  256: static void change_winsize(int sig)
  257: {
  258:   /* signal(sig,change_winsize); should not be necessary with bsd_signal */
  259: #ifdef TIOCGWINSZ
  260:   get_winsize();
  261: #endif
  262: }
  263: #endif
  264: 
  265: void install_signal_handlers(void)
  266: {
  267: 
  268: #if 0
  269: /* these signals are handled right by default, no need to handle them;
  270:    they are listed here just for fun */
  271:   static short sigs_to_default [] = {
  272: #ifdef SIGCHLD
  273:     SIGCHLD,
  274: #endif
  275: #ifdef SIGINFO
  276:     SIGINFO,
  277: #endif
  278: #ifdef SIGIO
  279:     SIGIO,
  280: #endif
  281: #ifdef SIGLOST
  282:     SIGLOST,
  283: #endif
  284: #ifdef SIGKILL
  285:     SIGKILL,
  286: #endif
  287: #ifdef SIGSTOP
  288:     SIGSTOP,
  289: #endif
  290: #ifdef SIGPWR
  291:     SIGPWR,
  292: #endif
  293: #ifdef SIGMSG
  294:     SIGMSG,
  295: #endif
  296: #ifdef SIGDANGER
  297:     SIGDANGER,
  298: #endif
  299: #ifdef SIGMIGRATE
  300:     SIGMIGRATE,
  301: #endif
  302: #ifdef SIGPRE
  303:     SIGPRE,
  304: #endif
  305: #ifdef SIGVIRT
  306:     SIGVIRT,
  307: #endif
  308: #ifdef SIGGRANT
  309:     SIGGRANT,
  310: #endif
  311: #ifdef SIGRETRACT
  312:     SIGRETRACT,
  313: #endif
  314: #ifdef SIGSOUND
  315:     SIGSOUND,
  316: #endif
  317: #ifdef SIGSAK
  318:     SIGSAK,
  319: #endif
  320: #ifdef SIGTSTP
  321:     SIGTSTP,
  322: #endif
  323: #ifdef SIGTTIN
  324:     SIGTTIN,
  325: #endif
  326: #ifdef SIGTTOU
  327:     SIGTTOU,
  328: #endif
  329: #ifdef SIGSTKFLT
  330:     SIGSTKFLT,
  331: #endif
  332: #ifdef SIGUNUSED
  333:     SIGUNUSED,
  334: #endif
  335:   };
  336: #endif
  337: 
  338:   static short async_sigs_to_throw [] = {
  339: #ifdef SIGINT
  340:     SIGINT,
  341: #endif
  342: #ifdef SIGALRM
  343:     SIGALRM,
  344: #endif
  345: #ifdef SIGPOLL
  346:     SIGPOLL,
  347: #endif
  348: #ifdef SIGPROF
  349:     SIGPROF,
  350: #endif
  351: #ifdef SIGURG
  352:     SIGURG,
  353: #endif
  354: #ifdef SIGPIPE
  355:     SIGPIPE,
  356: #endif
  357: #ifdef SIGUSR1
  358:     SIGUSR1,
  359: #endif
  360: #ifdef SIGUSR2
  361:     SIGUSR2,
  362: #endif
  363: #ifdef SIGVTALRM
  364:     SIGVTALRM,
  365: #endif
  366: #ifdef SIGXFSZ
  367:     SIGXFSZ,
  368: #endif
  369:   };
  370: 
  371:   static short sigs_to_throw [] = {
  372: #ifdef SIGBREAK
  373:     SIGBREAK,
  374: #endif
  375: #ifdef SIGILL
  376:     SIGILL,
  377: #endif
  378: #ifdef SIGEMT
  379:     SIGEMT,
  380: #endif
  381: #ifdef SIGFPE
  382:     SIGFPE,
  383: #endif
  384: #ifdef SIGIOT
  385:     SIGIOT,
  386: #endif
  387: #ifdef SIGSEGV
  388:     SIGSEGV,
  389: #endif
  390: #ifdef SIGBUS
  391:     SIGBUS,
  392: #endif
  393: #ifdef SIGSYS
  394:     SIGSYS,
  395: #endif
  396: #ifdef SIGTRAP
  397:     SIGTRAP,
  398: #endif
  399:   };
  400: 
  401:   static short sigs_to_quit [] = {
  402: #ifdef SIGQUIT
  403:     SIGQUIT,
  404: #endif
  405: #ifdef SIGHUP
  406:     SIGHUP,
  407: #endif
  408: #ifdef SIGABRT
  409:     SIGABRT,
  410: #endif
  411: #ifdef SIGTERM
  412:     SIGTERM,
  413: #endif
  414: #ifdef SIGXCPU
  415:     SIGXCPU,
  416: #endif
  417:   };
  418:   int i;
  419:   void (*throw_handler)() = die_on_signal ? graceful_exit : signal_throw;
  420: #if 0
  421:   /* sigaltstack is now called by gforth_stacks() */
  422: #if defined(SIGSTKSZ)
  423:   stack_t sigstack;
  424:   int sas_retval=-1;
  425: 
  426:   sigstack.ss_size=SIGSTKSZ;
  427:   /* Actually the stack should only be ss_size large, and according to
  428:      SUSv2 ss_sp should point to the start of the stack, but
  429:      unfortunately Irix 6.5 (at least) expects ss_sp to point to the
  430:      end, so we work around this issue by accomodating everyone. */
  431:   if ((sigstack.ss_sp = gforth_alloc(sigstack.ss_size*2)) != NULL) {
  432:     sigstack.ss_sp += sigstack.ss_size;
  433:     sigstack.ss_flags=0;
  434:     sas_retval=sigaltstack(&sigstack,(stack_t *)0);
  435:   }
  436: #if defined(HAS_FILE) || !defined(STANDALONE)
  437:   debugp(stderr,"sigaltstack: %s\n",strerror(sas_retval));
  438: #endif
  439: #endif
  440: #endif
  441: 
  442: #define DIM(X)		(sizeof (X) / sizeof *(X))
  443: /*
  444:   for (i = 0; i < DIM (sigs_to_ignore); i++)
  445:     signal (sigs_to_ignore [i], SIG_IGN);
  446: */
  447:   for (i = 0; i < DIM (sigs_to_throw); i++)
  448:     bsd_signal(sigs_to_throw[i], throw_handler);
  449:   for (i = 0; i < DIM (async_sigs_to_throw); i++)
  450:     bsd_signal(async_sigs_to_throw[i], 
  451:                ignore_async_signals ? SIG_IGN : throw_handler);
  452:   for (i = 0; i < DIM (sigs_to_quit); i++)
  453:     bsd_signal(sigs_to_quit [i], graceful_exit);
  454: #ifdef SA_SIGINFO
  455:   if (!die_on_signal) {
  456: #ifdef SIGFPE
  457:     install_signal_handler(SIGFPE, fpe_handler);
  458: #endif
  459: #ifdef SIGSEGV
  460:     install_signal_handler(SIGSEGV, segv_handler);
  461: #endif
  462:     /* use SA_ONSTACK for all signals that could come from executing
  463:        wrong code */
  464: #ifdef SIGILL
  465:     install_signal_handler(SIGILL, sigaction_throw);
  466: #endif
  467: #ifdef SIGBUS
  468:     install_signal_handler(SIGBUS, sigaction_throw);
  469: #endif
  470: #ifdef SIGTRAP
  471:     install_signal_handler(SIGTRAP, sigaction_throw);
  472: #endif
  473:   }
  474: #endif /* defined(SA_SIGINFO) */
  475: #ifdef SIGCONT
  476:     bsd_signal(SIGCONT, termprep);
  477: #endif
  478: #ifdef SIGWINCH
  479:     bsd_signal(SIGWINCH, change_winsize);
  480: #endif
  481: }

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