[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Lost input when using suspendable read-line
From: |
Maxim Cournoyer |
Subject: |
Lost input when using suspendable read-line |
Date: |
Mon, 23 Aug 2021 00:04:46 -0400 |
Hello,
I'm pretty new to this, so hopefully I'm doing something wrong, but when
using a suspendable read-line with the following "minimal" program:
--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)
;; Create a pipe, and set its read side to non-blocking mode.
(define child->parent-pipe (pipe))
(let ((flags (fcntl (car child->parent-pipe) F_GETFL)))
(fcntl (car child->parent-pipe) F_SETFL (logior O_NONBLOCK flags)))
;; Empty buffers to avoid duplicated output.
(flush-all-ports)
(match (primitive-fork)
(0 ;child
;; Connect the stdout and stderr outputs of the child process to the
;; pipe established in the parent.
(close (car child->parent-pipe)) ;unused input pipe
(dup2 (port->fdes (cdr child->parent-pipe)) 1)
(dup2 1 2)
(set-current-output-port (cdr child->parent-pipe))
(set-current-error-port (cdr child->parent-pipe))
(while #t
(format #t "Line 1\n")
(format #t "Line 2\nLine 3\n")
(display "Done!\n")
(force-output)
(sleep 5)))
(child-pid ;parent
(close (cdr child->parent-pipe)) ;disconnect the write end of the pipe
(define port (car child->parent-pipe))
(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---
The output looks like this (non-deterministic it seems):
--8<---------------cut here---------------start------------->8---
$ guile repro.scm
Line 1
Line 2
Line 3
Done!
Line 1
Line 2
Line 3
Done!
Line 1
Line 1
Line 1
[...]
--8<---------------cut here---------------end--------------->8---
And strace shows that more than a single line is buffered on each
read-line, but that it only returns the first line of such buffered
input:
--8<---------------cut here---------------start------------->8---
read(8, 0x7fcd06bfc020, 4096) = -1 EAGAIN (Resource temporarily
unavailable)
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
select(9, [3 8], [], [], NULL) = 1 (in [8])
read(8, "Line 1\nLine 2\nLine 3\nDone!\n", 4096) = 27
write(1, "Line 1", 6Line 1) = 6
write(1, "\n", 1
) = 1
read(8, 0x7fcd06bfc020, 4096) = -1 EAGAIN (Resource temporarily
unavailable)
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
select(9, [3 8], [], [], NULL) = 1 (in [8])
read(8, "Line 1\nLine 2\nLine 3\nDone!\n", 4096) = 27
write(1, "Line 1", 6Line 1) = 6
write(1, "\n", 1
) = 1
[...]
--8<---------------cut here---------------end--------------->8---
Bug? PEBCAK? I'm interested to know :-).
Thanks,
Maxim
- Lost input when using suspendable read-line,
Maxim Cournoyer <=