File: signals.c

package info (click to toggle)
gforth 0.7.0+ds2-0.1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 5,808 kB
  • sloc: ansic: 8,506; sh: 3,660; lisp: 1,783; makefile: 993; yacc: 186; sed: 141; lex: 102; awk: 21
file content (462 lines) | stat: -rw-r--r-- 9,527 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
/* signal handling

  Copyright (C) 1995,1996,1997,1998,2000,2003,2006,2007 Free Software Foundation, Inc.

  This file is part of Gforth.

  Gforth is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation, either version 3
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, see http://www.gnu.org/licenses/.

*/


#include "config.h"
#include "forth.h"
#include <stdio.h>
#include <setjmp.h>
#include <string.h>
#include <stdlib.h>
#if !defined(apollo) && !defined(MSDOS)
#include <sys/ioctl.h>
#endif
/* #include <asm/signal.h> */
#include <sys/types.h>
#include <signal.h>
#include "io.h"

#ifndef HAVE_STACK_T
/* Darwin uses "struct sigaltstack" instead of "stack_t" */
typedef struct sigaltstack stack_t;
#endif

#define DEFAULTCOLS 80
#if defined(MSDOS) || defined (_WIN32) || defined (__CYGWIN__)
#define DEFAULTROWS 25
#else
#define DEFAULTROWS 24
#endif

UCell cols=DEFAULTCOLS;
UCell rows=DEFAULTROWS;

#ifndef SA_NODEFER
#define SA_NODEFER 0
/* systems that don't have SA_NODEFER hopefully don't block anyway */
#endif

#ifndef SA_ONSTACK
#define SA_ONSTACK 0
#endif

#ifdef SA_SIGINFO
void install_signal_handler(int sig, void (*handler)(int, siginfo_t *, void *))
     /* installs three-argument signal handler for sig */
{
  struct sigaction action;

  action.sa_sigaction=handler;
  sigemptyset(&action.sa_mask);
  action.sa_flags=SA_RESTART|SA_NODEFER|SA_SIGINFO|SA_ONSTACK; /* pass siginfo */
  sigaction(sig, &action, NULL);
}
#endif

Sigfunc *bsd_signal(int signo, Sigfunc *func)
{
  struct sigaction act, oact;

  act.sa_handler=func;
  sigemptyset(&act.sa_mask);
  act.sa_flags=SA_NODEFER; /* SA_ONSTACK does not work for graceful_exit */
  if (sigaction(signo,&act,&oact) < 0)
    return SIG_ERR;
  else
    return oact.sa_handler;
}

static void
graceful_exit (int sig)
{
  deprep_terminal();
  fprintf (stderr, "\n\n%s.\n", strsignal (sig));
  exit (0x80|sig);
}

jmp_buf throw_jmp_buf;

void throw(int code)
{
  longjmp(throw_jmp_buf,code); /* !! or use siglongjmp ? */
}

static void 
signal_throw(int sig)
{
  int code;

  switch (sig) {
  case SIGINT: code=-28; break;
  case SIGFPE: code=-55; break;
#ifdef SIGBUS
  case SIGBUS: code=-23; break;
#endif
  case SIGSEGV: code=-9; break;
#ifdef SIGPIPE
  case SIGPIPE: code=-2049; break;
#endif
  default: code=-256-sig; break;
  }
#ifdef __CYGWIN__
  /* the SA_NODEFER apparently does not work on Cygwin 1.3.18(0.69/3/2) */
  {
    sigset_t emptyset;
    sigemptyset(&emptyset);
    sigprocmask(SIG_SETMASK, &emptyset, NULL);
  }
#endif
  throw(code);
}

#ifdef SA_SIGINFO
static void
sigaction_throw(int sig, siginfo_t *info, void *_)
{
  signal_throw(sig);
}

static void fpe_handler(int sig, siginfo_t *info, void *_)
     /* handler for SIGFPE */
{
  int code;

  switch(info->si_code) {
#ifdef FPE_INTDIV
  case FPE_INTDIV: code=BALL_DIVZERO; break;
#endif
#ifdef FPE_INTOVF
  case FPE_INTOVF: code=BALL_RESULTRANGE; break; /* integer overflow */
#endif
#ifdef FPE_FLTDIV
  case FPE_FLTDIV: code=-42; break; /* floating point divide by zero */
#endif
#ifdef FPE_FLTOVF
  case FPE_FLTOVF: code=-43; break; /* floating point overflow  */
#endif
#ifdef FPE_FLTUND
  case FPE_FLTUND: code=-54; break; /* floating point underflow  */
#endif
#ifdef FPE_FLTRES
  case FPE_FLTRES: code=-41; break; /* floating point inexact result  */
#endif
#if 0 /* defined by Unix95, but unnecessary */
  case FPE_FLTINV: /* invalid floating point operation  */
  case FPE_FLTSUB: /* subscript out of range  */
#endif
  default: code=-55; break;
  }
  throw(code);
}


