[racket] design and use of continuation barriers

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Sun Jul 11 10:06:52 EDT 2010

At Sat, 10 Jul 2010 20:45:29 +0000, Taylor R Campbell wrote:
>       Using `dynamic-wind' turns out not to be enough if you have with
>       multiple threads:
>             (GUI)         (...)    (...)
>               |             |        |
>          (button push)     (B)      (C)
>               |
>              (A)
>       A `dynamic-wind' post-thunk there could prevent applying the
>       continuation `B' at `A', so you won't lose the GUI loop. For
>       applying `A' at `B', however, a guard in a `dynamic-wind' pre-thunk
>       may be too late; the GUI loop would be duplicated before the
>       pre-thunk could complain.
> I don't understand this last clause, that the GUI loop would be
> duplicated before the pre-thunk could complain.  Are you worried that
> throwing into A will trigger DYNAMIC-WIND entrance procedures up in
> the `(GUI)' frames that shouldn't be run more than once?  If so, can't
> those detect being run more than once and signal an error, as you
> suggested below in the setup code?

If GUI has `dynamic-wind's inside, it seems more likely that it could
deal with restarts --- or, yes, at least detect and prevent them.

I was more concerned with what happens when the pre-thunk at `A'
discovers a problem. If it raises an exception at that point, then the
GUI will see the escape and may attempt clean-up actions that crash. I
guess "too late" in this case is tied up with my view that libraries
often will include escape-handling code without restart-handling code
(and that it should be ok for them to be written that way).

>    To help library implementers, a continuation barrier is installed just
>    before before an exception handler is called. That way, if it is
>    possible for an exception to be raised, the implementer of `L-1' and
>    `L-2' can just use `with-handlers' to clean up, instead of having to
>    worry about jumps into the library.
> Can you be more specific about where continuation barriers are placed?
> I just tried jumping about inside and outside handled extents and the
> handlers themselves, and didn't hit any continuation barriers:
> ((call-with-current-continuation
>   (lambda (outside)
>     (lambda ()
>       (with-handlers
>           ((continuation?
>             (lambda (inside)
>               ((call-with-current-continuation
>                 (lambda (handler)
>                   (outside
>                    (lambda ()
>                      (handler
>                       (lambda () (inside (lambda () 0))))))))))))
>         (list 1 ((call-with-current-continuation raise))))))))
> ;Value: (1 0)

The `with-handlers' form escapes before applying a handler procedure.

To install an exception handler that is called in the dynamic extent of
`raise', use `call-with-exception-handler'.

>    I've just pushed a change to Racket to use the "rnrs" trick
>    internally. Since the trick is implemented within the run-time system,
>    it can also hide the continuation-mark difference. In fact, given the
>    continuation machinery that we developed a couple of years ago, the
>    change was pretty easy; I just hadn't thought about it enough.
> So can full continuations now be used to exit across continuation
> barriers just like exit-only continuations and prompt aborts,


Posted on the users mailing list.