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;
}
|