[usocket-cvs] r343 - in usocket/branches/new-wfi: . backend

ehuelsmann at common-lisp.net ehuelsmann at common-lisp.net
Sun Jun 15 21:17:24 UTC 2008


Author: ehuelsmann
Date: Sun Jun 15 17:17:23 2008
New Revision: 343

Added:
   usocket/branches/new-wfi/BRANCH-README   (contents, props changed)
Modified:
   usocket/branches/new-wfi/backend/allegro.lisp
   usocket/branches/new-wfi/backend/clisp.lisp
   usocket/branches/new-wfi/backend/cmucl.lisp
   usocket/branches/new-wfi/backend/lispworks.lisp
   usocket/branches/new-wfi/backend/openmcl.lisp
   usocket/branches/new-wfi/usocket.lisp
Log:
Populate new-WAIT-FOR-INPUT branch with intended API.

Added: usocket/branches/new-wfi/BRANCH-README
==============================================================================
--- (empty file)
+++ usocket/branches/new-wfi/BRANCH-README	Sun Jun 15 17:17:23 2008
@@ -0,0 +1,8 @@
+
+
+At least these backends are broken, for now:
+
+ - ABCL
+ - LispWorks (Win32)
+ - SBCL/ ECL
+ - Scieneer

Modified: usocket/branches/new-wfi/backend/allegro.lisp
==============================================================================
--- usocket/branches/new-wfi/backend/allegro.lisp	(original)
+++ usocket/branches/new-wfi/backend/allegro.lisp	Sun Jun 15 17:17:23 2008
@@ -127,18 +127,29 @@
     (list (hbo-to-vector-quad (socket:lookup-hostname
                                (host-to-hostname name))))))
 
-(defun wait-for-input-internal (sockets &key timeout)
+(defun %setup-wait-list (wait-list)
+  (declare (ignore wait-list)))
+
+(defun %add-waiter (wait-list waiter)
+  (push (socket waiter) (%wait wait-list)))
+
+(defun %remove-waiter (wait-list waiter)
+  (setf (%wait wait-list)
+        (remove (socket waiter) (%wait wait-list))))
+
+(defun wait-for-input-internal (wait-list &key timeout)
   (with-mapped-conditions ()
     (let ((active-internal-sockets
            (if timeout
-               (mp:wait-for-input-available (mapcar #'socket sockets)
+               (mp:wait-for-input-available (%wait wait-list)
                                             :timeout timeout)
-             (mp:wait-for-input-available (mapcar #'socket sockets)))))
+             (mp:wait-for-input-available (%wait wait-list)))))
       ;; this is quadratic, but hey, the active-internal-sockets
       ;; list is very short and it's only quadratic in the length of that one.
       ;; When I have more time I could recode it to something of linear
       ;; complexity.
-      ;; [Same code is also used in lispworks.lisp, openmcl.lisp]
-      (remove-if #'(lambda (x)
-                     (not (member (socket x) active-internal-sockets)))
-                 sockets))))
+      ;; [Same code is also used in openmcl.lisp]
+      (dolist (x active-internal-sockets)
+        (setf (state (gethash x (wait-map wait-list)))
+              :READ))
+      wait-list)))

Modified: usocket/branches/new-wfi/backend/clisp.lisp
==============================================================================
--- usocket/branches/new-wfi/backend/clisp.lisp	(original)
+++ usocket/branches/new-wfi/backend/clisp.lisp	Sun Jun 15 17:17:23 2008
@@ -127,23 +127,33 @@
   (nth-value 1 (get-peer-name usocket)))
 
 
