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