* Thomas Karolski [2008-12-05 22:04+0100] writes:
Helmut Eller schrieb:
Does READ-CHAR-NO-HANG work properly on socket streams? There is a comment in HANDLE-LISTEN (in win32.lisp)
Not sure - how could I test that?
For example with:
(read-char-no-hang (let ((socket (make-instance 'sb-bsd-sockets:inet-socket :type :stream :protocol :tcp))) (setf (sb-bsd-sockets:sockopt-reuse-address socket) t) (sb-bsd-sockets:socket-bind socket #(0 0 0 0) 5000) (sb-bsd-sockets:socket-listen socket 5) (unwind-protect (sb-bsd-sockets:socket-make-stream (sb-bsd-sockets:socket-accept socket) :output t :input t :element-type 'character) (sb-bsd-sockets:socket-close socket))))
This creates a socket, waits for someone to connect, and calls read-char-no-hang on the new stream. Start this in SBCL and execute "telnet localhost 5000" in a shell. read-char-no-hang should return nil as soon as the telnet client connects.
If it just waits, then you can type something into the telnet window and the first char should appear on the SBCL side. In this case read-char-no-hang doesn't work properly, it works like the ordinary read-char.
I think it should work on gray streams, but I'm not sure what slime is using.
In this situation it's a fd-stream and the fd is a socket.
I suspect that WAIT-FOR-EVENT/EVENT-LOOP (in swank.lisp) blocks even though the timeout argument is t. To see if that's actually the case, you could generate some debug output in WAIT-FOR-EVENT/EVENT-LOOP. It's the easiest if you use LOG-EVENT for that.
Changed wait-for-event/event-loop into:
(defun wait-for-event/event-loop (pattern timeout) (assert (or (not timeout) (eq timeout t))) (log-event "wait-for-event/event-loop: ~s ~s~%" pattern timeout) (let ((r (loop (check-slime-interrupts) (let ((event (poll-for-event pattern))) (when event (return (car event)))) (log-event "pre wait-for-input~%") (let ((events-enqueued *events-enqueued*) (ready (wait-for-input (list (current-socket-io)) timeout))) (log-event "after wait-for-input~%") (cond ((and timeout (not ready)) (return (values nil t))) ((or (/= events-enqueued *events-enqueued*) (eq ready :interrupt)) ;; rescan event queue, interrupts may enqueue new events ) (t (assert (equal ready (list (current-socket-io)))) (dispatch-event (decode-message (current-socket-io))))))))) (log-event "-wait-for-event/event-loop: ~s~%" r) r))
I attached the new *inferior-lisp* buffer. The last message is "pre wait-for-input", which indicates that its hanging inside wait-for-input. I also tried putting a log-event before read-char-no-hang inside wait-for-input, but that didn't seem to get logged for some reason.
wait-for-input is in swank-backend.lisp and in swank-sbcl.lisp. Perhaps you added it in the wrong file. Those are also in different packages so, you probably need something like (funcall (read-from-string "swank::log-event") ...)
Seeing this I guess you're right. Is there any way to work around this issue? - it does work for earlier calls to wait-for-input after all (though those all don't have a timeout).
The best solution would be to fix HANDLE-LISTEN, but I don't know how to do that.
As a workaround you can probably replace (wait-for-event `(:sldb-return ,(1+ level)) t) ; clean event-queue in sldb-loop with: (poll-for-event `(:sldb-return ,(1+ level)))
Helmut.