Annotation of gforth/engine/signals.c, revision 1.52

1.1       anton       1: /* signal handling
                      2: 
1.52    ! anton       3:   Copyright (C) 1995,1996,1997,1998,2000,2003,2006,2007,2011,2012 Free Software Foundation, Inc.
1.1       anton       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
1.39      anton       9:   as published by the Free Software Foundation, either version 3
1.1       anton      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
1.39      anton      18:   along with this program; if not, see http://www.gnu.org/licenses/.
1.1       anton      19: 
                     20: */
                     21: 
                     22: 
1.19      anton      23: #include "config.h"
                     24: #include "forth.h"
1.1       anton      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
1.20      anton      32: #include <sys/types.h>
1.2       anton      33: #include <signal.h>
1.41      pazsan     34: #include <termios.h>
1.1       anton      35: #include "io.h"
                     36: 
1.44      pazsan     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: 
1.20      anton      46: #ifndef HAVE_STACK_T
                     47: /* Darwin uses "struct sigaltstack" instead of "stack_t" */
                     48: typedef struct sigaltstack stack_t;
                     49: #endif
1.1       anton      50: 
                     51: #define DEFAULTCOLS 80
1.36      pazsan     52: #if defined(MSDOS) || defined (_WIN32) || defined (__CYGWIN__)
1.1       anton      53: #define DEFAULTROWS 25
                     54: #else
                     55: #define DEFAULTROWS 24
                     56: #endif
                     57: 
                     58: UCell cols=DEFAULTCOLS;
                     59: UCell rows=DEFAULTROWS;
                     60: 
1.7       anton      61: #ifndef SA_NODEFER
1.8       anton      62: #define SA_NODEFER 0
1.7       anton      63: /* systems that don't have SA_NODEFER hopefully don't block anyway */
                     64: #endif
                     65: 
1.17      anton      66: #ifndef SA_ONSTACK
                     67: #define SA_ONSTACK 0
                     68: #endif
                     69: 
1.5       anton      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);
1.15      anton      78:   action.sa_flags=SA_RESTART|SA_NODEFER|SA_SIGINFO|SA_ONSTACK; /* pass siginfo */
1.5       anton      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);
1.18      anton      89:   act.sa_flags=SA_NODEFER; /* SA_ONSTACK does not work for graceful_exit */
1.5       anton      90:   if (sigaction(signo,&act,&oact) < 0)
                     91:     return SIG_ERR;
                     92:   else
                     93:     return oact.sa_handler;
                     94: }
1.1       anton      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: 
1.50      pazsan    104: PER_THREAD jmp_buf * throw_jmp_handler;
1.1       anton     105: 
1.31      anton     106: void throw(int code)
                    107: {
1.47      pazsan    108:   debugp(stderr,"\nthrow code %d to %p\n", code, *throw_jmp_handler);
1.46      pazsan    109:   longjmp(*throw_jmp_handler,code); /* !! or use siglongjmp ? */
1.31      anton     110: }
                    111: 
1.1       anton     112: static void 
                    113: signal_throw(int sig)
                    114: {
                    115:   int code;
1.44      pazsan    116:   debugp(stderr,"\ncaught signal %d\n", sig);
1.3       anton     117: 
                    118:   switch (sig) {
                    119:   case SIGINT: code=-28; break;
                    120:   case SIGFPE: code=-55; break;
1.1       anton     121: #ifdef SIGBUS
1.3       anton     122:   case SIGBUS: code=-23; break;
1.1       anton     123: #endif
1.3       anton     124:   case SIGSEGV: code=-9; break;
1.25      anton     125: #ifdef SIGPIPE
                    126:   case SIGPIPE: code=-2049; break;
                    127: #endif
1.3       anton     128:   default: code=-256-sig; break;
                    129:   }
1.26      anton     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
1.31      anton     138:   throw(code);
1.3       anton     139: }
                    140: 
                    141: #ifdef SA_SIGINFO
