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...