Kick Damien-DKICK1 wrote:

> [EMAIL PROTECTED] wrote:

> > Concerning toplevel polling:

> > Kick> Why does it seem to get stuck?

> > I think because the underlying system call (select(2)/poll(2)) is
> > only sensitive to status change.  Your handler is expected to read
> > all available input each time it is called.

> I don't think that it['s] true.  [...]

> AFAIK, that fact that READ-CHAR was returning characters without
> blocking would seem to indicate that select would tell us that the
> descriptor is readable.  [...]

Well, it would seem that this train of thought of mine was flawed.

  * (load "new-expect")

  ; Loading #p"/usr/vob/2gtt/lti/new-expect.sparcf".
  T
  * (shelf3--make)

  #<process 25602 :RUNNING>
  * (shelf3--add-fd-handler)

  #<Handler for INPUT on descriptor 11: #<Closure Over Function "DEFUN 
SHELF3--ADD-FD-HANDLER"
                                          {40A29871}>>
  * ; (get-internal-real-time) => 142838
  ; cxx_check_fd => 1
  ;; bytes-read => 50
  (shelf3--check-fd)
  ;;; (get-internal-real-time) => 143473
  ;;; (read-char (ext:process-pty *shelf3*)) =>  
  ;;; (get-internal-real-time) => 143473
  NIL
  * (shelf3--check-fd)
  ;;; (get-internal-real-time) => 143999
  ;;; (read-char (ext:process-pty *shelf3*)) => c
  ;;; (get-internal-real-time) => 143999
  NIL
  * (shelf3--check-fd)
  ;;; (get-internal-real-time) => 144223
  ;;; (read-char (ext:process-pty *shelf3*)) => h
  ;;; (get-internal-real-time) => 144223
  NIL
  * *expect-buffer*

  "Trying 127.0.0.1...
  Connected to 127.0.0.1.
  Escape"
  * ; (get-internal-real-time) => 148328
  ; cxx_check_fd => 1
  ;; bytes-read => 50
  ; (get-internal-real-time) => 148328
  ; cxx_check_fd => 1
  ;; bytes-read => 50
  ; (get-internal-real-time) => 148328
  ; cxx_check_fd => 1
  ;; bytes-read => 50

With the following code...

  % cat new-expect.lisp 
  (in-package #:lone-trip-investments-user)

  (defconstant +block-size+ 50)

  (defvar *shelf3*)
  (defvar *handler*)
  (defvar *expect-buffer*
    (make-array '(0) :element-type 'base-char :fill-pointer 0 :adjustable t))
  (defvar *address*
    "127.0.0.1")

  (let ((buffer (make-string +block-size+)))
    (defun read->echo (in out)
      ;; Can I make use (MAKE-ECHO-STREAM IN OUT) with READ-N-BYTES ?
      ;; Is there any benefit to using READ-N-BYTES instead of
      ;; READ-SEQUENCE ?
      (handler-bind
          ((error (lambda (e)
                    (declare (ignore e))
                    (format t ";; *** Invalidating the descriptor!~%")
                    (sys:invalidate-descriptor
                     (sys:fd-stream-fd
                      (ext:process-pty *shelf3*)))
                    (return-from read->echo 0))))
        (let ((bytes-read (sys:read-n-bytes in buffer 0 +block-size+ nil)))
          #+nil
          (format t ";; buffer => ~S~%" buffer)
          (format t ";; bytes-read => ~A~%" bytes-read)
          (force-output)
          (write-string buffer out :start 0 :end bytes-read)
          (force-output out)
          bytes-read))))

  (defun shelf3--make ()
    (when (and (boundp '*shelf3*) *shelf3*)
      (error "*shelf3* is already bound: ~A" *shelf3*))
    (setf *shelf3*
          (ext:run-program "telnet" (list *address*)
                           :wait nil :pty t :input t :output t :error t)))

  (defun shelf3--add-fd-handler ()
    (setf *handler*
          (sys:add-fd-handler
           (sys:fd-stream-fd (ext:process-pty *shelf3*))
           :input
           ;; Why is the handler being called before one even calls
           ;; SYS:SERVE-EVENT ?  I want to be able to set this handler
           ;; and then call SYS:SERVE-EVENT to have the handler invoked.
           (with-output-to-string (s *expect-buffer*)
             (lambda (fd)
               (declare (ignorable fd))
               (format t "; (get-internal-real-time) => ~A~%"
                       (get-internal-real-time))
               (format t "; cxx_check_fd => ~A~%"
                       (alien:alien-funcall
                        (alien:extern-alien "cxx_check_fd"
                                            (function c-call:int c-call:int))
                        (sys:fd-stream-fd (ext:process-pty *shelf3*))))
               (force-output)
               (let ((bytes-read (read->echo (ext:process-pty *shelf3*) s)))
                 #+nil
                 (format t "; *expect-buffer* => ~S~%"
                         *expect-buffer*)
                 (when (= bytes-read 0)
                   (sys:remove-fd-handler *handler*)
                   (format t "; Having just removed the handler ~A~%"
                           *handler*))))))))

  (defun shelf3--read-5 ()
    (dotimes (n 5)
      (format t "~A" (read-char (ext:process-pty *shelf3*))))
    (format t "~%"))

  (defun shelf3--check-fd ()
    (when (eql (alien:alien-funcall
                (alien:extern-alien "cxx_check_fd" (function c-call:int
                                                             c-call:int))
                (sys:fd-stream-fd (ext:process-pty *shelf3*)))
               0)
      (format t ";;; (get-internal-real-time) => ~A~%"
              (get-internal-real-time))
      (force-output)
      (format t ";;; (read-char (ext:process-pty *shelf3*)) => ~A~%"
              (read-char (ext:process-pty *shelf3*)))
      (force-output)
      (format t ";;; (get-internal-real-time) => ~A~%"
              (get-internal-real-time))
      (force-output)))

  % cat new-expect.c
  #include <sys/select.h>
  #include <sys/time.h>
  #include <string.h>

  int cxx_check_fd(int fd)
  {
      fd_set read_fds;
      struct timeval timeout;

      FD_ZERO(&read_fds);
      FD_SET(fd, &read_fds);
      timeout.tv_sec = 0;
      timeout.tv_usec = 0;
      select(fd+1, &read_fds, 0, 0, &timeout);
      return FD_ISSET(fd, &read_fds);
  }

  % 

I'm still surprised that READ-CHAR is not blocking when "select" is
telling us the filedes is not available.  Must be some buffering of
which I was not considering the possibility.  I'm still confused,
though.  Surely "read" must block if "select" tells us that the
filedes is not available for reading...

Reply via email to