1.24      anton     142: static void
                    143: sigaction_throw(int sig, siginfo_t *info, void *_)
                    144: {
1.49      pazsan    145:   debugp(stderr,"\nsigaction_throw %d %p %p\n", sig, info, _);
1.24      anton     146:   signal_throw(sig);
                    147: }
                    148: 
1.3       anton     149: static void fpe_handler(int sig, siginfo_t *info, void *_)
                    150:      /* handler for SIGFPE */
                    151: {
                    152:   int code;
                    153: 
1.44      pazsan    154:   debugp(stderr,"\nfpe_handler %d %x %x\n", sig, info, _);
                    155: 
1.3       anton     156:   switch(info->si_code) {
1.16      anton     157: #ifdef FPE_INTDIV
1.32      anton     158:   case FPE_INTDIV: code=BALL_DIVZERO; break;
1.16      anton     159: #endif
                    160: #ifdef FPE_INTOVF
1.32      anton     161:   case FPE_INTOVF: code=BALL_RESULTRANGE; break; /* integer overflow */
1.16      anton     162: #endif
1.28      anton     163: #ifdef FPE_FLTDIV
1.3       anton     164:   case FPE_FLTDIV: code=-42; break; /* floating point divide by zero */
1.28      anton     165: #endif
                    166: #ifdef FPE_FLTOVF
1.3       anton     167:   case FPE_FLTOVF: code=-43; break; /* floating point overflow  */
1.28      anton     168: #endif
                    169: #ifdef FPE_FLTUND
1.3       anton     170:   case FPE_FLTUND: code=-54; break; /* floating point underflow  */
1.28      anton     171: #endif
                    172: #ifdef FPE_FLTRES
1.3       anton     173:   case FPE_FLTRES: code=-41; break; /* floating point inexact result  */
1.28      anton     174: #endif
1.16      anton     175: #if 0 /* defined by Unix95, but unnecessary */
1.3       anton     176:   case FPE_FLTINV: /* invalid floating point operation  */
                    177:   case FPE_FLTSUB: /* subscript out of range  */
1.16      anton     178: #endif
1.3       anton     179:   default: code=-55; break;
                    180:   }
1.31      anton     181:   throw(code);
1.3       anton     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))
1.51      pazsan    195: #define NEXTPAGE2(addr) ((Address)((((UCell)(addr)-1)&-pagesize)+2*pagesize))
                    196: #define NEXTPAGE3(addr) ((Address)((((UCell)(addr)-1)&-pagesize)+3*pagesize))
1.3       anton     197: 
                    198: static void segv_handler(int sig, siginfo_t *info, void *_)
                    199: {
                    200:   int code=-9;
                    201:   Address addr=info->si_addr;
                    202: 
1.51      pazsan    203:   debugp(stderr,"\nsegv_handler %d %p %p @%p\n", sig, info, _, addr);
1.44      pazsan    204: 
1.51      pazsan    205:   if (JUSTUNDER(addr, NEXTPAGE3(gforth_UP)))
1.3       anton     206:     code=-3;
1.51      pazsan    207:   else if (JUSTOVER(addr, NEXTPAGE(gforth_UP->sp0)))
1.3       anton     208:     code=-4;
1.51      pazsan    209:   else if (JUSTUNDER(addr, NEXTPAGE2(gforth_UP->sp0)))
1.3       anton     210:     code=-5;
1.51      pazsan    211:   else if (JUSTOVER(addr, NEXTPAGE(gforth_UP->rp0)))
1.3       anton     212:     code=-6;
1.51      pazsan    213:   else if (JUSTUNDER(addr, NEXTPAGE2(gforth_UP->rp0)))
1.3       anton     214:     code=-44;
1.51      pazsan    215:   else if (JUSTOVER(addr, NEXTPAGE(gforth_UP->fp0)))
1.3       anton     216:     code=-45;
1.31      anton     217:   throw(code);
1.1       anton     218: }
                    219: 
