hopefully I have stripped the problematic code to something
representative but simple enough ...
I (using SBCL and Slime on macOS) have the following:
(defparameter *call-for-action*
(uiop:launch-program "nc -l 11111" :input :stream :output :stream))
to listen on some example port. Some third party application writes
lines to this stream, upon which I want to act according to the content
of the line.
(defun handle-one-action ()
(let ((stream (uiop:process-info-output *call-for-action*)))
(when (or (listen stream)
(progn (sleep 10) (listen stream)))
(read-line stream nil)
(some-action-returning-non-nil))))
Now I am looping over this:
(loop (unless (handle-one-action) (return)))
The loop works fine and acts "immediately" upon line after line, until
the third party application is done (there are other ways to confirm
this). Then the loop gets stuck (I waited for more than 10 seconds ...
(-:).
While stepping through the debugger and evaluating forms, I was able to
find out that
(listen stream)
returns T even after the app is done.
However, neither a read-line nor a
read-char were able to read anything and thus blocked. When I aborted
the debugger and tried
(loop (unless (handle-one-action) (return)))
again, it returned as expected after 10 seconds. The debugger revealed
that now before the read-line evaluating
(listen stream)
returned NIL.
So I understand why my code hangs, but not why "listen" detects something when there seems to be nothing.
Any hints on how I can ensure a robust exit from the loop? Pointers much appreciated!
I do not follow what you are trying to do. Your *call-for-action*
process is a netcat server already waiting for connections and handling clients as netcat do. So I don't know what a listen to its stream from
sbcl will do.
When the connection to netcat from the remote host is dropped, netcat
exits. The netcat process is dead. (uiop:process-alive-p
*call-for-action*) would return NIL.
PEEK-CHAR may return T
I would ditch this whole approach (using sleep 10, etc.) - and try to
use iolib streams
I do not follow what you are trying to do. Your *call-for-action*
process is a netcat server already waiting for connections and handling clients as netcat do.
Here is an complete (no external netcat involved) usocket example of a
timing out server that might be what you want:
* Manuel Giraud <87zgsn8nwp.fsf@elite.giraud> :
Wrote on Wed, 08 Sep 2021 10:36:06 +0200:
I do not follow what you are trying to do. Your *call-for-action*
process is a netcat server already waiting for connections and handling
clients as netcat do. So I don't know what a listen to its stream from
sbcl will do.
It's common-lisp's LISTEN on lisp streams
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 293 |
Nodes: | 16 (2 / 14) |
Uptime: | 225:19:10 |
Calls: | 6,623 |
Calls today: | 5 |
Files: | 12,171 |
Messages: | 5,318,600 |