[racket] design and use of continuation barriers
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,
Yes.