File: sighandlers1.c

package info (click to toggle)
scsh 0.5.1-2
  • links: PTS
  • area: non-free
  • in suites: potato, slink
  • size: 6,540 kB
  • ctags: 8,656
  • sloc: lisp: 39,346; ansic: 13,466; sh: 1,669; makefile: 624
file content (197 lines) | stat: -rw-r--r-- 5,208 bytes parent folder | download
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
/* Need to define sig2interrupt vector.
** Interrupt-system mutators should probably hold interrupts while they
**   operate.
*/

#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include "cstuff.h"

/* Make sure our exports match up w/the implementation: */
#include "sighandlers1.h"

/* Import the OS-dependent set of signals and their translations
** to S48 vm interrupts.
*/
#include "signals1.h"

extern int errno;

extern scheme_value Spending_interruptsS, Sinterrupt_handlersS;

/* Translate Unix signal numbers to S48 interrupt numbers. */

int sig2interrupt(int signal)
{
  return ( signal < 0 || signal > max_sig ) ? -1 : sig2int[signal];
  }


/* Hack the blocked-signal mask.
*******************************************************************************
*/


#include "machine/sigset.h"

int set_procmask(int hi, int lo, int *old_lo_p)
{
    sigset_t mask, old_mask;
    int old_hi;

    make_sigset(&mask, hi, lo);
    
    sigprocmask(SIG_SETMASK, &mask, &old_mask);
    split_sigset(old_mask, &old_hi, old_lo_p);
    return old_hi;
    }


int get_procmask(int *old_lo_p)
{
    sigset_t old_mask;
    int old_hi;

    sigprocmask(SIG_SETMASK, NULL, &old_mask);
    split_sigset(old_mask, &old_hi, old_lo_p);
    return old_hi;
    }


/* Set/Get signal handlers
*******************************************************************************
*/

static void scm_handle_sig(int sig)
{
  /*fprintf(stderr, "scm_handle_sig(%d) = int %d\n", sig, sig2int[sig]);*/
  Spending_interruptsS |= (1<<sig2int[sig]);
  }


/* handler_code: 0 => ignore, 1 => default, 2 => S48 VM */

/* Common code for two functions above. */
static scheme_value scsh_ret_sig(int retval, struct sigaction *oldsa,
				 int *old_hc, int *oflags)
{
    if( retval ) {
	*old_hc = -1;
	*oflags = -1;
	return ENTER_FIXNUM(errno);
	}
    if( oldsa->sa_handler == SIG_IGN )             *old_hc = 0;
    else if( oldsa->sa_handler == SIG_DFL )        *old_hc = 1;
    else if( oldsa->sa_handler == scm_handle_sig ) *old_hc = 2;
    else *old_hc = ENTER_FIXNUM(3); /* Unknown signal handler. */

    *oflags = oldsa->sa_flags;
    return SCHFALSE;
    }
      

scheme_value scsh_set_sig(int sig, int handler_code, int flags,
			  int *old_hc, int *oflags)
{
    struct sigaction new, old;

    sigemptyset(&new.sa_mask); /* WTF */
    new.sa_flags = flags;

    switch( handler_code ) {
    case 0: new.sa_handler = SIG_IGN; break;
    case 1: new.sa_handler = SIG_DFL; break;
    case 2: new.sa_handler = scm_handle_sig; break;
    default:
      fprintf(stderr, "Impossible handler_code in set_sig_handler: %d\n",
	      handler_code);
      exit(-1);
    }

    return scsh_ret_sig(sigaction(sig, &new, &old),
			&old, old_hc, oflags);
    }


scheme_value scsh_get_sig(int signal, int *old_hc, int *oflags)
{
    struct sigaction old;
    return scsh_ret_sig(sigaction(signal, NULL, &old),
			&old, old_hc, oflags);
    }


/* This guy is responsible for making the default action for a
** Unix signal happen. Because S48's signal handler system is
** interposed between delivery-to-the-process and
** delivery-to-the-scheme-handler, when the user sets a signal
** handler to default, we install a Scheme proc that calls this
** guy, instead of just slapping a SIGDFL in as the Unix handler.
** We only have to do this for signals whose default isn't "ignore," i.e.:
**   Posix: SIGALRM SIGHUP SIGINT SIGQUIT SIGTERM SIGUSR1 SIGUSR2
**   Non-Posix: SIGINFO SIGPOLL SIGPROF SIGVTALRM SIGXCPU SIGXFSZ SIGIO
** This way, the S48 signal-blocking mechanism can work.
**
** Weird, I know.
*/
void do_default_sigaction(int signal)
{
  sigset_t ss, old_ss;
  struct sigaction default_action, old_action;

  /* fprintf(stderr, "Doing default for signal %d\n", signal); */

  sigfillset(&ss);				/* Block everyone. */
  sigprocmask(SIG_SETMASK, &ss, &old_ss);

  default_action.sa_handler = SIG_DFL;		/* Set for default. */
  sigemptyset(&default_action.sa_mask);
  default_action.sa_flags = 0;
  sigaction(signal, &default_action, &old_action);

  raise(signal);			      	/* Raise the signal. */
  sigdelset(&ss, signal);
  sigprocmask(SIG_SETMASK, &ss, 0);		/* Handle it. */

  /* Most likely, we'll never get to here, as the default for
  ** the signals we're handling is "terminate," but we'll play it safe.
  */
  sigaction(signal, &old_action, 0);		/* Restore old handler, */
  sigprocmask(SIG_SETMASK, &old_ss, 0);		/* and mask.            */
  }


/* Set up the Unix signal system the way we want it for scsh. */

void install_scsh_handlers(void)
{
  struct sigaction new;
  int i;

  sigemptyset(&new.sa_mask); /* WTF */
  new.sa_handler = scm_handle_sig;
  new.sa_flags = 0;

  for(i=max_sig; i>=0; i--)
    if( sig2int[i] ) {
      /* This is a signal we want the S48 interrupt system to handle. */
      sigaction(i, &new, 0);
      }

  /* Turn off SIGPIPE and SIGSYS -- they are handled by synchronous exceptions
  ** triggered by errno returns.
  */
  new.sa_handler = SIG_IGN;
  sigaction(SIGPIPE, &new, 0);
#ifdef SIGSYS
  sigaction(SIGSYS, &new, 0);
#endif
  }

/* Sneak me the S48 interrupt handlers vector. */
scheme_value get_int_handlers(void)
{
  return Sinterrupt_handlersS;
  }