From: Maxim Cournoyer <maxim.cournoyer@gmail.com>
To: Leo Prikler <leo.prikler@student.tugraz.at>
Cc: guile-user@gnu.org
Subject: Re: Lost input when using suspendable read-line
Date: Mon, 23 Aug 2021 22:03:25 -0400 [thread overview]
Message-ID: <87sfyztx8y.fsf@gmail.com> (raw)
In-Reply-To: <04425a0337fa3d75f367d7e390c280ff5aa1bb1c.camel@student.tugraz.at> (Leo Prikler's message of "Mon, 23 Aug 2021 23:45:19 +0200")
Hello Leo!
Leo Prikler <leo.prikler@student.tugraz.at> writes:
> Hi,
>
> Am Montag, den 23.08.2021, 00:04 -0400 schrieb Maxim Cournoyer:
>> --8<---------------cut here---------------start------------->8---
>> (use-modules (ice-9 match)
>> (ice-9 rdelim)
>> (ice-9 suspendable-ports))
>>
>> (install-suspendable-ports!)
>>
>> (define (read-line* port cont)
>> ;; Return, as a pair, the line and the terminated delimiter
>> or end-of-file
>> ;; object. When a line cannot be read, return the
>> '(suspended
>> ;; . partial-continuation) pair, where partial-continuation
>> can be
>> ;; evaluated in the future when the port is ready to be read.
>> (call-with-prompt 'continue
>> (lambda ()
>> (parameterize ((current-read-waiter
>> (lambda (_)
>> (abort-to-prompt 'continue))))
>> (if cont
>> (cont)
>> (read-line port 'split))))
>> (lambda (partial-continuation)
>> (cons 'suspended partial-continuation))))
>>
>> (define (main)
>> [...]
>> (let loop ((cont #f))
>> (match (select (list (port->fdes port)) '() '())
>> (((fdes ..1) () ())
>> (let next-line ((line+delim (read-line* port cont)))
>> (match line+delim
>> (('suspended . partial-continuation)
>> (loop partial-continuation))
>> ((line . _)
>> (format #t "~a~%" line)
>> (next-line (read-line* port cont)))))))))))
>>
>> (main)
>> --8<---------------cut here---------------end--------------->8---
> This main loop appears broken. Look at the value of cont over time.
> On the first few lines, before suspending, you will read all the lines
> just fine. But afterwards it will be set to partial-continuation, even
> if said continuation is no longer current.
>
> This appears to be no issue if you need less than one continuation to
> finish the line, but if you need two or more, the outer continuation
> will cause you to redo the inner over and over again.
>
> I tried to make this loop somewhat more sensible:
>
> (define port (car child->parent-pipe))
> (define cont (make-parameter #f))
> (define do-read
> (lambda ()
> (match (select (list (port->fdes port)) '() '())
> (((fdes ..1) () ())
> (match (read-line* port (cont))
> (('suspended . partial-cont)
> partial-cont)
> ((line . _)
> (format #t "~a~%" line)
> #f))))))
>
> (let loop ((cont? (do-read)))
> (loop (parameterize ((cont cont?)) (do-read)))))))
>
> Here, each continuation is used exactly once, and that is to finish the
> current line. With this, I typically get output of the style:
>
> --8<---------------cut here---------------start------------->8---
> Line 1
> [wait for it...]
> Line 2
> Line 3
> Done!
> Line 1
> [wait for it...]
> --8<----------
> -----cut here---------------end--------------->8---
> So it's not perfect either, but it's somewhat better than what you have
> currently.
>
> I'd hazard a guess that there are simpler implementations that need not
> make use of parameters, particularly because I kinda eliminated the
> inner loop anyway. A simpler fix, which retains your structure is to
> use
> (next-line (read-line* port #f)))))))))))
> in the case where a line has already been read. This also seems to
> have the desired behaviour of waiting after the "Done!" line.
Thank you so much (to flatwhatson on #guile) :-). I had indeed failed
to carry/refresh the partial continuity in the inner loop. I had made a
similar mistake in the original problem which was capturing the
continuity at the wrong place in the closure, which was fixed like so:
--8<---------------cut here---------------start------------->8---
1 file changed, 7 insertions(+), 7 deletions(-)
src/mcron/base.scm | 14 +++++++-------
modified src/mcron/base.scm
@@ -330,8 +330,7 @@ associated <job-data> instance."
;; could not be read.
(let ((name (job-data:name data))
(pid (job-data:pid data))
- (port (job-data:port data))
- (cont (job-data:continuation data)))
+ (port (job-data:port data)))
(define (read-line*)
;; Return, as a pair, the line and the terminated delimiter or end-of-file
@@ -343,11 +342,12 @@ associated <job-data> instance."
(parameterize ((current-read-waiter
(lambda (_)
(abort-to-prompt 'continue))))
- (if cont
- (begin
- (set-job-data-continuation! data #f) ;reset continuation field
- (cont))
- (read-line port 'split))))
+ (let ((cont (job-data:continuation data)))
+ (if cont
+ (begin
+ (set-job-data-continuation! data #f) ;reset continuation
+ (cont))
+ (read-line port 'split)))))
(lambda (partial-continuation)
(cons 'suspended partial-continuation))))
--8<---------------cut here---------------end--------------->8---
You've made my day.
Happy hacking!
Maxim
prev parent reply other threads:[~2021-08-24 2:03 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-23 4:04 Lost input when using suspendable read-line Maxim Cournoyer
2021-08-23 21:45 ` Leo Prikler
2021-08-24 2:03 ` Maxim Cournoyer [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/guile/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87sfyztx8y.fsf@gmail.com \
--to=maxim.cournoyer@gmail.com \
--cc=guile-user@gnu.org \
--cc=leo.prikler@student.tugraz.at \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).