/* Need to define sig2interrupt vector. ** Interrupt-system mutators should probably hold interrupts while they ** operate. */ #include #include #include #include "cstuff.h" /* Make sure our exports match up w/the implementation: */ #include "sighandlers1.h" extern int errno; extern scheme_value Spending_interruptsS, Sinterrupt_handlersS; /* Translate Unix signal numbers to S48 interrupt numbers. ** alarm, keyboard (^C, SIGINT), and memory shortage are 0, 1, and 2. */ static int sig2interrupt(int signal) { switch (signal) { case SIGALRM: return 0; /* Already defined by S48. */ case SIGCHLD: return 3; case SIGCONT: return 4; case SIGHUP: return 5; case SIGINT: return 1; /* Already defined by S48. */ case SIGQUIT: return 6; case SIGTERM: return 7; case SIGTSTP: return 8; case SIGUSR1: return 9; case SIGUSR2: return 10; #ifdef SIGINFO case SIGINFO: return 11; #endif #ifdef SIGIO case SIGIO: return 12; #endif #ifdef SIGPOLL case SIGPOLL: return 13; #endif #ifdef SIGPROF case SIGPROF: return 14; #endif #ifdef SIGPWR case SIGPWR: return 15; #endif #ifdef SIGURG case SIGURG: return 16; #endif #ifdef SIGVTALRM case SIGVTALRM: return 17; #endif #ifdef SIGWINCH case SIGWINCH: return 18; #endif #ifdef SIGXCPU case SIGXCPU: return 19; #endif #ifdef SIGXFSZ case SIGXFSZ: return 20; #endif default: return -1; } } /* 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) { Spending_interruptsS |= (1<= VECTOR_LENGTH(Sinterrupt_handlersS) ) { *ohandler = SCHFALSE; return ENTER_FIXNUM(-1); } /* We may need this for ohandler later, but it may get clobbered ** when we set the new handler, so stash it away for now. */ old_scsh_handler = VECTOR_REF(Sinterrupt_handlersS, intnum); sigemptyset(&new.sa_mask); /* WTF */ new.sa_flags = flags; if( handler == SCHFALSE ) { new.sa_handler = SIG_IGN; VECTOR_REF(Sinterrupt_handlersS, intnum) = SCHFALSE; } /* This *really* sets the Unix signal handler to SIG_DFL. ** What usually happens isn't this -- what usually happens is that ** we establish a special Scheme handler that does the default, so ** that it is subject to S48's blocking machinery. */ else if( handler == SCHTRUE ) { new.sa_handler = SIG_DFL; VECTOR_REF(Sinterrupt_handlersS, intnum) = SCHFALSE; } else { new.sa_handler = scm_handle_sig; VECTOR_REF(Sinterrupt_handlersS, intnum) = handler; /* Do other stuff. */ } if( sigaction(sig, &new, &old) ) { *ohandler = SCHFALSE; return ENTER_FIXNUM(errno); } *oflags = old.sa_flags; if( old.sa_handler == SIG_IGN ) *ohandler = SCHFALSE; else if( old.sa_handler == SIG_DFL ) *ohandler = SCHTRUE; else if( old.sa_handler == scm_handle_sig ) *ohandler = old_scsh_handler; else *ohandler = ENTER_FIXNUM(-1); /* Unknown signal handler. */ return SCHFALSE; } scheme_value get_sig_handler(int signal, scheme_value *handler, int *flags) { struct sigaction old; if( sigaction(signal, NULL, &old) ) { *handler = SCHFALSE; return ENTER_FIXNUM(errno); } *flags = old.sa_flags; if( old.sa_handler == SIG_IGN ) *handler = SCHFALSE; else if( old.sa_handler == SIG_DFL ) *handler = SCHTRUE; else if( old.sa_handler == scm_handle_sig ) { int intnum = sig2interrupt(signal); /* intnum in range? */ if( intnum >= VECTOR_LENGTH(Sinterrupt_handlersS) ) { *handler = SCHFALSE; return ENTER_FIXNUM(-1); } *handler = VECTOR_REF(Sinterrupt_handlersS, intnum); } else *handler = ENTER_FIXNUM(-1); /* Unknown signal handler. */ return SCHFALSE; } /* Return true if SIGNAL's default action is definitely to be ignored. */ /* This should be inlined by a good compiler. */ static int sig_def_is_ignored(int signal) { return /* Posix signals */ signal == SIGALRM || signal == SIGHUP || signal == SIGINT || signal == SIGQUIT || signal == SIGTERM || signal == SIGUSR1 || signal == SIGUSR2 /* Non-Posix signals, when present. */ #ifdef SIGINFO || signal == SIGINFO #endif #ifdef SIGPOLL || signal == SIGPOLL #endif #ifdef SIGPROF || signal == SIGPROF #endif #ifdef SIGVTALRM || signal == SIGVTALRM #endif #ifdef SIGXCPU || signal == SIGXCPU #endif #ifdef SIGXFSZ || signal == SIGXFSZ #endif #ifdef SIGIO || signal == SIGIO /* BSD => ignore; SVR4 => terminate */ #endif ; } /* 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; if( !sig_def_is_ignored(signal) ) { /* OK -- signal's default *isn't* "ignore," so we have to do it. */ 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. */ } } /* Install a new signal-handler vector. ** I use this because the default one is only 3 entries long, and I ** don't want to modify the S48 source. So I'll just install my own ** at run-time. ** It's not a hack, it's a kluge. */ void install_new_handler_vector(scheme_value handlers) { extern scheme_value Sinterrupt_handlersS; Sinterrupt_handlersS = handlers; }