Here's a procedure for reading lines from the stdin. It implements the handling of a POST command from NNTP. It seems to work, but it looks
like work from a beginner. I wonder if there's anything you can say to illuminate me.
What does it do? A thread will kill the program if the user takes too
long. (Otherwise we kill the thread.) The reading ends gracefully if
the user types a ``.'' on a line by itself. Otherwise we append the
current line read onto the end of a LINES-SO-FAR list and repeat. (Yes,
if a ``..'' is on a line by itself, that's the user escaping the dot
that's not the end of input. I decided to implement this corner-case
with that /let/ before repeating.)
(define (read-with-timeout [lines-so-far '()] [timeout 60])
(define killer
(thread (lambda ()
(sleep timeout)
(displayln "Timeout on posting article.")
(flush-output)
(exit))))
(define ln (read-line (current-input-port) 'return-linefeed))
(kill-thread killer)
(cond
[(eof-object? ln)
(displayln "fatal: eof while reading article...")
(exit)]
[(string=? ln ".")
(string-join lines-so-far "\r\n")]
[else
(let ([ln (if (string=? ln "..") "." ln)])
(read-with-timeout (append lines-so-far (list ln))))]))
Any thoughts, comments? Help to be a better Lisp programmer.
On 2023-12-26, Julieta Shem <jshem@yaxenu.org> wrote:
Here's a procedure for reading lines from the stdin. It implements the
handling of a POST command from NNTP. It seems to work, but it looks
like work from a beginner. I wonder if there's anything you can say to
illuminate me.
What does it do? A thread will kill the program if the user takes too
long. (Otherwise we kill the thread.) The reading ends gracefully if
the user types a ``.'' on a line by itself. Otherwise we append the
current line read onto the end of a LINES-SO-FAR list and repeat. (Yes,
if a ``..'' is on a line by itself, that's the user escaping the dot
that's not the end of input. I decided to implement this corner-case
with that /let/ before repeating.)
(define (read-with-timeout [lines-so-far '()] [timeout 60])
(define killer
(thread (lambda ()
(sleep timeout)
(displayln "Timeout on posting article.")
(flush-output)
(exit))))
(define ln (read-line (current-input-port) 'return-linefeed))
(kill-thread killer)
(cond
[(eof-object? ln)
(displayln "fatal: eof while reading article...")
(exit)]
[(string=? ln ".")
(string-join lines-so-far "\r\n")]
[else
(let ([ln (if (string=? ln "..") "." ln)])
(read-with-timeout (append lines-so-far (list ln))))]))
Any thoughts, comments? Help to be a better Lisp programmer.
Using a thread just for timing out a read is ugly, like something you'd
do in a shell program, not in a serious application.
(And if the shell is Bash, you wouldn't have to; it has a timed out read! Type "help read" in bash: you can see that read can read characters
up to a specified delimiter, with a timeout (-t)).
A proper Unix program uses select or poll, or else uses setsockopt
to set up read timeout (if the input is known to be a socket).
Hello. Say anything and press RET.123
But why do you say that?
God, you're slow.
I see to see a complicated behavior of this program in Windows ``Command Prompt'', but not in the GNU EMACS eshell. On the Command Prompt,
sometimes the timeout doesn't take effect. To make it easy to hit
reproduce, I reduce the timeout to 1. Here's an example. I took way
longer than 1 second to type that ``123''. The timeout only took effect
on the second wait. Weird.
c:\something>racket timezup.rkt
Hello. Say anything and press RET.123
< 123
But why do you say that?
God, you're slow.
Hello. Say anything and press RET.No timeout.
But why do you say that?0.00user 0.00system 0:11.68elapsed 0%CPU (0avgtext+0avgdata 5228maxresident)k 0inputs+0outputs (1389major+0minor)pagefaults 0swaps
God, you're slow.
https://docs.racket-lang.org/reference/sync.html
On Tue, 26 Dec 2023 12:25:11 -0300, Julieta Shem wrote:
https://docs.racket-lang.org/reference/sync.html
I had a look at that. Why do languages feel they have to stack on thick layers of extra abstraction on top of basic POSIX concepts?
I do more Python than Lisp, and look how thin Python’s standard-library abstractions on top of select/poll are: <https://docs.python.org/3/library/select.html>. Makes it so much easier
to figure out what’s going on.
I suppose Racket could be worse. It could be Java.
Julieta Shem <jshem@yaxenu.org> writes:
[...]
I see to see a complicated behavior of this program in Windows ``Command
Prompt'', but not in the GNU EMACS eshell. On the Command Prompt,
sometimes the timeout doesn't take effect. To make it easy to hit
reproduce, I reduce the timeout to 1. Here's an example. I took way
longer than 1 second to type that ``123''. The timeout only took effect
on the second wait. Weird.
c:\something>racket timezup.rkt
Hello. Say anything and press RET.123
< 123
But why do you say that?
God, you're slow.
Here's a better presentation. I set the timeout to 1 second. After
about ten seconds, I wrote ``No timeout'' and pressed RET.
c:\something>c:/sys/emacs/usr/mingw/usr/bin/time.exe racket timezup.rkt
Hello. Say anything and press RET.No timeout.
< No timeout.
But why do you say that?0.00user 0.00system 0:11.68elapsed 0%CPU (0avgtext+0avgdata 5228maxresident)k 0inputs+0outputs (1389major+0minor)pagefaults 0swaps
God, you're slow.
On Tue, 26 Dec 2023 12:25:11 -0300, Julieta Shem wrote:
https://docs.racket-lang.org/reference/sync.html
I had a look at that. Why do languages feel they have to stack on thick >layers of extra abstraction on top of basic POSIX concepts?
I do more Python than Lisp, and look how thin Python’s standard-library >abstractions on top of select/poll are: ><https://docs.python.org/3/library/select.html>. Makes it so much easier
to figure out what’s going on.
I suppose Racket could be worse. It could be Java.
... Windows is not POSIX compliant.
On Fri, 29 Dec 2023 00:50:32 -0500, George Neuner wrote:
... Windows is not POSIX compliant.
Wasn’t NT supposed to be POSIX-compliant in the beginning? Seems like that >whole part of the system has bitrotted away ...
So you have to ask yourself: is your return from supporting Windows users >worth the greatly increased expense?
On Fri, 29 Dec 2023 02:19:44 -0000 (UTC), Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
On Tue, 26 Dec 2023 12:25:11 -0300, Julieta Shem wrote:
https://docs.racket-lang.org/reference/sync.html
I had a look at that. Why do languages feel they have to stack on thick >>layers of extra abstraction on top of basic POSIX concepts?
For one thing, because Windows is not POSIX compliant.
On Fri, 29 Dec 2023 06:04:52 -0000 (UTC), Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
So you have to ask yourself: is your return from supporting Windows
users worth the greatly increased expense?
More people directly use Windows than directly use Unix/Linux.
George Neuner <gneuner2@comcast.net> writes:
On Fri, 29 Dec 2023 02:19:44 -0000 (UTC), Lawrence D'Oliveiro
<ldo@nz.invalid> wrote:
On Tue, 26 Dec 2023 12:25:11 -0300, Julieta Shem wrote:
https://docs.racket-lang.org/reference/sync.html
I had a look at that. Why do languages feel they have to stack on thick >>>layers of extra abstraction on top of basic POSIX concepts?
For one thing, because Windows is not POSIX compliant.
Microsoft lawyers called me to say Microsoft supports ISO-IEC
9945-1:1990 --- and, having installed Cygwin, they could not distinguish
a POSIX compliant system from Microsoft Windows. I said our team would
get back to them.
The Windows APIs are not POSIX, but for the most part they provide
equivalent functionality, so POSIX calls can be translated into Windows
call (with varying degrees of difficulty, the asynch stuff in particular
is completely different). This is what cygwin does.
On Sun, 31 Dec 2023 01:31:34 -0500, George Neuner wrote:
The Windows APIs are not POSIX, but for the most part they provide
equivalent functionality, so POSIX calls can be translated into Windows
call (with varying degrees of difficulty, the asynch stuff in particular
is completely different). This is what cygwin does.
Actually, Cygwin actually manages to do something a bit better than that.
Consider the select/poll calls
<https://docs.python.org/3/library/select.html>: note the caveat that, on
Windows, they only work on sockets, whereas on regular POSIX OSes they
work on other things, in particular pipes.
Cygwin manages to implement its select/poll calls on pipes, on Windows.
Cygnal is probably the best way to port a POSIX program to Windows.
On Sun, 31 Dec 2023 07:27:56 -0000 (UTC), Kaz Kylheku wrote:
Cygnal is probably the best way to port a POSIX program to Windows.
There is a better way now, and that is WSL2.
On 2023-12-31, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
On Sun, 31 Dec 2023 07:27:56 -0000 (UTC), Kaz Kylheku wrote:
Cygnal is probably the best way to port a POSIX program to Windows.
There is a better way now, and that is WSL2.
I don't think so. With Cygnal, you deliver an .exe accompanied by a DLL
or two, and that's it.
On Sun, 31 Dec 2023 17:20:16 -0000 (UTC), Kaz Kylheku wrote:
On 2023-12-31, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
On Sun, 31 Dec 2023 07:27:56 -0000 (UTC), Kaz Kylheku wrote:
Cygnal is probably the best way to port a POSIX program to Windows.
There is a better way now, and that is WSL2.
I don't think so. With Cygnal, you deliver an .exe accompanied by a DLL
or two, and that's it.
WSL2 at least lets you run a proper Linux distro, with proper package management.
Frickin Windows as a host for Linux? That's a recipe for disaster (MS
Windows must die; thank you).
On Sun, 31 Dec 2023 17:20:16 -0000 (UTC), Kaz Kylheku wrote:
On 2023-12-31, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
On Sun, 31 Dec 2023 07:27:56 -0000 (UTC), Kaz Kylheku wrote:
Cygnal is probably the best way to port a POSIX program to Windows.
There is a better way now, and that is WSL2.
I don't think so. With Cygnal, you deliver an .exe accompanied by a DLL
or two, and that's it.
WSL2 at least lets you run a proper Linux distro, with proper package management.
On Sun, 31 Dec 2023 21:30:18 -0000 (UTC), De ongekruisigde wrote:
Frickin Windows as a host for Linux? That's a recipe for disaster (MS
Windows must die; thank you).
Microsoft has no choice: it has to do something to stem the tide of developers deserting Windows for Linux. Of course WSL2 is a kludge. But
then the whole history of Windows is of piling kludges on kludges, for short-term profit-driven reasons.
Funny you say proper package management as if UNIX ever had this ---
before GNU Guix.
On Sun, 31 Dec 2023 21:48:06 -0300, Julieta Shem wrote:
Funny you say proper package management as if UNIX ever had this ---
before GNU Guix.
Where was there a “Unix” that had this? It was pretty much developed and refined by Debian and Red Hat, from about 1993 onwards.
Lawrence D'Oliveiro <ldo@nz.invalid> writes:
On Sun, 31 Dec 2023 21:48:06 -0300, Julieta Shem wrote:
Funny you say proper package management as if UNIX ever had this ---
before GNU Guix.
Where was there a “Unix” that had this? It was pretty much developed
and refined by Debian and Red Hat, from about 1993 onwards.
Funny you think that Debian and Red Hat ever had it. What they seem to
have done --- with all due respect --- is to compress files with
metadata.
On Sun, 31 Dec 2023 17:20:16 -0000 (UTC), Kaz Kylheku wrote:
On 2023-12-31, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
On Sun, 31 Dec 2023 07:27:56 -0000 (UTC), Kaz Kylheku wrote:
Cygnal is probably the best way to port a POSIX program to Windows.
There is a better way now, and that is WSL2.
I don't think so. With Cygnal, you deliver an .exe accompanied by a DLL
or two, and that's it.
WSL2 at least lets you run a proper Linux distro, with proper package management.
On 2023-12-31, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
WSL2 at least lets you run a proper Linux distro, with proper package
management.
That's nice, but not what you want when you want to ship a Windows application ...
On Mon, 1 Jan 2024 03:20:05 -0000 (UTC), Kaz Kylheku wrote:
On 2023-12-31, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
WSL2 at least lets you run a proper Linux distro, with proper package
management.
That's nice, but not what you want when you want to ship a Windows
application ...
Which is why WSL2 is likely to become a mandatory part of future Windows installs.
On 2024-01-01, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
On Mon, 1 Jan 2024 03:20:05 -0000 (UTC), Kaz Kylheku wrote:
On 2023-12-31, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
WSL2 at least lets you run a proper Linux distro, with proper package
management.
That's nice, but not what you want when you want to ship a Windows
application ...
Which is why WSL2 is likely to become a mandatory part of future Windows
installs.
Might work in the future, and definitely won't work on older Windows,
like 7.
How easily do WSL2 programs work with the native Windows environment?
Suppose that the current directory on the F: drive is \data,
and the WSL2 program is given the path F:file.txt. Will it understand
that the path means F:\data\file.txt?
The Cygnal program will do that.
WSL's FAQ says this:
You can also access your local machine’s file system from within the
Linux Bash shell – you’ll find your local drives mounted under the
/mnt folder. For example, your C: drive is mounted under /mnt/c:
That's not native; it's like /cygdrive/c in Cygwin. I fixed that;
I got rid of /cygdrive/c and most of the path munging.
On 2024-01-01, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
Which is why WSL2 is likely to become a mandatory part of future
Windows installs.
Might work in the future, and definitely won't work on older Windows,
like 7.
How easily do WSL2 programs work with the native Windows environment?
Suppose that the current directory on the F: drive is \data,
and the WSL2 program is given the path F:file.txt. Will it understand
that the path means F:\data\file.txt?
On 2024-01-01, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
On Mon, 1 Jan 2024 08:07:50 -0000 (UTC), Kaz Kylheku wrote:
How easily do WSL2 programs work with the native Windows environment?
They don’t need to, won’t need to.
It's nice that you can drop that requirement. I have that requirement.
Suppose that the current directory on the F: drive is \data,
and the WSL2 program is given the path F:file.txt. Will it understand
that the path means F:\data\file.txt?
No, it means what you said, which is “F:file.txt”. Just tried this:
ldo@theon:~> touch F:file.txt
ldo@theon:~> ls -l F:file.txt
-rw-r--r-- 1 ldo users 0 Jan 2 10:32 F:file.txt
Well, that is not native Windows behavior ...
On Mon, 1 Jan 2024 08:07:50 -0000 (UTC), Kaz Kylheku wrote:
On 2024-01-01, Lawrence D'Oliveiro <ldo@nz.invalid> wrote:
Which is why WSL2 is likely to become a mandatory part of future
Windows installs.
Might work in the future, and definitely won't work on older Windows,
like 7.
Which nobody uses any more--nobody that Microsoft cares about, anyway.
How easily do WSL2 programs work with the native Windows environment?
They don’t need to, won’t need to.
Windows programs, on the other hand, will be working, unbeknownst to them, through an emulation layer not entirely unlike WINE, onto the Linux
kernel.
Suppose that the current directory on the F: drive is \data,
and the WSL2 program is given the path F:file.txt. Will it understand
that the path means F:\data\file.txt?
No, it means what you said, which is “F:file.txt”. Just tried this:
ldo@theon:~> touch F:file.txt
ldo@theon:~> ls -l F:file.txt
-rw-r--r-- 1 ldo users 0 Jan 2 10:32 F:file.txt
In C I would have used select. But how do I select in Racket? I found Racket's sync/timeout, a procedure based on Racket's ``events''. The reference dissertates briefly about events at
https://docs.racket-lang.org/reference/sync.html
and they cite
John H. Reppy, Concurrent Programming in ML, Cambridge University
Press, 1999. https://doi.org/10.1017/CBO9780511574962
as a reference. It's unclear to me that this is what I'm looking for,
but it might very well be.
#lang racket/base
(define (read-line-timeout [timeout 60] [port (current-input-port)])
(define port-or-false
(sync/timeout timeout port))
(and port-or-false (read-line port-or-false)))
(define (interact-with-timeout timeout)
(define ln (read-line-timeout timeout))
(cond [(not ln)
(say "> God, you're slow.")]
[(eof-object? ln)
(say "> Okay, see you later.")]
[else
(say (format "< ~a" ln))
(say "> But why do you say that?")
(interact-with-timeout timeout)]))
(define (say s) (displayln s) (flush-output))
(module+ main
(say "> Hello. Say anything and press RET.")
(interact-with-timeout 3))
which seems helpful, but with no examples. Given that I could write
such program in C using select(2) or poll(2), would there be anything
you could say here that would give me a direction? Thank you! Any interesting publication that I so far failed to have found? (For
instance, I have Peter Seibel's Practical Common Lisp, but it doesn't
seem to help me with this exercise.)
On 2024-01-05, Julieta Shem <jshem@yaxenu.org> wrote:
which seems helpful, but with no examples. Given that I could write
such program in C using select(2) or poll(2), would there be anything
you could say here that would give me a direction? Thank you! Any
interesting publication that I so far failed to have found? (For
instance, I have Peter Seibel's Practical Common Lisp, but it doesn't
seem to help me with this exercise.)
One thing to watch out for, in any language, is if you're reading
from high level buffered streams but trying to use select or poll.
(This goes for C stdio also.)
You don't want to be accidentally blocking in select or poll
while the stream contains unread, buffered data (already transferred
from the operating system descriptor to user space).
That can happen if the stream reads more data than your program
requested. E.g. you're looking for one byte, and poll. The stream
initially has nothing so this is right. Poll unblocks when data
becomes available, so you read the one byte from the stream. But suppose
that the stream actually reads 500 bytes from the OS, giving you 1 and buffering 499. After that, you have to read the available 499 bytes
from the stream before calling poll (unless poll is aware of streams,
rather than just a thin wrapper for the POSIX function.)
You have to put the underlying descriptor into non-blocking mode
(even if you're only reading from that one). Then whenever it polls
positive, read all available data from the stream until it hits an
error from the file descriptor with EWOULDBLOCK.
I need to learn to put file descriptors in non-blocking mode. Thanks
for reminding me. Surely an abstraction to handle this is desired. The problem seems to boil down to reading a partial line in the buffer
without having the rest of it --- say coming from the network still.
The procedure for reading such lines should somehow hold the partial
line until it completes.
I managed to discover UNIX-SIMPLE-POLL in SB-UNIX. Here's a procedure
that suffers from the problem you warned me above.
(defun read-line-timeout (s)
"reads a line from stdin or times out in S seconds."
(let ((ready (sb-unix:unix-simple-poll 0 :input (* 1000 s))))
(cond (ready (format t "I read: ~a~%" (read-line)))
(t (format t "God, you're slow.~%")))))
;; main =
(read-line-timeout 3)
* Julieta Shem <87frzcwgxi.fsf @yaxenu.org> :
Wrote on Fri, 05 Jan 2024 01:19:21 -0300:
I need to learn to put file descriptors in non-blocking mode. Thanks
for reminding me. Surely an abstraction to handle this is desired. The
problem seems to boil down to reading a partial line in the buffer
without having the rest of it --- say coming from the network still.
The procedure for reading such lines should somehow hold the partial
line until it completes.
I managed to discover UNIX-SIMPLE-POLL in SB-UNIX. Here's a procedure
that suffers from the problem you warned me above.
(defun read-line-timeout (s)
"reads a line from stdin or times out in S seconds."
(let ((ready (sb-unix:unix-simple-poll 0 :input (* 1000 s))))
(cond (ready (format t "I read: ~a~%" (read-line)))
(t (format t "God, you're slow.~%")))))
;; main =
(read-line-timeout 3)
I think a better way to approach this is to (somehow) set a
stream-timout on the stream and have read-line (on your special stream) return nil (or a supplied on-timeout value) if there is no data on the stream. your lisp code in your thread would still deal with a blocking
read.
I think a better way to approach this is to (somehow) set a
stream-timout on the stream and have read-line (on your special stream) return nil (or a supplied on-timeout value) if there is no data on the stream. your lisp code in your thread would still deal with a blocking
read.
On Fri, 05 Jan 2024 17:34:20 +0530, Madhu wrote:
I think a better way to approach this is to (somehow) set a
stream-timout on the stream and have read-line (on your special stream)
return nil (or a supplied on-timeout value) if there is no data on the
stream. your lisp code in your thread would still deal with a blocking
read.
Remember the main point of select/poll, in that it lets you non- deterministically wait on a number of file descriptors at once, and
respond immediately to the first one that has any I/O to do.
Kaz Kylheku <433-929-6894@kylheku.com> writes:
On 2024-01-05, Julieta Shem <jshem@yaxenu.org> wrote:
which seems helpful, but with no examples. Given that I could write
such program in C using select(2) or poll(2), would there be anything
you could say here that would give me a direction? Thank you! Any
interesting publication that I so far failed to have found? (For
instance, I have Peter Seibel's Practical Common Lisp, but it doesn't
seem to help me with this exercise.)
One thing to watch out for, in any language, is if you're reading
from high level buffered streams but trying to use select or poll.
(This goes for C stdio also.)
You don't want to be accidentally blocking in select or poll
while the stream contains unread, buffered data (already transferred
from the operating system descriptor to user space).
That can happen if the stream reads more data than your program
requested. E.g. you're looking for one byte, and poll. The stream
initially has nothing so this is right. Poll unblocks when data
becomes available, so you read the one byte from the stream. But suppose
that the stream actually reads 500 bytes from the OS, giving you 1 and
buffering 499. After that, you have to read the available 499 bytes
from the stream before calling poll (unless poll is aware of streams,
rather than just a thin wrapper for the POSIX function.)
You have to put the underlying descriptor into non-blocking mode
(even if you're only reading from that one). Then whenever it polls
positive, read all available data from the stream until it hits an
error from the file descriptor with EWOULDBLOCK.
I need to learn to put file descriptors in non-blocking mode. Thanks
for reminding me.
Madhu <enometh@meer.net> writes:
I think a better way to approach this is to (somehow) set a
stream-timout on the stream and have read-line (on your special stream)
return nil (or a supplied on-timeout value) if there is no data on the
stream. your lisp code in your thread would still deal with a blocking
read.
Sounds interesting. It's a stream like stdin, stdout, stderr, but it
has a timeout associate with it. Reading or writing to it times out if nothing usual happens before. Is that the idea?
It's a bit scary that this isn't done by any library given all the years
of SBCL. What's up with that? I'm not talking about CL as a standard
--- I'm talking about the implementations. In practice we need all of
these system-specific things.
I was expecting replies in the form --- hold it, young Skywalker: here's
how we've doing this for decades. I'm a total beginner. The procedure
above is my first procedure in CL. It makes me feel that the most
useful thing I can do in CL is learn about the SBCL's FFI. That's no complaint. I'm just trying to understand the Lisp world.
Funny you think that Debian and Red Hat ever had it. What they seem to
have done --- with all due respect --- is to compress files with
metadata. Pretty useful, but I think that /management/ should be
applied to GNU Guix, with due credit to Nix, the pioneer.
* Julieta Shem <87jzonvg81.fsf @yaxenu.org> :
Wrote on Fri, 05 Jan 2024 14:32:14 -0300:
Madhu <enometh@meer.net> writes:
I think a better way to approach this is to (somehow) set a
stream-timout on the stream and have read-line (on your special stream)
return nil (or a supplied on-timeout value) if there is no data on the
stream. your lisp code in your thread would still deal with a blocking
read.
Sounds interesting. It's a stream like stdin, stdout, stderr, but it
has a timeout associate with it. Reading or writing to it times out if
nothing usual happens before. Is that the idea?
It's a bit scary that this isn't done by any library given all the years
of SBCL. What's up with that? I'm not talking about CL as a standard
--- I'm talking about the implementations. In practice we need all of
these system-specific things.
I was expecting replies in the form --- hold it, young Skywalker: here's
how we've doing this for decades. I'm a total beginner. The procedure
above is my first procedure in CL. It makes me feel that the most
useful thing I can do in CL is learn about the SBCL's FFI. That's no
complaint. I'm just trying to understand the Lisp world.
I searched for a published example but I didn't find it -- I have an
example in an implementation of a "https stream" a subclass of fd-stream (probably derived from something "emarsden" posted somewhere, but i
can't find it) which specializes the fd-stream class and adds a
connection timeout. IIRC This integrates with the SERVE-EVENT
abstraction which is a co-ooperative multiprocessing layer about select,
and the implementation is tied to SERVE-EVENT, if the fd is not usable
(data does not arrive on it in the given time), it raises a timeout
error.
On second thoughts I don't think it will solve your problem.
I just thought this was the way to approach the problem: call READ and
handle a timeout condition (from the implementation)
I think the CMUCL code base still has the code for a netnews client for hemlock, though it doesn't use this strategy. You can see the code from
1980, (which has not yet been deleted by some open source who has been
hired to delete it) here https://gitlab.common-lisp.net/cmucl/cmucl/-/blob/master/src/hemlock/netnews.lisp
(or wihout js) https://gitlab.common-lisp.net/cmucl/cmucl/-/raw/master/src/hemlock/netnews.lisp
I checked trivial-nntp (probably in quicklisp) but it just wraps
usocket and doesnt deal with timeouts. iolib also doesnt seem to
expose any setsock SO_RCVTIMEO, though it can probably used, i havent
figured it out, i'll have to look again later.
Julieta Shem <jshem@yaxenu.org> writes:
Funny you think that Debian and Red Hat ever had it. What they seem to
have done --- with all due respect --- is to compress files with
metadata. Pretty useful, but I think that /management/ should be
applied to GNU Guix, with due credit to Nix, the pioneer.
If you are into GNU Guix (I am currently being tempted to switch), then
you are aware of Guile (methinks you mentioned it in another thread),
which brings me back to your original question: Since Guile is
advertised with its POSIX capabilities, I expect you could find a
better/more familiar technique there.
But that is just guessing and gut feeling, not based on any research.
So, my exercise was to read a file
descriptor with a timeout --- give me your command or die.
On Sat, 06 Jan 2024 18:43:24 -0300, Julieta Shem wrote:
So, my exercise was to read a file
descriptor with a timeout --- give me your command or die.
Typically you will have multiple concurrent client connections going on.
So you want an event loop that monitors all connections. Each one will
have a last-active timer. The poll(2) call will have a timeout that corresponds to the earliest of these timer expirations. So if you don’t
get any activity in that time (or even if you do), you start disconnecting idle clients.
Lawrence D'Oliveiro <ldo@nz.invalid> writes:
On Sat, 06 Jan 2024 18:43:24 -0300, Julieta Shem wrote:
So, my exercise was to read a file
descriptor with a timeout --- give me your command or die.
Typically you will have multiple concurrent client connections going
on. So you want an event loop that monitors all connections. Each
one will have a last-active timer. The poll(2) call will have a
timeout that corresponds to the earliest of these timer
expirations. So if you don’t get any activity in that time (or even
if you do), you start disconnecting idle clients.
The exercise is much easier than that --- it's an NNTP server, so the
service doesn't need to handle clients in a centralized manner. The
TCP server will spawn the nntpd, which will only handle a single
client.
* Julieta Shem <87ttnpsysl.fsf @yaxenu.org> :
Wrote on Sat, 06 Jan 2024 22:43:54 -0300:
Lawrence D'Oliveiro <ldo@nz.invalid> writes:
On Sat, 06 Jan 2024 18:43:24 -0300, Julieta Shem wrote:
So, my exercise was to read a file
descriptor with a timeout --- give me your command or die.
Typically you will have multiple concurrent client connections going
on. So you want an event loop that monitors all connections. Each
one will have a last-active timer. The poll(2) call will have a
timeout that corresponds to the earliest of these timer
expirations. So if you don’t get any activity in that time (or even
if you do), you start disconnecting idle clients.
The exercise is much easier than that --- it's an NNTP server, so the
service doesn't need to handle clients in a centralized manner. The
TCP server will spawn the nntpd, which will only handle a single
client.
TCPD is a nice abstraction but in my mind there is a conflict, bringing
in lisp, also brings an unbearable urge to manage the file descriptors
from lisp in a long running stateful lisp process, Personally I never
got over this particular dissonance ("If I use lisp I _have_ to take advantage of this feature long-running-process -- or bust"), and prefer
short small executables programs for processes. [OTOH I remember cl-http
on buggy linux in 1996 which would result in a number of TCP connections which were never cleaned up for 2 days]
Likewise "If I use Lisp I _have_ to take advantage of the stream
abstraction and all the goodies of its stream design". In lisp stdin
(when it is also *terminal-io*) is special because it is an interactive stream. You can call PEEK on it to see if there is data to be read and
and handle some aspects of interactivity primitively through that. CL
defines INTERACTIVE-STREAM-P and extensions like gray streams purport to support it. but when you get stdin from a fdstream or TCPstream, it
isn't really special.
Madhu <enometh@meer.net> writes:[...]
TCPD is a nice abstraction but in my mind there is a conflict, bringing
in lisp, also brings an unbearable urge to manage the file descriptors
from lisp in a long running stateful lisp process, Personally I never
Likewise "If I use Lisp I _have_ to take advantage of the stream
abstraction and all the goodies of its stream design". In lisp stdin
(when it is also *terminal-io*) is special because it is an interactive
stream. You can call PEEK on it to see if there is data to be read and
and handle some aspects of interactivity primitively through that. CL
defines INTERACTIVE-STREAM-P and extensions like gray streams purport to
support it. but when you get stdin from a fdstream or TCPstream, it
isn't really special.
I don't understand. The program is being written to handle a TCP
connection. Terminals are not going to be connected to it. How would
you handle that?
I am thankful I can write the program with my keyboard attached to it
and then later naturally switch it all to a TCP connection. Isn't that great?
Axel Reichert <mail@axel-reichert.de> writes:
which brings me back to your original question: Since Guile is
advertised with its POSIX capabilities, I expect you could find a
better/more familiar technique there.
But that is just guessing and gut feeling, not based on any research.
Relative to my desires that's good intuition. I've been looking for a
Lisp as a medium of expression and Racket does appear to be the most sophisticated one.
seeing how much fun I was having just considering Common Lisp I did
think of Guile precisely because of the GNU Guix connection.
reading Common Lisp documentation I felt like a computing historian.
I do enjoy the history of computing quite a lot and it does feel good
to actually use tools older than the current ones that actually feels
/quite/ superior
Julieta Shem <jshem@yaxenu.org> writes:
Axel Reichert <mail@axel-reichert.de> writes:
which brings me back to your original question: Since Guile is
advertised with its POSIX capabilities, I expect you could find a
better/more familiar technique there.
But that is just guessing and gut feeling, not based on any research.
Relative to my desires that's good intuition. I've been looking for a
Lisp as a medium of expression and Racket does appear to be the most
sophisticated one.
Sounds familiar. Some years back I was torn between (Steel Bank) Common
Lisp, Clojure and Racket. From an aesthetic/minimalistic point of view,
I prefer Lisp-1s/Schemes, but SBCL is just an awesome interactive
experience in Emacs with SLIME and really fast. Clojure feels more
modern (but I am allergic against anything related to Java) and Racket >powerful (but somehow not pragmatic). Common Lisp seems more down to
earth, but also baroque (its age shows).
seeing how much fun I was having just considering Common Lisp I did
think of Guile precisely because of the GNU Guix connection.
I somewhere read that Guile is the most Common-Lisp-like of the Scheme >implementations (if you ask for it, I will try to dig up the link). From
my above paragraph, you can imagine that this is intriguing for
me. Especially having a reasonably fast general purpose language that >purportedly integrates well with everything POSIX or C (I do not speak
C), can be used to configure (I should rather say "determine") the setup
of an operating system (Guix SD) and, with this OS, also for Emacs
(since Guix SD has Guile Emacs, which otherwise is said to be quite an >endeavour to build/install). I really like to reduce the number of tools
in my box, provided they are powerful and I am willing to learn them
deeply.
reading Common Lisp documentation I felt like a computing historian.
[...]
I do enjoy the history of computing quite a lot and it does feel good
to actually use tools older than the current ones that actually feels
/quite/ superior
Sure, and again, sounds familiar. Emacs is old, AWK is old, Unix is
old. Many of the good tools are old, it is called
https://en.wikipedia.org/wiki/Lindy_effect
Learn them early, try to master them until late in your life. (This
makes sense only for both powerful and versatile tools.)
Best regards
Axel
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 405 |
Nodes: | 16 (2 / 14) |
Uptime: | 46:30:38 |
Calls: | 8,495 |
Calls today: | 8 |
Files: | 13,203 |
Messages: | 5,916,121 |
Posted today: | 1 |