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