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