;;; The signal-handling code in the last half of this file is obsolete. 8/23/96 ;;; Copyright (c) 1993 by Olin Shivers. See file COPYING. ;;; Job control code. (foreign-source "#include " "#include " "#include " "#include " "" "#define errno_or_false(x) (((x) == -1) ? ENTER_FIXNUM(errno) : SCHFALSE)" "" "") ;;; Fork off a process that runs in its own process group. The process is ;;; placed in its own process group before the process's actual work code is ;;; executed. We block ^Z's until we've got the child into its own proc group. (define (fork-job . maybe-thunk) (flush-all-ports) ((with-blocked-interrupts (bitwise-ior (blocked-interrupts) ; Block ^Z. (interrupt-set signal/tstp)) (cond ((%fork) => (lambda (child) (lambda () child))) ; Parent (else ; Child (set-process-group (pid)) ; Put ourselves in our own proc group. (if (not (interrupt-handler signal/tstp)) ; If ignoring TSTP, (set-interrupt-handler signal/tstp #t)) ; reset to default. (set-batch-mode?! #t) ; Batch mode. (lambda () (and (pair? maybe-thunk) ; Release ^Z & do it. (call-terminally (car maybe-thunk))))))))) ;;; Foreground a suspended or running background job. (define (foreground-job proc-group) (let ((iport (current-input-port))) (cond ((and (not (batch-mode?)) (is-control-tty? iport)) (dynamic-wind (lambda () (set-tty-process-group iport proc-group)) (lambda () (signal-process-group proc-group signal/cont) ; You go; (wait proc-group wait/stopped-children)) ; I'll wait. (lambda () (with-blocked-interrupts (bitwise-ior (blocked-interrupts) (interrupt-set signal/ttou)) (set-tty-process-group iport (process-group)))))) ;; Oops, not really doing job control -- just wait on the process. (else (signal-process proc-group signal/cont) ; You go; (wait proc-group wait/stopped-children))))) ; I'll wait. ;;; Background a suspended job. (define (background-job proc-group) (signal-process-group proc-group signal/cont)) (define-simple-syntax (run . epf) (foreground-job (& . epf))) (define-simple-syntax (& . epf) (fork-job (lambda () (exec-epf . epf)))) ;;; Need repl loop that manages some kind of a job table. ;;; Interactive startup must ignore ^Z. (define *control-tty-fdes* #f) (define (control-tty-fdes) (or *control-tty-fdes* (begin (set! *control-tty-fdes* (with-errno-handler ((errno data) (else #f)) (open-fdes "/dev/tty" open/read))) *control-tty-fdes*))) (define (is-control-tty? fd/port) (with-errno-handler ((errno data) (else #f)) ; False if you fail. (tty-process-group fd/port))) ; Try it. ;;; Blocking interrupts ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (interrupt-set . interrupts) (let lp ((ints interrupts) (ans 0)) (if (pair? ints) (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 (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 ;;; Get/Set interrupt handlers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; I'm punting the MASK value for now. ;;; I'm also punting returning real Scheme handlers for now. (define (set-interrupt-handler interrupt handler) (receive (handler flags) ; Should be (handler mask flags). (%set-interrupt-handler interrupt handler 0) handler)) (define (interrupt-handler interrupt) (receive (handler flags) (%interrupt-handler interrupt) handler)) (define (%interrupt-handler interrupt) (receive (err handler flags) (%%interrupt-handler interrupt) (if err (errno-error err interrupt-handler interrupt) (process-interrupt-handler-retvals handler flags)))) ;;; (%set-interrupt-handler interrupt handler [mask flags]) -> [handler mask flags] ;;; Except no MASK for now. (define (%set-interrupt-handler interrupt handler . args) (let-optionals args ((flags 0)) (receive (err handler flags) (%%set-interrupt-handler interrupt handler flags) (if err (errno-error err %set-interrupt-handler interrupt handler flags) (process-interrupt-handler-retvals handler flags))))) (define-foreign %%set-interrupt-handler (set_int_handler (fixnum signal) (desc handler) (fixnum flags)) desc ; #f or errno desc ; handler fixnum) ; flags (define-foreign %%interrupt-handler (get_int_handler (fixnum signal)) desc ; #f or errno desc ; handler fixnum) ; flags (define (process-interrupt-handler-retvals handler flags) (values (if (integer? handler) (error "We don't do Scheme handlers yet.") handler) flags))