File:
[gforth] /
gforth /
engine /
signals.c
Revision
1.28:
download - view:
text,
annotated -
select for diffs
Wed Aug 20 09:23:46 2003 UTC (20 years, 7 months ago) by
anton
Branches:
MAIN
CVS tags:
v0-6-2,
HEAD
Defined run-time routines (docol etc.) as primitives, eliminated some
special-casing and "+DOESJUMP+1" etc. in engine.c and main.c
Defined the enum type PrimNum and replaced many shorts with PrimNums
(gives nicer gdb output)
Workaround for the absence of the FPE_... macros in FreeBSD/Alpha 4_STABLE
1: /* signal handling
2:
3: Copyright (C) 1995,1996,1997,1998,2000,2003 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: Sigfunc *bsd_signal(int signo, Sigfunc *func)
76: {
77: struct sigaction act, oact;
78:
79: act.sa_handler=func;
80: sigemptyset(&act.sa_mask);
81: act.sa_flags=SA_NODEFER; /* SA_ONSTACK does not work for graceful_exit */
82: if (sigaction(signo,&act,&oact) < 0)
83: return SIG_ERR;
84: else
85: return oact.sa_handler;
86: }
87:
88: static void
89: graceful_exit (int sig)
90: {
91: deprep_terminal();
92: fprintf (stderr, "\n\n%s.\n", strsignal (sig));
93: exit (0x80|sig);
94: }
95:
96: jmp_buf throw_jmp_buf;
97:
98: static void
99: signal_throw(int sig)
100: {
101: int code;
102:
103: switch (sig) {
104: case SIGINT: code=-28; break;
105: case SIGFPE: code=-55; break;
106: #ifdef SIGBUS
107: case SIGBUS: code=-23; break;
108: #endif
109: case SIGSEGV: code=-9; break;
110: #ifdef SIGPIPE
111: case SIGPIPE: code=-2049; break;
112: #endif
113: default: code=-256-sig; break;
114: }
115: #ifdef __CYGWIN__
116: /* the SA_NODEFER apparently does not work on Cygwin 1.3.18(0.69/3/2) */
117: {
118: sigset_t emptyset;
119: sigemptyset(&emptyset);
120: sigprocmask(SIG_SETMASK, &emptyset, NULL);
121: }
122: #endif
123: longjmp(throw_jmp_buf,code); /* !! or use siglongjmp ? */
124: }
125:
126: #ifdef SA_SIGINFO
127: static void
128: sigaction_throw(int sig, siginfo_t *info, void *_)
129: {
130: signal_throw(sig);
131: }
132:
133: static void fpe_handler(int sig, siginfo_t *info, void *_)
134: /* handler for SIGFPE */
135: {
136: int code;
137:
138: switch(info->si_code) {
139: #ifdef FPE_INTDIV
140: case FPE_INTDIV: code=-10; break; /* integer divide by zero */
141: #endif
142: #ifdef FPE_INTOVF
143: case FPE_INTOVF: code=-11; break; /* integer overflow */
144: #endif
145: #ifdef FPE_FLTDIV
146: case FPE_FLTDIV: code=-42; break; /* floating point divide by zero */
147: #endif
148: #ifdef FPE_FLTOVF
149: case FPE_FLTOVF: code=-43; break; /* floating point overflow */
150: #endif
151: #ifdef FPE_FLTUND
152: case FPE_FLTUND: code=-54; break; /* floating point underflow */
153: #endif
154: #ifdef FPE_FLTRES
155: case FPE_FLTRES: code=-41; break; /* floating point inexact result */
156: #endif
157: #if 0 /* defined by Unix95, but unnecessary */
158: case FPE_FLTINV: /* invalid floating point operation */
159: case FPE_FLTSUB: /* subscript out of range */
160: #endif
161: default: code=-55; break;
162: }
163: longjmp(throw_jmp_buf,code);
164: }
165:
166:
167: #define SPILLAGE 128
168: /* if there's a SIGSEGV within SPILLAGE bytes of some stack, we assume
169: that this stack has over/underflowed */
170:
171: #define JUSTUNDER(addr1,addr2) (((UCell)((addr2)-1-(addr1)))<SPILLAGE)
172: /* true is addr1 is just under addr2 */
173:
174: #define JUSTOVER(addr1,addr2) (((UCell)((addr1)-(addr2)))<SPILLAGE)
175:
176: #define NEXTPAGE(addr) ((Address)((((UCell)(addr)-1)&-pagesize)+pagesize))
177:
178: static void segv_handler(int sig, siginfo_t *info, void *_)
179: {
180: int code=-9;
181: Address addr=info->si_addr;
182: ImageHeader *h=gforth_header;
183:
184: if (JUSTUNDER(addr, h->data_stack_base))
185: code=-3;
186: else if (JUSTOVER(addr, NEXTPAGE(h->data_stack_base+h->data_stack_size)))
187: code=-4;
188: else if (JUSTUNDER(addr, h->return_stack_base))
189: code=-5;
190: else if (JUSTOVER(addr, NEXTPAGE(h->return_stack_base+h->return_stack_size)))
191: code=-6;
192: else if (JUSTUNDER(addr, h->fp_stack_base))
193: code=-44;
194: else if (JUSTOVER(addr, NEXTPAGE(h->fp_stack_base+h->fp_stack_size)))
195: code=-45;
196: longjmp(throw_jmp_buf,code);
197: }
198:
199: #endif /* defined(SA_SIGINFO) */
200:
201: #ifdef SIGCONT
202: static void termprep(int sig)
203: {
204: bsd_signal(sig,termprep);
205: terminal_prepped=0;
206: }
207: #endif
208:
209: void get_winsize()
210: {
211: #ifdef TIOCGWINSZ
212: struct winsize size;
213: size.ws_row = size.ws_col = 0;
214:
215: if (ioctl (1, TIOCGWINSZ, (char *) &size) >= 0) {
216: rows = size.ws_row;
217: cols = size.ws_col;
218: }
219: #else
220: char *s;
221: if ((s=getenv("LINES"))) {
222: rows=atoi(s);
223: }
224: if ((s=getenv("COLUMNS"))) {
225: rows=atoi(s);
226: }
227: #endif
228: if (rows==0)
229: rows=DEFAULTROWS;
230: if (rows==0)
231: cols=DEFAULTCOLS;
232: }
233:
234: #ifdef SIGWINCH
235: static void change_winsize(int sig)
236: {
237: /* signal(sig,change_winsize); should not be necessary with bsd_signal */
238: #ifdef TIOCGWINSZ
239: get_winsize();
240: #endif
241: }
242: #endif
243:
244: void install_signal_handlers(void)
245: {
246:
247: #if 0
248: /* these signals are handled right by default, no need to handle them;
249: they are listed here just for fun */
250: static short sigs_to_default [] = {
251: #ifdef SIGCHLD
252: SIGCHLD,
253: #endif
254: #ifdef SIGINFO
255: SIGINFO,
256: #endif
257: #ifdef SIGIO
258: SIGIO,
259: #endif
260: #ifdef SIGLOST
261: SIGLOST,
262: #endif
263: #ifdef SIGKILL
264: SIGKILL,
265: #endif
266: #ifdef SIGSTOP
267: SIGSTOP,
268: #endif
269: #ifdef SIGPWR
270: SIGPWR,
271: #endif
272: #ifdef SIGMSG
273: SIGMSG,
274: #endif
275: #ifdef SIGDANGER
276: SIGDANGER,
277: #endif
278: #ifdef SIGMIGRATE
279: SIGMIGRATE,
280: #endif
281: #ifdef SIGPRE
282: SIGPRE,
283: #endif
284: #ifdef SIGVIRT
285: SIGVIRT,
286: #endif
287: #ifdef SIGGRANT
288: SIGGRANT,
289: #endif
290: #ifdef SIGRETRACT
291: SIGRETRACT,
292: #endif
293: #ifdef SIGSOUND
294: SIGSOUND,
295: #endif
296: #ifdef SIGSAK
297: SIGSAK,
298: #endif
299: #ifdef SIGTSTP
300: SIGTSTP,
301: #endif
302: #ifdef SIGTTIN
303: SIGTTIN,
304: #endif
305: #ifdef SIGTTOU
306: SIGTTOU,
307: #endif
308: #ifdef SIGSTKFLT
309: SIGSTKFLT,
310: #endif
311: #ifdef SIGUNUSED
312: SIGUNUSED,
313: #endif
314: };
315: #endif
316:
317: static short sigs_to_throw [] = {
318: #ifdef SIGBREAK
319: SIGBREAK,
320: #endif
321: #ifdef SIGINT
322: SIGINT,
323: #endif
324: #ifdef SIGILL
325: SIGILL,
326: #endif
327: #ifdef SIGEMT
328: SIGEMT,
329: #endif
330: #ifdef SIGFPE
331: SIGFPE,
332: #endif
333: #ifdef SIGIOT
334: SIGIOT,
335: #endif
336: #ifdef SIGSEGV
337: SIGSEGV,
338: #endif
339: #ifdef SIGALRM
340: SIGALRM,
341: #endif
342: #ifdef SIGPIPE
343: SIGPIPE,
344: #endif
345: #ifdef SIGPOLL
346: SIGPOLL,
347: #endif
348: #ifdef SIGPROF
349: SIGPROF,
350: #endif
351: #ifdef SIGBUS
352: SIGBUS,
353: #endif
354: #ifdef SIGSYS
355: SIGSYS,
356: #endif
357: #ifdef SIGTRAP
358: SIGTRAP,
359: #endif
360: #ifdef SIGURG
361: SIGURG,
362: #endif
363: #ifdef SIGUSR1
364: SIGUSR1,
365: #endif
366: #ifdef SIGUSR2
367: SIGUSR2,
368: #endif
369: #ifdef SIGVTALRM
370: SIGVTALRM,
371: #endif
372: #ifdef SIGXFSZ
373: SIGXFSZ,
374: #endif
375: };
376: static short sigs_to_quit [] = {
377: #ifdef SIGQUIT
378: SIGQUIT,
379: #endif
380: #ifdef SIGHUP
381: SIGHUP,
382: #endif
383: #ifdef SIGABRT
384: SIGABRT,
385: #endif
386: #ifdef SIGTERM
387: SIGTERM,
388: #endif
389: #ifdef SIGXCPU
390: SIGXCPU,
391: #endif
392: };
393: int i;
394: void (*throw_handler)() = die_on_signal ? graceful_exit : signal_throw;
395: #ifdef SIGSTKSZ
396: stack_t sigstack;
397: int sas_retval=-1;
398:
399: sigstack.ss_size=SIGSTKSZ;
400: /* Actually the stack should only be ss_size large, and according to
401: SUSv2 ss_sp should point to the start of the stack, but
402: unfortunately Irix 6.5 (at least) expects ss_sp to point to the
403: end, so we work around this issue by accomodating everyone. */
404: if ((sigstack.ss_sp = my_alloc(sigstack.ss_size*2)) != NULL) {
405: sigstack.ss_sp += sigstack.ss_size;
406: sigstack.ss_flags=0;
407: sas_retval=sigaltstack(&sigstack,(stack_t *)0);
408: }
409: if (debug)
410: fprintf(stderr,"sigaltstack: %s\n",strerror(sas_retval));
411: #endif
412:
413: #define DIM(X) (sizeof (X) / sizeof *(X))
414: /*
415: for (i = 0; i < DIM (sigs_to_ignore); i++)
416: signal (sigs_to_ignore [i], SIG_IGN);
417: */
418: for (i = 0; i < DIM (sigs_to_throw); i++)
419: bsd_signal(sigs_to_throw[i], throw_handler);
420: for (i = 0; i < DIM (sigs_to_quit); i++)
421: bsd_signal(sigs_to_quit [i], graceful_exit);
422: #ifdef SA_SIGINFO
423: if (!die_on_signal) {
424: #ifdef SIGFPE
425: install_signal_handler(SIGFPE, fpe_handler);
426: #endif
427: #ifdef SIGSEGV
428: install_signal_handler(SIGSEGV, segv_handler);
429: #endif
430: /* use SA_ONSTACK for all signals that could come from executing
431: wrong code */
432: #ifdef SIGILL
433: install_signal_handler(SIGILL, sigaction_throw);
434: #endif
435: #ifdef SIGBUS
436: install_signal_handler(SIGBUS, sigaction_throw);
437: #endif
438: #ifdef SIGTRAP
439: install_signal_handler(SIGTRAP, sigaction_throw);
440: #endif
441: }
442: #endif /* defined(SA_SIGINFO) */
443: #ifdef SIGCONT
444: bsd_signal(SIGCONT, termprep);
445: #endif
446: #ifdef SIGWINCH
447: bsd_signal(SIGWINCH, change_winsize);
448: #endif
449: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>