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