guile-user
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]