diff --git a/scsh/scsh_aux.h b/scsh/scsh_aux.h index 2567443..d5bdcf3 100644 --- a/scsh/scsh_aux.h +++ b/scsh/scsh_aux.h @@ -5,3 +5,31 @@ #define Malloc(type,n) ((type *) malloc(sizeof(type)*(n))) #define Free(p) (free((char *)(p))) #define Realloc(type,p,n) ((type *) realloc(p, (n)*sizeof(type))) + + +/* These are the interrupt numbers used by the S48/scsh VM. +** The first three are S48 interrupts. The rest were added for +** scsh to support Unix signals. Note that not all Unixes support +** all these signals. +*/ +#define scshint_alarm (0) /* S48 Unix SIGALRM signal */ +#define scshint_keyboard (1) /* S48 Unix SIGINT signal */ +#define scshint_memory_shortage (2) +#define scshint_chld (3) /* Interrupts from here down are */ +#define scshint_cont (4) /* Unix signals. The last ten are */ +#define scshint_hup (5) /* non-Posix, hence not necessarily */ +#define scshint_quit (6) /* found on all Unixes. */ +#define scshint_term (7) +#define scshint_tstp (8) +#define scshint_usr1 (9) +#define scshint_usr2 (10) +#define scshint_info (11) /* BSD */ +#define scshint_io (12) /* BSD + SVR4 */ +#define scshint_poll (13) /* SVR4 */ +#define scshint_prof (14) /* BSD + SVR4 */ +#define scshint_pwr (15) /* SVR4 */ +#define scshint_urg (16) /* BSD + SVR4 */ +#define scshint_vtalrm (17) /* BSD + SVR4 */ +#define scshint_winch (18) /* BSD + SVR4 */ +#define scshint_xcpu (19) /* BSD + SVR4 */ +#define scshint_xfsz (20) /* BSD + SVR4 */ diff --git a/scsh/sighandlers.scm b/scsh/sighandlers.scm index c30df4c..0877b20 100644 --- a/scsh/sighandlers.scm +++ b/scsh/sighandlers.scm @@ -5,6 +5,10 @@ ;;; *through* an intermediate interface, the S48 vm's idea of interrupts. ;;; So there is a difference between delivering a signal to the underlying ;;; Unix process and delivering it to the program that runs on the VM. +;;; +;;; One effect is that we have two separate codes for the same thing -- the +;;; Unix signal code, and the S48 interrupt value. E.g., SIGNAL/TSTP and +;;; INTERRUPT/TSTP. ;;; These system calls can return EINTR or restart. In order for the S48 vm's ;;; interrupt system to detect a signal and invoke the handler, they *must* @@ -20,6 +24,11 @@ ;;; HP-UX, but I don't use: poll lockf msem_lock msgsnd msgrcv semop ;;; ;;; * Only during a F_SETLKW +;;; +;;; From rts/interrupt.scm (package interrupts, interface interrupts-interface) +;;; WITH-INTERRUPTS INTERRUPT-HANDLERS SET-ENABLED-INTERRUPTS! +;;; ENABLED-INTERRUPTS +;;; Must define WITH-INTERRUPTS* and WITH-INTERRUPTS. (foreign-source "extern int errno;" @@ -28,10 +37,16 @@ "#include \"sighandlers1.h\"" "" "") -;;; Blocking interrupts -;;; I think all of this code (and associated C code) has been obsoleted by -;;; the new system that uses S48's sigblocking machinery. -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Map a Unix async signal to its S48 interrupt value. +;;; -1 => Not defined. +(define-foreign %signal->interrupt (sig2interrupt (integer sig)) + integer) + +(define (signal->interrupt sig) + (let ((int (%signal->interrupt sig))) + (if (>= int 0) int + (error "Unix signal has no Scheme 48 interrupt." sig)))) + (define (interrupt-set . interrupts) (let lp ((ints interrupts) (ans 0)) @@ -39,33 +54,10 @@ (lp (cdr ints) (bitwise-ior ans (arithmetic-shift 1 (- (car ints) 1)))) ans))) -(define-simple-syntax (with-blocked-interrupts mask body ...) - (with-blocked-interrupts* mask (lambda () body ...))) +(define-simple-syntax (with-enabled-interrupts mask body ...) + (with-interrupts mask (lambda () body ...))) -(define (with-blocked-interrupts* mask thunk) - (let ((old-mask #f)) - (dynamic-wind - (lambda () (set! old-mask (set-blocked-interrupts! mask))) - thunk - (lambda () (set-blocked-interrupts! old-mask))))) - -(define (set-blocked-interrupts! mask) - (receive (hi-out lo-out) - (%set-blocked-interrupts! (hi8 mask) (lo24 mask)) - (compose-8/24 hi-out lo-out))) - - -(define (blocked-interrupts) - (call-with-values %blocked-interrupts compose-8/24)) - -(define-foreign %set-blocked-interrupts! (set_procmask (fixnum hi) - (fixnum lo)) - fixnum ; hi - fixnum) ; lo - -(define-foreign %blocked-interrupts (get_procmask) - fixnum ; hi - fixnum) ; lo +(define with-enabled-interrupts* with-interrupts) ;;; Get/Set signal handlers @@ -81,62 +73,90 @@ ;;; to our waiting parent proc correctly reflects how we died, and also ;;; makes the core dump happen if it should. Details, details. -(define (default-handler sig) - (lambda (enabled-interrupts) (%do-default-sigaction sig))) - (define-foreign %do-default-sigaction (do_default_sigaction (fixnum signal)) ignore) +;;; This gives the default handler for each signal. +(define default-handler-vec + (initialize-vector 32 (lambda (sig) + ;; This is the guy to call when you want signal + ;; SIG handled in the default manner. + (if (memv sig signals-ignored-by-default) + (lambda (enabled-interrupts) #f) + (lambda (enabled-interrupts) + (%do-default-sigaction sig)))))) -;;; HANDLER is #f (ignore), #t (default), or an integer procedure. -;;; The interrupt is delivered to a procedure by (1) setting the -;;; ENABLED-INTERRUPTS register to 0 (i.e., blocking all interrupts), -;;; and (2) applying the procedure to the previous value of the -;;; ENABLED-INTERRUPTS register. If the procedure returns normally -;;; (i.e., it doesn't throw to a continuation), the ENABLED-INTERRUPTS -;;; register will be restored to its previous value. -;;; Should have extra args, MASK & FLAGS. -(define (set-signal-handler sig handler) - (let ((handler (if (eq? handler #t) ; Hack the default handler. - (default-handler sig) - handler))) - (receive (handler flags) ; Should be (handler mask flags). - (%set-signal-handler! sig handler 0) - handler))) +;;; HANDLER is #f (ignore), #t (default), or a procedure taking an integer +;;; argument. The interrupt is delivered to a procedure by (1) setting the +;;; ENABLED-INTERRUPTS register to 0 (i.e., blocking all interrupts), and (2) +;;; applying the procedure to the previous value of the ENABLED-INTERRUPTS +;;; register. If the procedure returns normally (i.e., it doesn't throw to a +;;; continuation), the ENABLED-INTERRUPTS register will be restored to its +;;; previous value. + +(define (set-signal-handler! sig handler) + (let ((nhandler (if (eq? handler #t) ; Get SIG's default handler. + (vector-ref default-handler-vec sig) + handler)) + (int (signal->interrupt sig))) + (with-enabled-interrupts 0 + (let ((ohandler (vector-ref interrupt-handlers int))) + (vector-set! interrupt-handlers int nhandler) + ohandler)))) (define (signal-handler sig) - (receive (handler flags) (%signal-handler sig) - handler)) + (vector-ref interrupt-handlers (signal->interrupt sig))) -(define (%signal-handler sig) - (receive (err handler flags) (%%signal-handler sig) - (if err (errno-error err %signal-handler sig) - (values handler flags)))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Set the Unix signal handler. One doesn't usually use this; one usually +;;; uses the S48 VM's interrupt system. +;;; HANDLER-CODE: 0 => ignore, 1 => default, 2 => S48 VM +;;; Returns equivalent code, additionally 3 => other handler. +;;; Raises an error exception if there's a problem. -;;; (%set-signal-handler! sig handler [mask flags]) -> [handler mask flags] -;;; Except no MASK for now. +(define (%set-unix-signal-handler! sig handler-code) + (check-arg (lambda (x) (and (integer? sig) (< 0 sig 32))) + sig + %set-unix-signal-handler!) + (check-arg (lambda (x) (and (integer? handler-code) (<= 0 handler-code 2))) + handler-code + %set-unix-signal-handler!) + (let retry () + (receive (err old-hc) (%%set-unix-signal-handler! sig handler-code) + (cond ((not err) old-hc) + ((= err errno/intr) (retry)) + (else (errno-error err %set-unix-signal-handler! sig handler-code)))))) -(define (%set-signal-handler! sig handler . args) - (let-optionals args ((flags 0)) - (receive (err handler flags) - (%%set-signal-handler! sig handler flags) - (if err - (errno-error err %set-signal-handler! sig handler flags) - (values handler flags))))) - -(define-foreign %%set-signal-handler! (set_sig_handler (fixnum signal) - (desc handler) - (fixnum flags)) +(define-foreign %%set-unix-signal-handler! + (scsh_set_sig (fixnum sig) (fixnum hc) (fixnum flags)) desc ; #f or errno - desc ; handler - fixnum) ; flags + integer ; previous handler-code + integer) ; previous handler flags -(define-foreign %%signal-handler (get_sig_handler (fixnum signal)) +(define (%unix-signal-handler sig) + (check-arg (lambda (x) (and (integer? sig) (< 0 sig 32))) + sig + %unix-signal-handler) + (let retry () + (receive (err hc flags) (%%unix-signal-handler sig) + (cond ((not err) hc) + ((= err errno/intr) (retry)) + (else (errno-error err %unix-signal-handler sig)))))) + +(define-foreign %%unix-signal-handler (scsh_get_sig (fixnum sig)) desc ; #f or errno - desc ; handler - fixnum) ; flags + integer ; previous handler-code + integer) ; previous handler flags -(define-foreign %%install-new-handler-vec - (install_new_handler_vector (vector-desc vec)) - ignore) +(define-foreign %install-unix-scsh-handlers (install_scsh_handlers) ignore) + +(define-foreign %%get-int-handlers (get_int_handlers) desc) + +(define (%install-scsh-handlers) + (do ((sig 32 (- sig 1))) + ((< sig 0)) + (let ((i (%signal->interrupt sig))) + (if (not (or (= i -1) (= sig signal/int) (= sig signal/alrm))) + (vector-set! interrupt-handlers i + (vector-ref default-handler-vec sig)))))) diff --git a/scsh/sighandlers1.c b/scsh/sighandlers1.c index fdc675d..6f1b94d 100644 --- a/scsh/sighandlers1.c +++ b/scsh/sighandlers1.c @@ -6,66 +6,25 @@ #include #include #include +#include #include "cstuff.h" /* Make sure our exports match up w/the implementation: */ #include "sighandlers1.h" +#include "machine/signals1.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. -*/ +/* Translate Unix signal numbers to S48 interrupt numbers. */ -static int sig2interrupt(int signal) +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; + return ( signal < 0 || signal > max_sig ) ? -1 : sig2int[signal]; } -} + /* Hack the blocked-signal mask. ******************************************************************************* @@ -104,138 +63,63 @@ int get_procmask(int *old_lo_p) static void scm_handle_sig(int sig) { - Spending_interruptsS |= (1< 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; - int intnum = sig2interrupt(sig); - scheme_value old_scsh_handler; - - /* intnum in range? */ - if( intnum >= 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; - } + 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); + } - /* 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; + return scsh_ret_sig(sigaction(sig, &new, &old), + &old, old_hc, oflags); } -scheme_value get_sig_handler(int signal, scheme_value *handler, int *flags) +scheme_value scsh_get_sig(int signal, int *old_hc, int *oflags) { 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 scsh_ret_sig(sigaction(signal, NULL, &old), + &old, old_hc, oflags); } -/* 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 @@ -254,39 +138,56 @@ void do_default_sigaction(int signal) sigset_t ss, old_ss; struct sigaction default_action, old_action; - if( !sig_def_is_ignored(signal) ) { + fprintf(stderr, "Doing default for signal %d\n", signal); - /* OK -- signal's default *isn't* "ignore," so we have to do it. */ - sigfillset(&ss); /* Block everyone. */ - sigprocmask(SIG_SETMASK, &ss, &old_ss); + 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); + 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. */ + 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. */ - } + /* 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. -*/ +/* Set up the Unix signal system the way we want it for scsh. */ -void install_new_handler_vector(scheme_value handlers) +void install_scsh_handlers(void) { - extern scheme_value Sinterrupt_handlersS; - Sinterrupt_handlersS = handlers; + struct sigaction new; + int i; + + sigemptyset(&new.sa_mask); /* WTF */ + new.sa_handler = scm_handle_sig; + + 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; } diff --git a/scsh/sighandlers1.h b/scsh/sighandlers1.h index c069c62..c3a5720 100644 --- a/scsh/sighandlers1.h +++ b/scsh/sighandlers1.h @@ -1,12 +1,16 @@ /* Exports from sighandlers1.c */ +int sig2interrupt(int signal); + int set_procmask(int hi, int lo, int *old_lo_p); int get_procmask(int *old_lo_p); -scheme_value set_int_handler(int sig, scheme_value handler, int flags, - scheme_value *ohandler, int *oflags); -scheme_value get_int_handler(int signal, scheme_value *handler, int *flags); +scheme_value scsh_set_sig(int sig, int handler_code, int flags, + int *ohc, int *oflags); +scheme_value scsh_get_sig(int signal, int *handler_code, int *flags); void do_default_sigaction(int signal); -void install_new_handler_vector(scheme_value handlers); +void install_scsh_handlers(void); + +scheme_value get_int_handlers(void);