From: Nikodemus Siivola Date: Sun, 19 Sep 2010 21:33:31 +0000 (+0000) Subject: 1.0.42.45: more descriptive errors for exceeding FD_SETSIZE X-Git-Url: http://repo.macrolet.net/gitweb/?a=commitdiff_plain;h=fcdd5b05583258e43bfe22bdfaea1fc34f85289d;p=sbcl.git 1.0.42.45: more descriptive errors for exceeding FD_SETSIZE Instead of a type-error whose meaning is pretty opaque to an average user, signal an error with a descriptive message. Add bug numbers to the previous select()/poll() changes in NEWS. --- diff --git a/NEWS b/NEWS index ce063ac..653806a 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,7 @@ ;;;; -*- coding: utf-8; fill-column: 78 -*- changes relative to sbcl-1.0.42 * incompatible change: FD-STREAMS no longer participate in the serve-event - event-loop by default. + event-loop by default. (lp#316072) ** In addition to streams created by explicit calls to MAKE-FD-STREAM this affects streams from CL:OPEN. ** Streams from SOCKET-MAKE-STREAM still participate in serve-event by @@ -17,10 +17,9 @@ changes relative to sbcl-1.0.42 * enhancement: symbols are printed using fully qualified names in several error and warning messages which are often associated with package conflicts or mixups (lp#622789, thanks to Attila Lendvai) - * optimization: where available, use poll(2) instead of select(2) to check - for blocking IO on a single FD. * bug fix: SB-BSD-SOCKETS:SOCKET-CONNECT was not thread safe. (lp#505497, thanks to Andrew Golding) + * bug fix: reading /proc files on Linux works. (lp#425199) * bug fix: DOTIMES accepted literal non-integer reals. (lp#619393, thanks to Roman Marynchak) * bug fix: WRITE-TO-STRING compiler macro binding special variable names, @@ -56,6 +55,8 @@ changes relative to sbcl-1.0.42 * bug fix: workaround for compiler hang in ORDER-UVL-SETS (lp#308914) * bug fix: evaluation in debugger REPL works using the global context when in frames that do not have sufficient debug information. + * bug fix: exceeding FD_SETSIZE limit now results in an sensible error + (lp#316068) changes in sbcl-1.0.42 relative to sbcl-1.0.41 * build changes diff --git a/src/code/serve-event.lisp b/src/code/serve-event.lisp index 508d465..e3563e6 100644 --- a/src/code/serve-event.lisp +++ b/src/code/serve-event.lisp @@ -72,6 +72,8 @@ (unless (member direction '(:input :output)) ;; FIXME: should be TYPE-ERROR? (error "Invalid direction ~S, must be either :INPUT or :OUTPUT" direction)) + (unless (<= 0 fd (1- sb!unix:fd-setsize)) + (error "Cannot add an FD handler for ~D: not under FD_SETSIZE limit." fd)) (let ((handler (make-handler direction fd function))) (with-descriptor-handlers (push handler *descriptor-handlers*)) diff --git a/src/code/unix.lisp b/src/code/unix.lisp index 2ea6ee9..37d715f 100644 --- a/src/code/unix.lisp +++ b/src/code/unix.lisp @@ -625,6 +625,14 @@ corresponds to NAME, or NIL if there is none." ;;;; sys/select.h +(defmacro with-fd-setsize ((n) &body body) + `(let ((,n (if (< 0 ,n fd-setsize) + ,n + (error "Cannot select(2) on ~D: above FD_SETSIZE limit." + (1- num-descriptors))))) + (declare (type (integer 0 #.fd-setsize) ,n)) + ,@body)) + ;;;; FIXME: Why have both UNIX-SELECT and UNIX-FAST-SELECT? ;;; Perform the UNIX select(2) system call. @@ -632,24 +640,25 @@ corresponds to NAME, or NIL if there is none." (defun unix-fast-select (num-descriptors read-fds write-fds exception-fds timeout-secs timeout-usecs) - (declare (type (integer 0 #.fd-setsize) num-descriptors) + (declare (type integer num-descriptors) (type (or (alien (* (struct fd-set))) null) read-fds write-fds exception-fds) (type (or null (unsigned-byte 31)) timeout-secs timeout-usecs)) - (flet ((select (tv-sap) - (int-syscall ("select" int (* (struct fd-set)) (* (struct fd-set)) - (* (struct fd-set)) (* (struct timeval))) - num-descriptors read-fds write-fds exception-fds - tv-sap))) - (cond ((or timeout-secs timeout-usecs) - (with-alien ((tv (struct timeval))) - (setf (slot tv 'tv-sec) (or timeout-secs 0)) - (setf (slot tv 'tv-usec) (or timeout-usecs 0)) - (select (alien-sap (addr tv))))) - (t - (unless *interrupts-enabled* - (note-dangerous-wait "select(2)")) - (select (int-sap 0)))))) + (with-fd-setsize (num-descriptors) + (flet ((select (tv-sap) + (int-syscall ("select" int (* (struct fd-set)) (* (struct fd-set)) + (* (struct fd-set)) (* (struct timeval))) + num-descriptors read-fds write-fds exception-fds + tv-sap))) + (cond ((or timeout-secs timeout-usecs) + (with-alien ((tv (struct timeval))) + (setf (slot tv 'tv-sec) (or timeout-secs 0)) + (setf (slot tv 'tv-usec) (or timeout-usecs 0)) + (select (alien-sap (addr tv))))) + (t + (unless *interrupts-enabled* + (note-dangerous-wait "select(2)")) + (select (int-sap 0))))))) ;;; UNIX-SELECT accepts sets of file descriptors and waits for an event ;;; to happen on one of them or to time out. @@ -680,35 +689,36 @@ corresponds to NAME, or NIL if there is none." ;;; they are ready for reading and writing. See the UNIX Programmer's ;;; Manual for more information. (defun unix-select (nfds rdfds wrfds xpfds to-secs &optional (to-usecs 0)) - (declare (type (integer 0 #.fd-setsize) nfds) + (declare (type integer nfds) (type unsigned-byte rdfds wrfds xpfds) (type (or (unsigned-byte 31) null) to-secs) (type (unsigned-byte 31) to-usecs) (optimize (speed 3) (safety 0) (inhibit-warnings 3))) - (with-alien ((tv (struct timeval)) - (rdf (struct fd-set)) - (wrf (struct fd-set)) - (xpf (struct fd-set))) - (cond (to-secs - (setf (slot tv 'tv-sec) to-secs - (slot tv 'tv-usec) to-usecs)) - ((not *interrupts-enabled*) - (note-dangerous-wait "select(2)"))) - (num-to-fd-set rdf rdfds) - (num-to-fd-set wrf wrfds) - (num-to-fd-set xpf xpfds) - (macrolet ((frob (lispvar alienvar) - `(if (zerop ,lispvar) - (int-sap 0) - (alien-sap (addr ,alienvar))))) - (syscall ("select" int (* (struct fd-set)) (* (struct fd-set)) - (* (struct fd-set)) (* (struct timeval))) - (values result - (fd-set-to-num nfds rdf) - (fd-set-to-num nfds wrf) - (fd-set-to-num nfds xpf)) - nfds (frob rdfds rdf) (frob wrfds wrf) (frob xpfds xpf) - (if to-secs (alien-sap (addr tv)) (int-sap 0)))))) + (with-fd-setsize (nfds) + (with-alien ((tv (struct timeval)) + (rdf (struct fd-set)) + (wrf (struct fd-set)) + (xpf (struct fd-set))) + (cond (to-secs + (setf (slot tv 'tv-sec) to-secs + (slot tv 'tv-usec) to-usecs)) + ((not *interrupts-enabled*) + (note-dangerous-wait "select(2)"))) + (num-to-fd-set rdf rdfds) + (num-to-fd-set wrf wrfds) + (num-to-fd-set xpf xpfds) + (macrolet ((frob (lispvar alienvar) + `(if (zerop ,lispvar) + (int-sap 0) + (alien-sap (addr ,alienvar))))) + (syscall ("select" int (* (struct fd-set)) (* (struct fd-set)) + (* (struct fd-set)) (* (struct timeval))) + (values result + (fd-set-to-num nfds rdf) + (fd-set-to-num nfds wrf) + (fd-set-to-num nfds xpf)) + nfds (frob rdfds rdf) (frob wrfds wrf) (frob xpfds xpf) + (if to-secs (alien-sap (addr tv)) (int-sap 0))))))) ;;; Lisp-side implmentations of FD_FOO macros. Abandon all hope who enters ;;; here... diff --git a/version.lisp-expr b/version.lisp-expr index 9714821..a43766b 100644 --- a/version.lisp-expr +++ b/version.lisp-expr @@ -17,4 +17,4 @@ ;;; checkins which aren't released. (And occasionally for internal ;;; versions, especially for internal versions off the main CVS ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".) -"1.0.42.44" +"1.0.42.45"