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