Annotation of gforth/engine/signals.c, revision 1.46
1.1 anton 1: /* signal handling
2:
1.42 anton 3: Copyright (C) 1995,1996,1997,1998,2000,2003,2006,2007,2011 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.46 ! pazsan 104: __thread jmp_buf * throw_jmp_handler;
1.1 anton 105:
1.31 anton 106: void throw(int code)
107: {
1.46 ! pazsan 108: debugp(stderr,"\nthrow code %d to %lx\n", code, (intptr_t)*throw_jmp_handler);
! 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.45 pazsan 145: debugp(stderr,"\nsigaction_throw %d 0x%lx 0x%lx\n", sig, (intptr_t)info, (intptr_t)_);
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))
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:
1.45 pazsan 202: debugp(stderr,"\nsegv_handler %d 0x%lx 0x%lx\n", sig, (intptr_t)info, (intptr_t)_);
1.44 pazsan 203:
1.3 anton 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;
1.31 anton 216: throw(code);
1.1 anton 217: }
218:
1.3 anton 219: #endif /* defined(SA_SIGINFO) */
220:
1.1 anton 221: #ifdef SIGCONT
1.9 anton 222: static void termprep(int sig)
1.1 anton 223: {
1.5 anton 224: bsd_signal(sig,termprep);
1.1 anton 225: terminal_prepped=0;
226: }
227: #endif
228:
229: void get_winsize()
230: {
231: #ifdef TIOCGWINSZ
232: struct winsize size;
1.12 pazsan 233: size.ws_row = size.ws_col = 0;
1.1 anton 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
1.12 pazsan 248: if (rows==0)
249: rows=DEFAULTROWS;
1.37 anton 250: if (cols==0)
1.12 pazsan 251: cols=DEFAULTCOLS;
1.1 anton 252: }
253:
254: #ifdef SIGWINCH
255: static void change_winsize(int sig)
256: {
1.5 anton 257: /* signal(sig,change_winsize); should not be necessary with bsd_signal */
1.1 anton 258: #ifdef TIOCGWINSZ
259: get_winsize();
260: #endif
261: }
262: #endif
263:
1.2 anton 264: void install_signal_handlers(void)
1.1 anton 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:
1.30 anton 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:
1.1 anton 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: };
1.30 anton 399:
1.1 anton 400: static short sigs_to_quit [] = {
1.4 pazsan 401: #ifdef SIGQUIT
402: SIGQUIT,
403: #endif
1.1 anton 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;
1.2 anton 418: void (*throw_handler)() = die_on_signal ? graceful_exit : signal_throw;
1.17 anton 419: #ifdef SIGSTKSZ
1.15 anton 420: stack_t sigstack;
421: int sas_retval=-1;
422:
423: sigstack.ss_size=SIGSTKSZ;
1.23 anton 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. */
1.29 pazsan 428: if ((sigstack.ss_sp = gforth_alloc(sigstack.ss_size*2)) != NULL) {
1.23 anton 429: sigstack.ss_sp += sigstack.ss_size;
1.15 anton 430: sigstack.ss_flags=0;
431: sas_retval=sigaltstack(&sigstack,(stack_t *)0);
432: }
1.35 pazsan 433: #if defined(HAS_FILE) || !defined(STANDALONE)
1.44 pazsan 434: debugp(stderr,"sigaltstack: %s\n",strerror(sas_retval));
1.17 anton 435: #endif
1.34 pazsan 436: #endif
1.1 anton 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++)
1.5 anton 444: bsd_signal(sigs_to_throw[i], throw_handler);
1.30 anton 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);
1.1 anton 448: for (i = 0; i < DIM (sigs_to_quit); i++)
1.5 anton 449: bsd_signal(sigs_to_quit [i], graceful_exit);
1.3 anton 450: #ifdef SA_SIGINFO
1.14 anton 451: if (!die_on_signal) {
1.24 anton 452: #ifdef SIGFPE
1.14 anton 453: install_signal_handler(SIGFPE, fpe_handler);
1.24 anton 454: #endif
455: #ifdef SIGSEGV
1.14 anton 456: install_signal_handler(SIGSEGV, segv_handler);
1.24 anton 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
1.14 anton 469: }
1.24 anton 470: #endif /* defined(SA_SIGINFO) */
1.1 anton 471: #ifdef SIGCONT
1.5 anton 472: bsd_signal(SIGCONT, termprep);
1.1 anton 473: #endif
474: #ifdef SIGWINCH
1.5 anton 475: bsd_signal(SIGWINCH, change_winsize);
1.1 anton 476: #endif
477: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>