-(defmethod wait-for-input-internal (sockets &key timeout)
+(defun %setup-wait-list (wait-list)
+  (declare (ignore wait-list)))
+
+(defun %add-waiter (wait-list waiter)
+  (push (cons (socket waiter) NIL) (%wait wait-list)))
+
+(defun %remove-waiter (wait-list waiter)
+  (setf (%wait wait-list)
+        (remove (socket waiter) (%wait wait-list) :key #'car)))
+
+(defmethod wait-for-input-internal (wait-list &key timeout)
   (with-mapped-conditions ()
     (multiple-value-bind
         (secs musecs)
         (split-timeout (or timeout 1))
-      (let* ((request-list (mapcar #'(lambda (x)
-                                       (if (stream-server-usocket-p x)
-                                           (socket x)
-                                         (list (socket x) :input)))
-                                   sockets))
-             (status-list (if timeout
+      (dolist (x (%wait wait-list))
+        (setf (cdr x) :INPUT))
+      (let* ((status-list (if timeout
                               (socket:socket-status request-list secs musecs)
-                            (socket:socket-status request-list))))
-        (remove nil
-                (mapcar #'(lambda (x y)
-                            (when y x))
-                        sockets status-list))))))
+                            (socket:socket-status request-list)))
+             (sockets (wait-list wait-list)))
+        (do* ((x (pop sockets) (pop sockets))
+              (y (pop status-list) (pop status-list)))
+             ((or (null sockets) (null status-list)))
+          (when y
+            (setf (state x) :READ)))
+        wait-list))))
 
 
 ;;

Modified: usocket/branches/new-wfi/backend/cmucl.lisp
==============================================================================
--- usocket/branches/new-wfi/backend/cmucl.lisp	(original)
+++ usocket/branches/new-wfi/backend/cmucl.lisp	Sun Jun 15 17:17:23 2008
@@ -162,26 +162,35 @@
 (defun get-host-name ()
   (unix:unix-gethostname))
 
