1999-09-14 09:32:05 -04:00
|
|
|
;;; select(2) syscall for scsh. -*- Scheme -*-
|
|
|
|
;;; Copyright (c) 1995 by Olin Shivers.
|
|
|
|
|
1999-09-23 19:02:54 -04:00
|
|
|
(foreign-init-name "select")
|
|
|
|
|
|
|
|
|
1999-09-14 09:32:05 -04:00
|
|
|
(foreign-source
|
|
|
|
"/* Make sure foreign-function stubs interface to the C funs correctly: */"
|
|
|
|
"#include \"select1.h\""
|
|
|
|
"" "")
|
|
|
|
|
|
|
|
;;; TIMEOUT is 0 for immediate, >0 for timeout, #f for infinite;
|
|
|
|
;;; default is #f.
|
|
|
|
;;; The sets are vectors of file descriptors & fd ports.
|
|
|
|
;;; You get three new vectors back.
|
|
|
|
|
|
|
|
; The following routines copy ports to fd's, and copy fd's back to fd's and
|
|
|
|
; ports, so that select can take numbers and ports, simultaneously.
|
|
|
|
|
|
|
|
; This is a C procedure in scheme. So sue me. At least it's tail-recursive
|
|
|
|
(define (fd-filter filter-me)
|
|
|
|
(let* ((len (vector-length filter-me))
|
|
|
|
(vector-to-return (make-vector len)))
|
|
|
|
(let loop ((count (- len 1)))
|
|
|
|
(if (>= count 0)
|
|
|
|
(let ((ref (vector-ref filter-me count)))
|
|
|
|
(if (integer? ref)
|
|
|
|
(vector-set! vector-to-return count ref)
|
|
|
|
(vector-set! vector-to-return count (port->fdes ref)))
|
|
|
|
(loop (- count 1)))))
|
|
|
|
vector-to-return))
|
|
|
|
|
|
|
|
; ! means side-effect, the next one is more functional.
|
|
|
|
(define (fd-copyback! orig form)
|
|
|
|
(let loop ((count (- (vector-length orig) 1)))
|
|
|
|
(if (>= count 0)
|
|
|
|
(begin
|
|
|
|
(if (not (vector-ref form count))
|
|
|
|
(vector-set! orig count #f)
|
|
|
|
(vector-set! form count (vector-ref orig count)))
|
|
|
|
(loop (- count 1)))))
|
|
|
|
orig)
|
|
|
|
|
|
|
|
(define (fd-copyback orig form)
|
|
|
|
(let* ((len (vector-length orig))
|
|
|
|
(vector-to-return (make-vector len #f)))
|
|
|
|
(let loop ((count (- len 1)))
|
|
|
|
(if (>= count 0)
|
|
|
|
(begin
|
|
|
|
(if (vector-ref form count)
|
|
|
|
(vector-set! vector-to-return count (vector-ref orig count)))
|
|
|
|
(loop (- count 1)))))
|
|
|
|
vector-to-return))
|
|
|
|
|
|
|
|
(define (select read-vec write-vec exception-vec . maybe-timeout)
|
|
|
|
(let ((rv (copy-vector read-vec))
|
|
|
|
(wv (copy-vector write-vec))
|
|
|
|
(ev (copy-vector exception-vec)))
|
|
|
|
(receive (nr nw ne) (apply select! rv wv ev maybe-timeout)
|
|
|
|
(values (vector-take-form read-vec rv nr)
|
|
|
|
(vector-take-form write-vec wv nw)
|
|
|
|
(vector-take-form exception-vec ev ne)))))
|
|
|
|
|
|
|
|
|
|
|
|
(define (select!/copyback read-vec write-vec exception-vec . maybe-timeout)
|
|
|
|
(receive (errno nr nw ne)
|
|
|
|
(apply select!/copyback/errno read-vec write-vec exception-vec
|
|
|
|
maybe-timeout)
|
|
|
|
(if errno
|
|
|
|
(apply errno-error errno select!/copyback
|
|
|
|
read-vec write-vec exception-vec maybe-timeout)
|
|
|
|
(values nr nw ne))))
|
|
|
|
|
|
|
|
|
|
|
|
(define (select!/copyback/errno read-vec write-vec
|
|
|
|
exception-vec . maybe-timeout)
|
|
|
|
(let ((timeout (and (pair? maybe-timeout)
|
|
|
|
(if (pair? (cdr maybe-timeout))
|
|
|
|
(apply error "Too many arguments"
|
|
|
|
select!/copyback/errno
|
|
|
|
read-vec write-vec exception-vec
|
|
|
|
maybe-timeout)
|
|
|
|
(real->exact-integer (check-arg real?
|
|
|
|
(car maybe-timeout)
|
|
|
|
select!/copyback/errno)))))
|
|
|
|
|
|
|
|
(vec-ok? (lambda (v)
|
|
|
|
(vector-every? (lambda (elt)
|
|
|
|
(or (and (integer? elt) (>= elt 0))
|
|
|
|
(fdport? elt)))
|
|
|
|
v))))
|
|
|
|
;; Type-check input vectors.
|
|
|
|
(check-arg vec-ok? read-vec select!/copyback/errno)
|
|
|
|
(check-arg vec-ok? write-vec select!/copyback/errno)
|
|
|
|
(check-arg vec-ok? exception-vec select!/copyback/errno)
|
|
|
|
(check-arg (lambda (x) (or (not x) (integer? x))) timeout
|
|
|
|
select!/copyback/errno)
|
|
|
|
|
|
|
|
(let ((prop-read-vec (fd-filter read-vec))
|
|
|
|
(prop-write-vec (fd-filter write-vec))
|
|
|
|
(prop-exception-vec (fd-filter exception-vec)))
|
|
|
|
(let lp ()
|
|
|
|
(receive (errno nr nw ne)
|
|
|
|
(%select/copyback/errno prop-read-vec prop-write-vec prop-exception-vec timeout)
|
|
|
|
(if (and errno (= errno errno/intr)) ; Retry on interrupts.
|
|
|
|
(lp)
|
|
|
|
(values errno
|
|
|
|
(fd-copyback read-vec nr)
|
|
|
|
(fd-copyback write-vec nw)
|
|
|
|
(fd-copyback exception-vec ne))))))))
|
|
|
|
|
|
|
|
|
|
|
|
(define-foreign %select/copyback/errno
|
|
|
|
(select_copyback (vector-desc rvec)
|
|
|
|
(vector-desc wvec)
|
|
|
|
(vector-desc evec)
|
|
|
|
(desc nsecs)) ; Integer or #f for infinity.
|
|
|
|
desc ; errno or #f
|
|
|
|
fixnum ; nread - number of hits in RVEC
|
|
|
|
fixnum ; nwrite - number of hits in WVEC
|
|
|
|
fixnum) ; nexcept - number of hits in EVEC
|
|
|
|
|
|
|
|
|
|
|
|
(define (vector-take-form vec form nelts)
|
|
|
|
(let ((short (make-vector nelts)))
|
|
|
|
(do ((i (- (vector-length vec) 1) (- i 1)))
|
|
|
|
((< i 0))
|
|
|
|
(if (vector-ref form i)
|
|
|
|
(begin
|
|
|
|
(set! nelts (- nelts 1))
|
|
|
|
(vector-set! short nelts (vector-ref vec i)))))
|
|
|
|
short))
|
|
|
|
|
|
|
|
|
|
|
|
;;; SELECT!
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;; The side-effecting variant. To be documented.
|
|
|
|
|
|
|
|
(define (select! read-vec write-vec exception-vec . maybe-timeout)
|
|
|
|
(receive (errno nr nw ne)
|
|
|
|
(apply select!/errno read-vec write-vec exception-vec maybe-timeout)
|
|
|
|
(if errno
|
|
|
|
(apply errno-error errno select! read-vec write-vec exception-vec
|
|
|
|
maybe-timeout)
|
|
|
|
(values nr nw ne))))
|
|
|
|
|
|
|
|
(define (select!/errno read-vec write-vec exception-vec . maybe-timeout)
|
|
|
|
(let ((timeout (and (pair? maybe-timeout)
|
|
|
|
(if (pair? (cdr maybe-timeout))
|
|
|
|
(apply error "Too many arguments"
|
|
|
|
select!/copyback/errno
|
|
|
|
read-vec write-vec exception-vec
|
|
|
|
maybe-timeout)
|
|
|
|
(real->exact-integer (check-arg real?
|
|
|
|
(car maybe-timeout)
|
|
|
|
select!/copyback/errno)))))
|
|
|
|
|
|
|
|
(vec-ok? (lambda (v)
|
|
|
|
(vector-every? (lambda (elt)
|
|
|
|
(or (and (integer? elt) (>= elt 0))
|
|
|
|
(not elt)
|
|
|
|
(fdport? elt)))
|
|
|
|
v))))
|
|
|
|
;; Type-check input vectors.
|
|
|
|
(check-arg vec-ok? read-vec select!/errno)
|
|
|
|
(check-arg vec-ok? write-vec select!/errno)
|
|
|
|
(check-arg vec-ok? exception-vec select!/errno)
|
|
|
|
(check-arg (lambda (x) (or (not x) (integer? x))) timeout select!/errno)
|
|
|
|
|
|
|
|
(let ((prop-read-vec (fd-filter read-vec))
|
|
|
|
(prop-write-vec (fd-filter write-vec))
|
|
|
|
(prop-exception-vec (fd-filter exception-vec)))
|
|
|
|
(let lp ()
|
|
|
|
(receive (errno nr nw ne)
|
|
|
|
(%select!/errno prop-read-vec prop-write-vec prop-exception-vec timeout)
|
|
|
|
(if (and errno (= errno errno/intr)) ; Retry on interrupts.
|
|
|
|
(lp)
|
|
|
|
(begin
|
|
|
|
(fd-copyback! read-vec prop-read-vec)
|
|
|
|
(fd-copyback! write-vec prop-write-vec)
|
|
|
|
(fd-copyback! exception-vec prop-exception-vec)
|
|
|
|
(values errno nr nw ne))))))))
|
|
|
|
|
|
|
|
|
|
|
|
(define-foreign %select!/errno
|
|
|
|
(select_filter (vector-desc rvec)
|
|
|
|
(vector-desc wvec)
|
|
|
|
(vector-desc evec)
|
|
|
|
(desc nsecs)) ; Integer or #f for infinity.
|
|
|
|
desc ; errno or #f
|
|
|
|
fixnum ; nread - number of hits in RVEC
|
|
|
|
fixnum ; nwrite - number of hits in WVEC
|
|
|
|
fixnum) ; nexcept - number of hits in EVEC
|