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