Annotation of gforth/engine/signals.c, revision 1.28
1.1 anton 1: /* signal handling
2:
1.27 anton 3: Copyright (C) 1995,1996,1997,1998,2000,2003 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: Sigfunc *bsd_signal(int signo, Sigfunc *func)
76: {
77: struct sigaction act, oact;
78:
79: act.sa_handler=func;
80: sigemptyset(&act.sa_mask);
1.18 anton 81: act.sa_flags=SA_NODEFER; /* SA_ONSTACK does not work for graceful_exit */
1.5 anton 82: if (sigaction(signo,&act,&oact) < 0)
83: return SIG_ERR;
84: else
85: return oact.sa_handler;
86: }
1.1 anton 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;
1.3 anton 102:
103: switch (sig) {
104: case SIGINT: code=-28; break;
105: case SIGFPE: code=-55; break;
1.1 anton 106: #ifdef SIGBUS
1.3 anton 107: case SIGBUS: code=-23; break;
1.1 anton 108: #endif
1.3 anton 109: case SIGSEGV: code=-9; break;
1.25 anton 110: #ifdef SIGPIPE
111: case SIGPIPE: code=-2049; break;
112: #endif
1.3 anton 113: default: code=-256-sig; break;
114: }
1.26 anton 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
1.3 anton 123: longjmp(throw_jmp_buf,code); /* !! or use siglongjmp ? */
124: }
125:
126: #ifdef SA_SIGINFO
1.24 anton 127: static void
128: sigaction_throw(int sig, siginfo_t *info, void *_)
129: {
130: signal_throw(sig);
131: }
132:
1.3 anton 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) {
1.16 anton 139: #ifdef FPE_INTDIV
1.3 anton 140: case FPE_INTDIV: code=-10; break; /* integer divide by zero */
1.16 anton 141: #endif
142: #ifdef FPE_INTOVF
1.3 anton 143: case FPE_INTOVF: code=-11; break; /* integer overflow */
1.16 anton 144: #endif
1.28 ! anton 145: #ifdef FPE_FLTDIV
1.3 anton 146: case FPE_FLTDIV: code=-42; break; /* floating point divide by zero */
1.28 ! anton 147: #endif
! 148: #ifdef FPE_FLTOVF
1.3 anton 149: case FPE_FLTOVF: code=-43; break; /* floating point overflow */
1.28 ! anton 150: #endif
! 151: #ifdef FPE_FLTUND
1.3 anton 152: case FPE_FLTUND: code=-54; break; /* floating point underflow */
1.28 ! anton 153: #endif
! 154: #ifdef FPE_FLTRES
1.3 anton 155: case FPE_FLTRES: code=-41; break; /* floating point inexact result */
1.28 ! anton 156: #endif
1.16 anton 157: #if 0 /* defined by Unix95, but unnecessary */
1.3 anton 158: case FPE_FLTINV: /* invalid floating point operation */
159: case FPE_FLTSUB: /* subscript out of range */
1.16 anton 160: #endif
1.3 anton 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);
1.1 anton 197: }
198:
1.3 anton 199: #endif /* defined(SA_SIGINFO) */
200:
1.1 anton 201: #ifdef SIGCONT
1.9 anton 202: static void termprep(int sig)
1.1 anton 203: {
1.5 anton 204: bsd_signal(sig,termprep);
1.1 anton 205: terminal_prepped=0;
206: }
207: #endif
208:
209: void get_winsize()
210: {
211: #ifdef TIOCGWINSZ
212: struct winsize size;
1.12 pazsan 213: size.ws_row = size.ws_col = 0;
1.1 anton 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
1.12 pazsan 228: if (rows==0)
229: rows=DEFAULTROWS;
230: if (rows==0)
231: cols=DEFAULTCOLS;
1.1 anton 232: }
233:
234: #ifdef SIGWINCH
235: static void change_winsize(int sig)
236: {
1.5 anton 237: /* signal(sig,change_winsize); should not be necessary with bsd_signal */
1.1 anton 238: #ifdef TIOCGWINSZ
239: get_winsize();
240: #endif
241: }
242: #endif
243:
1.2 anton 244: void install_signal_handlers(void)
1.1 anton 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 [] = {
1.4 pazsan 377: #ifdef SIGQUIT
378: SIGQUIT,
379: #endif
1.1 anton 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;
1.2 anton 394: void (*throw_handler)() = die_on_signal ? graceful_exit : signal_throw;
1.17 anton 395: #ifdef SIGSTKSZ
1.15 anton 396: stack_t sigstack;
397: int sas_retval=-1;
398:
399: sigstack.ss_size=SIGSTKSZ;
1.23 anton 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;
1.15 anton 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));
1.17 anton 411: #endif
1.1 anton 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++)
1.5 anton 419: bsd_signal(sigs_to_throw[i], throw_handler);
1.1 anton 420: for (i = 0; i < DIM (sigs_to_quit); i++)
1.5 anton 421: bsd_signal(sigs_to_quit [i], graceful_exit);
1.3 anton 422: #ifdef SA_SIGINFO
1.14 anton 423: if (!die_on_signal) {
1.24 anton 424: #ifdef SIGFPE
1.14 anton 425: install_signal_handler(SIGFPE, fpe_handler);
1.24 anton 426: #endif
427: #ifdef SIGSEGV
1.14 anton 428: install_signal_handler(SIGSEGV, segv_handler);
1.24 anton 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
1.14 anton 441: }
1.24 anton 442: #endif /* defined(SA_SIGINFO) */
1.1 anton 443: #ifdef SIGCONT
1.5 anton 444: bsd_signal(SIGCONT, termprep);
1.1 anton 445: #endif
446: #ifdef SIGWINCH
1.5 anton 447: bsd_signal(SIGWINCH, change_winsize);
1.1 anton 448: #endif
449: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>