1.3       anton     220: #endif /* defined(SA_SIGINFO) */
                    221: 
1.1       anton     222: #ifdef SIGCONT
1.9       anton     223: static void termprep(int sig)
1.1       anton     224: {
1.5       anton     225:   bsd_signal(sig,termprep);
1.1       anton     226:   terminal_prepped=0;
                    227: }
                    228: #endif
                    229: 
                    230: void get_winsize()
                    231: {
                    232: #ifdef TIOCGWINSZ
                    233:   struct winsize size;
1.12      pazsan    234:   size.ws_row = size.ws_col = 0;
1.1       anton     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
1.12      pazsan    249:   if (rows==0)
                    250:     rows=DEFAULTROWS;
1.37      anton     251:   if (cols==0)
1.12      pazsan    252:     cols=DEFAULTCOLS;
1.1       anton     253: }
                    254: 
                    255: #ifdef SIGWINCH
                    256: static void change_winsize(int sig)
                    257: {
1.5       anton     258:   /* signal(sig,change_winsize); should not be necessary with bsd_signal */
1.1       anton     259: #ifdef TIOCGWINSZ
                    260:   get_winsize();
                    261: #endif
                    262: }
                    263: #endif
                    264: 
1.2       anton     265: void install_signal_handlers(void)
1.1       anton     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: 
1.30      anton     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: 
1.1       anton     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:   };
1.30      anton     400: 
1.1       anton     401:   static short sigs_to_quit [] = {
1.4       pazsan    402: #ifdef SIGQUIT
                    403:     SIGQUIT,
                    404: #endif
1.1       anton     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;
1.2       anton     419:   void (*throw_handler)() = die_on_signal ? graceful_exit : signal_throw;
1.51      pazsan    420: #if 0
                    421:   /* sigaltstack is now called by gforth_stacks() */
1.49      pazsan    422: #if defined(SIGSTKSZ)
1.15      anton     423:   stack_t sigstack;
                    424:   int sas_retval=-1;
                    425: 
                    426:   sigstack.ss_size=SIGSTKSZ;
1.23      anton     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. */
1.29      pazsan    431:   if ((sigstack.ss_sp = gforth_alloc(sigstack.ss_size*2)) != NULL) {
1.23      anton     432:     sigstack.ss_sp += sigstack.ss_size;
1.15      anton     433:     sigstack.ss_flags=0;
                    434:     sas_retval=sigaltstack(&sigstack,(stack_t *)0);
                    435:   }
1.35      pazsan    436: #if defined(HAS_FILE) || !defined(STANDALONE)
1.44      pazsan    437:   debugp(stderr,"sigaltstack: %s\n",strerror(sas_retval));
1.17      anton     438: #endif
1.34      pazsan    439: #endif
1.51      pazsan    440: #endif
1.1       anton     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++)
1.5       anton     448:     bsd_signal(sigs_to_throw[i], throw_handler);
1.30      anton     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);
1.1       anton     452:   for (i = 0; i < DIM (sigs_to_quit); i++)
1.5       anton     453:     bsd_signal(sigs_to_quit [i], graceful_exit);
1.3       anton     454: #ifdef SA_SIGINFO
1.14      anton     455:   if (!die_on_signal) {
1.24      anton     456: #ifdef SIGFPE
1.14      anton     457:     install_signal_handler(SIGFPE, fpe_handler);
1.24      anton     458: #endif
                    459: #ifdef SIGSEGV
1.14      anton     460:     install_signal_handler(SIGSEGV, segv_handler);
1.24      anton     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
1.14      anton     473:   }
1.24      anton     474: #endif /* defined(SA_SIGINFO) */
1.1       anton     475: #ifdef SIGCONT
1.5       anton     476:     bsd_signal(SIGCONT, termprep);
1.1       anton     477: #endif
                    478: #ifdef SIGWINCH
1.5       anton     479:     bsd_signal(SIGWINCH, change_winsize);
1.1       anton     480: #endif
                    481: }

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