-(defun wait-for-input-internal (sockets &key timeout)
+(defun %setup-wait-list (wait-list)
+  (declare (ignore wait-list)))
+
+(defun %add-waiter (wait-list waiter)
+  (declare (ignore wait-list waiter)))
+
+(defun %remove-waiter (wait-list waiter)
+  (declare (ignore wait-list waiter)))
+
+(defun wait-for-input-internal (wait-list &key timeout)
   (with-mapped-conditions ()
     (alien:with-alien ((rfds (alien:struct unix:fd-set)))
        (unix:fd-zero rfds)
-       (dolist (socket sockets)
+       (dolist (socket (wait-list wait-list))
          (unix:fd-set (socket socket) rfds))
        (multiple-value-bind
            (secs musecs)
            (split-timeout (or timeout 1))
          (multiple-value-bind
              (count err)
-             (unix:unix-fast-select (1+ (reduce #'max sockets
+             (unix:unix-fast-select (1+ (reduce #'max (wait-list wait-list)
                                                 :key #'socket))
                                     (alien:addr rfds) nil nil
                                     (when timeout secs) musecs)
            (if (<= 0 count)
                ;; process the result...
-               (remove-if #'(lambda (x)
-                              (not (unix:fd-isset (socket x) rfds)))
-                          sockets)
+               (dolist (x (wait-list wait-list))
+                 (when (unix:fd-isset (socket x) rfds)
+                   (setf (state x) :READ)))
              (progn
                ;;###FIXME generate an error, except for EINTR
                )))))))

Modified: usocket/branches/new-wfi/backend/lispworks.lisp
==============================================================================
--- usocket/branches/new-wfi/backend/lispworks.lisp	(original)
+++ usocket/branches/new-wfi/backend/lispworks.lisp	Sun Jun 15 17:17:23 2008
@@ -169,21 +169,36 @@
 ;;;
 
 #-win32
-(defun wait-for-input-internal (sockets &key timeout)
-  (with-mapped-conditions ()
-    ;; unfortunately, it's impossible to share code between
-    ;; non-win32 and win32 platforms...
-    ;; Can we have a sane -pref. complete [UDP!?]- API next time, please?
-    (dolist (x sockets)
-       (mp:notice-fd (os-socket-handle x)))
-    (mp:process-wait-with-timeout "Waiting for a socket to become active"
-                                  (truncate timeout)
-                                  #'(lambda (socks)
-                                      (some #'usocket-listen socks))
-                                  sockets)
-    (dolist (x sockets)
-       (mp:unnotice-fd (os-socket-handle x)))
-    (remove nil (mapcar #'usocket-listen sockets))))
+(progn
+
+  (defun %setup-wait-list (wait-list)
+    (declare (ignore wait-list)))
+
+  (defun %add-waiter (wait-list waiter)
+    (declare (ignore wait-list waiter)))
+
+  (defun %remove-waiter (wait-list waiter)
+    (declare (ignore wait-list waiter)))
+
+  (defun wait-for-input-internal (wait-list &key timeout)
+    (with-mapped-conditions ()
+      ;; unfortunately, it's impossible to share code between
+      ;; non-win32 and win32 platforms...
+      ;; Can we have a sane -pref. complete [UDP!?]- API next time, please?
+      (dolist (x (wait-list wait-list))
+        (mp:notice-fd (os-socket-handle x)))
+      (mp:process-wait-with-timeout "Waiting for a socket to become active"
+                                    (truncate timeout)
+                                    #'(lambda (socks)
+                                        (let (rv)
+                                          (dolist (x socks rv)
+                                            (when (usocket-listen x)
+                                              (setf (state x) :READ
+                                                    rv t)))))
+                                    (wait-list wait-list))
+      (dolist (x (wait-list wait-list))
+        (mp:unnotice-fd (os-socket-handle x)))
+      wait-list)))
 
 
 ;;;

Modified: usocket/branches/new-wfi/backend/openmcl.lisp
==============================================================================
--- usocket/branches/new-wfi/backend/openmcl.lisp	(original)
+++ usocket/branches/new-wfi/backend/openmcl.lisp	Sun Jun 15 17:17:23 2008
@@ -32,21 +32,23 @@
 (defun input-available-p (sockets &optional ticks-to-wait)
   (ccl::rletZ ((tv :timeval))
     (ccl::ticks-to-timeval ticks-to-wait tv)
+    ;;### The trickery below can be moved to the wait-list now...
     (ccl::%stack-block ((infds ccl::*fd-set-size*))
       (ccl::fd-zero infds)
       (let ((max-fd -1))
         (dolist (sock sockets)
-          (let ((fd (openmcl-socket:socket-os-fd sock)))
+          (let ((fd (openmcl-socket:socket-os-fd (socket sock))))
             (setf max-fd (max max-fd fd))
             (ccl::fd-set fd infds)))
         (let* ((res (#_select (1+ max-fd)
                               infds (ccl::%null-ptr) (ccl::%null-ptr)
                               (if ticks-to-wait tv (ccl::%null-ptr)))))
           (when (> res 0)
-            (remove-if #'(lambda (x)
-                           (not (ccl::fd-is-set (openmcl-socket:socket-os-fd x)
-                                                infds)))
-                       sockets)))))))
+            (dolist (x sockets)
+              (when (ccl::fd-is-set (openmcl-socket:socket-os-fd (socket x))
+                                    infds)
+                (setf (state x) :READ))))
+          sockets)))))
 
 (defun raise-error-from-id (condition-id socket real-condition)
   (let ((usock-err (cdr (assoc condition-id +openmcl-error-map+))))
@@ -136,19 +138,23 @@
      (list (hbo-to-vector-quad (openmcl-socket:lookup-hostname
                                 (host-to-hostname name))))))
 
-(defun wait-for-input-internal (sockets &key timeout)
+
+(defun %setup-wait-list (wait-list)
+  (declare (ignore wait-list)))
+
+(defun %add-waiter (wait-list waiter)
+  (declare (ignore wait-list waiter)))
+
+(defun %remove-waiter (wait-list waiter)
+  (declare (ignore wait-list waiter)))
+
+(defun wait-for-input-internal (wait-list &key timeout)
   (with-mapped-conditions ()
-    (let* ((ticks-timeout (truncate (* (or timeout 1) ccl::*ticks-per-second*)))
+    (let* ((ticks-timeout (truncate (* (or timeout 1)
+                                       ccl::*ticks-per-second*)))
            (active-internal-sockets
-            (input-available-p (mapcar #'socket sockets)
+            (input-available-p wait-list
                                (when timeout ticks-timeout))))
-      ;; this is quadratic, but hey, the active-internal-sockets
-      ;; list is very short and it's only quadratic in the length of that one.
-      ;; When I have more time I could recode it to something of linear
-      ;; complexity.
-      ;; [Same code is also used in lispworks.lisp, allegro.lisp]
-      (remove-if #'(lambda (x)
-                     (not (member (socket x) active-internal-sockets)))
-                 sockets))))
+      wait-list)))
 
 

Modified: usocket/branches/new-wfi/usocket.lisp
==============================================================================
--- usocket/branches/new-wfi/usocket.lisp	(original)
+++ usocket/branches/new-wfi/usocket.lisp	Sun Jun 15 17:17:23 2008
@@ -15,7 +15,20 @@
   ((socket
     :initarg :socket
     :accessor socket
-    :documentation "Implementation specific socket object instance."))
+    :documentation "Implementation specific socket object instance.'")
+   (state
+    :initform nil
+    :accessor state
+    :documentation "Per-socket return value for the `wait-for-input' function.
+
+The value stored in this slot can be any of
+ NIL          - not ready
+ :READ        - ready to read
+ :READ-WRITE  - ready to read and write
+ :WRITE       - ready to write
+
+The last two remain unused in the current version.
+"))
   (:documentation
 "The main socket class.
 
@@ -33,7 +46,7 @@
 ))
    (:documentation
 "Stream socket class.
-
+'
 Contrary to other sockets, these sockets may be closed either
 with the `socket-close' method or by closing the associated stream
 (which can be retrieved with the `socket-stream' accessor)."))
@@ -201,10 +214,46 @@
       , at body))
 
 
-(defgeneric wait-for-input (socket-or-sockets
-                            &key timeout)
-  (:documentation
-"Waits for one or more streams to become ready for reading from
+(defstruct (wait-list (:constructor %make-wait-list))
+  (%wait     ;; implementation specific
+   wait-list ;; the list of all usockets
+   wait-map  ;; maps implementation sockets to usockets
+   ))
+
+;; Implementation specific:
+;;
+;;  %setup-wait-list
+;;  add-waiter
+;;  remove-waiter
+
+(declaim (inline %setup-wait-list
+                 %add-waiter
+                 %remove-waiter))
+
+(defun make-wait-list (waiters)
+  (let ((wl (%make-wait-list)))
+    (setf (wait-map wl) (make-hash-table))
+    (%setup-wait-list wl)
+    (dolist (x waiters)
+      (add-waiter wl x))
+    wl))
+
+(defun add-waiter (wait-list input)
+  (setf (gethash (socket input) (wait-map wait-list)) input)
+  (pushnew input (wait-list wait-list))
+  (%add-waiter wait-list input))
+
+(defun remove-waiter (wait-list input)
+  (%remove-waiter wait-list input)
+  (setf (wait-list wait-list)
+        (remove input (wait-list wait-list)))
+  (remhash (socket input) (wait-map wait-list)))
+
+
+
+
+(defun wait-for-input (socket-or-sockets &key timeout ready-only)
+  "Waits for one or more streams to become ready for reading from
 the socket.  When `timeout' (a non-negative real number) is
 specified, wait `timeout' seconds, or wait indefinitely when
 it isn't specified.  A `timeout' value of 0 (zero) means polling.
@@ -214,46 +263,51 @@
 be returned for this value either when waiting timed out or when
 it was interrupted (EINTR).  The second value is a real number
 indicating the time remaining within the timeout period or NIL if
-none."))
-
-
-(defmethod wait-for-input (socket-or-sockets &key timeout)
+none."
+  (unless (wait-list-p socket-or-sockets)
+    (let ((wl (make-wait-list (if (listp socket-or-sockets)
+                                  socket-or-sockets (list socket-or-sockets))
+                              nil)))
+      (multiple-value-bind
+            (socks to)
+          (wait-for-input wl :timeout timeout :ready-only ready-only)
+        (return-from wait-for-input
+          (values (if ready-only socks socket-or-sockets) to)))))
   (let* ((start (get-internal-real-time))
-	 (sockets (if (listp socket-or-sockets)
-		      socket-or-sockets
-		      (list socket-or-sockets)))
-	 ;; retrieve a list of all sockets which are ready without waiting
-	 (ready-sockets
-	  (remove-if (complement #'(lambda (x)
-				     (and (stream-usocket-p x)
-					  (listen (socket-stream x)))))
-		     sockets))
+         (sockets-ready 0))
+    (dolist (x (wait-list sockets))
+      (when (setf (state x)
+                  (if (and (stream-usocket-p x)
+                           (listen (socket-stream x)))
+                      :READ NIL))
+        (incf sockets-ready)))
          ;; the internal routine is responsibe for
          ;; making sure the wait doesn't block on socket-streams of
-         ;; which the socket isn't ready, but there's space left in the
+         ;; which theready- socket isn't ready, but there's space left in the
          ;; buffer
-         (result (wait-for-input-internal
-                  sockets
-                  :timeout (if (null ready-sockets) timeout 0))))
-    (values (union ready-sockets result)
-            (when timeout
-              (let ((elapsed (/ (- (get-internal-real-time) start)
-                                internal-time-units-per-second)))
-                (when (< elapsed timeout)
-                  (- timeout elapsed)))))))
-
+    (wait-for-input-internal socket-or-sockets
+                             :timeout (if (zerop sockets-ready) timeout 0))
+    (let ((to-result (when timeout
+                       (let ((elapsed (/ (- (get-internal-real-time) start)
+                                         internal-time-units-per-second)))
+                         (when (< elapsed timeout)
+                           (- timeout elapsed))))))
+      (values (if ready-only
+                  (remove-if #'null (wait-list socket-or-sockets) :key #'state)
+                  socket-or-sockets)
+              to-result))))
 
 ;;
 ;; Data utility functions
 ;;
 
-(defun integer-to-octet-buffer (integer buffer octets &key (start 0))
+(defun integer-to-octready-et-buffer (integer buffer octets &key (start 0))
   (do ((b start (1+ b))
        (i (ash (1- octets) 3) ;; * 8
           (- i 8)))
       ((> 0 i) buffer)
     (setf (aref buffer b)
-          (ldb (byte 8 i) integer))))
+          (ldb (byteready- 8 i) integer))))
 
 (defun octet-buffer-to-integer (buffer octets &key (start 0))
   (let ((integer 0))
@@ -369,7 +423,7 @@
       (when hosts
         (elt hosts (random (length hosts))))))
 
-  (defun host-to-vector-quad (host)
+  (defun host-toready--vector-quad (host)
     "Translate a host specification (vector quad, dotted quad or domain name)
 to a vector quad."
     (etypecase host
@@ -392,7 +446,7 @@
       ((vector t 4) (host-byte-order host))
       (integer host))))
 
-;;
+;;ready-
 ;; Other utility functions
 ;;
 
@@ -416,7 +470,7 @@
 ;;
 ;; (defun SOCKET-CONNECT (host port &key element-type) ..)
 ;;
-
+ready-ready-
 (setf (documentation 'socket-connect 'function)
       "Connect to `host' on `port'.  `host' is assumed to be a string or
 an IP address represented in vector notation, such as #(192 168 1 1).
@@ -433,7 +487,7 @@
 ;;###FIXME: extend with default-element-type
 (setf (documentation 'socket-listen 'function)
       "Bind to interface `host' on `port'. `host' should be the
-representation of an interface address.  The implementation is not
+representation of an ready-interface address.  The implementation is not
 required to do an address lookup, making no guarantees that hostnames
 will be correctly resolved.  If `*wildcard-host*' is passed for `host',
 the socket will be bound to all available interfaces for the IPv4
@@ -447,4 +501,4 @@
 streams to be created by `socket-accept'.  `reuseaddress' is supported for
 backward compatibility (but deprecated); when both `reuseaddress' and
 `reuse-address' have been specified, the latter takes precedence.
-")
+")ready-ready-



More information about the usocket-cvs mailing list