#define SPILLAGE 128
/* if there's a SIGSEGV within SPILLAGE bytes of some stack, we assume
   that this stack has over/underflowed */

#define JUSTUNDER(addr1,addr2) (((UCell)((addr2)-1-(addr1)))<SPILLAGE)
/* true is addr1 is just under addr2 */

#define JUSTOVER(addr1,addr2) (((UCell)((addr1)-(addr2)))<SPILLAGE)

#define NEXTPAGE(addr) ((Address)((((UCell)(addr)-1)&-pagesize)+pagesize))

static void segv_handler(int sig, siginfo_t *info, void *_)
{
  int code=-9;
  Address addr=info->si_addr;
  ImageHeader *h=gforth_header;

  if (JUSTUNDER(addr, h->data_stack_base))
    code=-3;
  else if (JUSTOVER(addr, NEXTPAGE(h->data_stack_base+h->data_stack_size)))
    code=-4;
  else if (JUSTUNDER(addr, h->return_stack_base))
    code=-5;
  else if (JUSTOVER(addr, NEXTPAGE(h->return_stack_base+h->return_stack_size)))
    code=-6;
  else if (JUSTUNDER(addr, h->fp_stack_base))
    code=-44;
  else if (JUSTOVER(addr, NEXTPAGE(h->fp_stack_base+h->fp_stack_size)))
    code=-45;
  throw(code);
}

#endif /* defined(SA_SIGINFO) */

#ifdef SIGCONT
static void termprep(int sig)
{
  bsd_signal(sig,termprep);
  terminal_prepped=0;
}
#endif

void get_winsize()
{
#ifdef TIOCGWINSZ
  struct winsize size;
  size.ws_row = size.ws_col = 0;
  
  if (ioctl (1, TIOCGWINSZ, (char *) &size) >= 0) {
    rows = size.ws_row;
    cols = size.ws_col;
  }
#else
  char *s;
  if ((s=getenv("LINES"))) {
    rows=atoi(s);
  }
  if ((s=getenv("COLUMNS"))) {
    rows=atoi(s);
  }
#endif
  if (rows==0)
    rows=DEFAULTROWS;
  if (cols==0)
    cols=DEFAULTCOLS;
}

#ifdef SIGWINCH
static void change_winsize(int sig)
{
  /* signal(sig,change_winsize); should not be necessary with bsd_signal */
#ifdef TIOCGWINSZ
  get_winsize();
#endif
}
#endif

