198 lines
5.1 KiB
C
198 lines
5.1 KiB
C
/* 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( ( i != SIGINT ) && 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;
|
|
}
|