[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Continuations in custom port: "cannot invoke continuation from this cont

From: Caleb Ristvedt
Subject: Continuations in custom port: "cannot invoke continuation from this context"
Date: Wed, 27 Mar 2019 23:30:01 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux)

I have a procedure that writes to an output port, a procedure that reads
from an input port, and some processing that I want to do in between. So
I figured that I'd try my hand at using continuations to write a custom
input/output port that would hook the two procedures together. The idea
is that I would give it two initial procedures, one for writing, one for
reading, and the read! and write! procedures would remember what the
latest read/write parameters were and read from / write to the
corresponding bytevectors, switching to the other procedure if there
wasn't a bytevector associated with that side. From what I've heard,
it's basically coroutining.

But I eventually (turns out exceptions in custom ports get silently
swallowed and turned into an attempt to close the port) discovered that
I was getting the error "cannot invoke continuations from this
context". The control flow went like this:

1. writer
2. write!
3. reader
4. read!
5. write!
6. writer
7. write!
8. exception when trying to go to read!

So clearly invoking the write continuation to get from 4 to 5 worked,
but invoking the read continuation to get from 7 to 8 didn't. That
sounds like something I read while looking at delimited continuations:

"... This is because composing a saved continuation with the current
continuation involves relocating the stack frames that were saved from
the old stack onto a (possibly) new position on the new stack, and Guile
can only do this for stack frames that it created for Scheme code, not
stack frames created by the C compiler"

I was under the impression this restriction only held for delimited
continuations, but in case I was wrong, I ran

(use-modules (ice-9 suspendable-ports))

and it continued to fail.

Here is the code I've been using, in all its hideous glory:

(use-modules (ice-9 suspendable-ports))
(use-modules (rnrs io ports))
(use-modules (ice-9 textual-ports))
(use-modules (rnrs bytevectors))

(let* ((the-pipe #f)
       (write-cont (lambda () (format the-pipe "Hello, world!~%")))
       (read-cont (lambda () (write (get-line the-pipe))))
       (read-bv #f)
       (read-len 0)
       (read-off 0)
       (write-bv #f)
       (write-len 0)
       (write-off 0))
  (set! the-pipe (make-custom-binary-input/output-port
                  ;; read!
                  (lambda (bv index len)
                    (catch #t
                      (lambda ()
                        (format #t "Reading ~A bytes~%" len)
                        (format #t "write-len: ~A write-off: ~A write-bv: ~A~%"
                                write-len write-off write-bv)
                        ;; Stored data?
                        (if (> write-len len)
                            ;; Write it, return to reader
                              (format #t "Read ~A bytes, return to reader.~%" 
                              (bytevector-copy! write-bv write-off bv index len)
                              (set! write-off (+ write-off len))
                              (set! write-len (- write-len len))
                            ;; Write it, return to writer
                              (format #t "Read ~A bytes, return to writer.~%"
                              (when (> write-len 0)
                                (bytevector-copy! write-bv write-off bv index
                              (set! read-bv bv)
                              (set! read-off (+ index write-len))
                              (set! read-len (- len write-len))
                               (lambda (c)
                                 (set! read-cont c)
                              (format #t "RETURN FROM READ!~%")
                      (lambda args
                        (format #t "EXCEPTION IN READ: ~A~%" args))))
                  ;; write!
                  (lambda (bv index len)
                    (catch #t
                      (lambda ()
                        (format #t "Writing ~A bytes~%" len)
                        (format #t "read-len: ~A read-off: ~A~%"
                                read-len read-off)
                        (if (> read-len len)
                            ;; Write it, return to writer
                              (format #t "Wrote ~A bytes, return to writer.~%"
                              (bytevector-copy! bv index read-bv read-off len)
                              (set! read-off (+ read-off len))
                              (set! read-len (- read-len len))
                            ;; Write it, return to reader
                              (format #t "Wrote ~A bytes, return to reader.~%"
                              (when (> read-len 0)
                                (bytevector-copy! bv index read-bv read-off 
                              (set! write-bv bv)
                              (set! write-off (+ index read-len))
                              (set! write-len (- len read-len))
                               (lambda (c)
                                 (set! write-cont c)
                              (format #t "RETURN FROM WRITE!~%")
                      (lambda args
                        (format #t "EXCEPTION IN WRITE: ~A~%" args))))
                  ;; get-position
                  (lambda ()
                    (format #t "Tried getting pos~%"))
                  ;; set-position!
                  (lambda (pos)
                    (format #t "Tried setting pos~%"))
                  ;; close
                  (lambda ()
                    (format #t "Tried closing~%"))))
  (setvbuf the-pipe 'none)
  (format #t "DONE WRITING!~%")

But just now I noticed that if I change the reader from

(get-line the-pipe)



it gets as far as the "DONE WRITING" message and then produces the same
"cannot invoke continuation from this context" error.

Any idea what's going wrong here?


- reepca

reply via email to

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