void install_signal_handlers(void)
{

#if 0
/* these signals are handled right by default, no need to handle them;
   they are listed here just for fun */
  static short sigs_to_default [] = {
#ifdef SIGCHLD
    SIGCHLD,
#endif
#ifdef SIGINFO
    SIGINFO,
#endif
#ifdef SIGIO
    SIGIO,
#endif
#ifdef SIGLOST
    SIGLOST,
#endif
#ifdef SIGKILL
    SIGKILL,
#endif
#ifdef SIGSTOP
    SIGSTOP,
#endif
#ifdef SIGPWR
    SIGPWR,
#endif
#ifdef SIGMSG
    SIGMSG,
#endif
#ifdef SIGDANGER
    SIGDANGER,
#endif
#ifdef SIGMIGRATE
    SIGMIGRATE,
#endif
#ifdef SIGPRE
    SIGPRE,
#endif
#ifdef SIGVIRT
    SIGVIRT,
#endif
#ifdef SIGGRANT
    SIGGRANT,
#endif
#ifdef SIGRETRACT
    SIGRETRACT,
#endif
#ifdef SIGSOUND
    SIGSOUND,
#endif
#ifdef SIGSAK
    SIGSAK,
#endif
#ifdef SIGTSTP
    SIGTSTP,
#endif
#ifdef SIGTTIN
    SIGTTIN,
#endif
#ifdef SIGTTOU
    SIGTTOU,
#endif
#ifdef SIGSTKFLT
    SIGSTKFLT,
#endif
#ifdef SIGUNUSED
    SIGUNUSED,
#endif
  };
#endif

  static short async_sigs_to_throw [] = {
#ifdef SIGINT
    SIGINT,
#endif
#ifdef SIGALRM
    SIGALRM,
#endif
#ifdef SIGPOLL
    SIGPOLL,
#endif
#ifdef SIGPROF
    SIGPROF,
#endif
#ifdef SIGURG
    SIGURG,
#endif
#ifdef SIGPIPE
    SIGPIPE,
#endif
#ifdef SIGUSR1
    SIGUSR1,
#endif
#ifdef SIGUSR2
    SIGUSR2,
#endif
#ifdef SIGVTALRM
    SIGVTALRM,
#endif
#ifdef SIGXFSZ
    SIGXFSZ,
#endif
  };

  static short sigs_to_throw [] = {
#ifdef SIGBREAK
    SIGBREAK,
#endif
#ifdef SIGILL
    SIGILL,
#endif
#ifdef SIGEMT
    SIGEMT,
#endif
#ifdef SIGFPE
    SIGFPE,
#endif
#ifdef SIGIOT
    SIGIOT,
#endif
#ifdef SIGSEGV
    SIGSEGV,
#endif
#ifdef SIGBUS
    SIGBUS,
#endif
#ifdef SIGSYS
    SIGSYS,
#endif
#ifdef SIGTRAP
    SIGTRAP,
#endif
  };

  static short sigs_to_quit [] = {
#ifdef SIGQUIT
    SIGQUIT,
#endif
#ifdef SIGHUP
    SIGHUP,
#endif
#ifdef SIGABRT
    SIGABRT,
#endif
#ifdef SIGTERM
    SIGTERM,
#endif
#ifdef SIGXCPU
    SIGXCPU,
#endif
  };
  int i;
  void (*throw_handler)() = die_on_signal ? graceful_exit : signal_throw;
#ifdef SIGSTKSZ 
  stack_t sigstack;
  int sas_retval=-1;

  sigstack.ss_size=SIGSTKSZ;
  /* Actually the stack should only be ss_size large, and according to
     SUSv2 ss_sp should point to the start of the stack, but
     unfortunately Irix 6.5 (at least) expects ss_sp to point to the
     end, so we work around this issue by accomodating everyone. */
  if ((sigstack.ss_sp = gforth_alloc(sigstack.ss_size*2)) != NULL) {
    sigstack.ss_sp += sigstack.ss_size;
    sigstack.ss_flags=0;
    sas_retval=sigaltstack(&sigstack,(stack_t *)0);
  }
#if defined(HAS_FILE) || !defined(STANDALONE)
  if (debug)
    fprintf(stderr,"sigaltstack: %s\n",strerror(sas_retval));
#endif
#endif

#define DIM(X)		(sizeof (X) / sizeof *(X))
/*
  for (i = 0; i < DIM (sigs_to_ignore); i++)
    signal (sigs_to_ignore [i], SIG_IGN);
*/
  for (i = 0; i < DIM (sigs_to_throw); i++)
    bsd_signal(sigs_to_throw[i], throw_handler);
  for (i = 0; i < DIM (async_sigs_to_throw); i++)
    bsd_signal(async_sigs_to_throw[i], 
               ignore_async_signals ? SIG_IGN : throw_handler);
  for (i = 0; i < DIM (sigs_to_quit); i++)
    bsd_signal(sigs_to_quit [i], graceful_exit);
#ifdef SA_SIGINFO
  if (!die_on_signal) {
#ifdef SIGFPE
    install_signal_handler(SIGFPE, fpe_handler);
#endif
#ifdef SIGSEGV
    install_signal_handler(SIGSEGV, segv_handler);
#endif
    /* use SA_ONSTACK for all signals that could come from executing
       wrong code */
#ifdef SIGILL
    install_signal_handler(SIGILL, sigaction_throw);
#endif
#ifdef SIGBUS
    install_signal_handler(SIGBUS, sigaction_throw);
#endif
#ifdef SIGTRAP
    install_signal_handler(SIGTRAP, sigaction_throw);
#endif
  }
#endif /* defined(SA_SIGINFO) */
#ifdef SIGCONT
    bsd_signal(SIGCONT, termprep);
#endif
#ifdef SIGWINCH
    bsd_signal(SIGWINCH, change_winsize);
#endif
}