Hi All, Hi Levente, Jaromir, and Context hackers,
find attached a change set which supports re-raising a fatal exception,
caught inside a critical section, outside the critical section. This is a
key facility for debugging systems such as Croquet. I expect it'll also be
useful in delimited continuation contexts such as Seaside. The facility is
closely related to Context>>copyTo: and Context>>copyTo:bottomContextDo:.
The main method is Exception>>copyForReraiseTo: aContext.
This implementation is higher quality than
Context>>copyTo:[bottomContextDo:]. It copies the stack and it also copies
blocks that are created on the copied stack. So the copied stack
correctly copies blocks, and hence exception handlers.
I'm thinking of adding this to trunk. I would like it to be reviewed
carefully before I do so. Both implementation and selector names need
reviewing, and tests and more use cases would be nice (I have a use case in
Virtend/Croquet).
Here's an example usage:
| sender error |
sender := thisContext sender.
Mutex new critical:
[[nil new]
on: Error
do: [:ex| error := ex copyForReraiseTo: sender]].
error reraiseFrom: thisContext
A simpler usage would be
| home error |
home := thisContext.
Mutex new critical:
[[nil new]
on: Error
do: [:ex| error := ex copyForReraiseTo: home]].
error outer
This doesn't
work because ProcessorScheduler>>#debugContext:title:full:contents: (et al)
contains
self assert: [thisContext hasSender: aContext]
and hence we have to stitch the copied stack into the current stack via
aContext privSender: signalContext.
thisContext privSender: aContext.
self outer
inside Exception>>reraiseFrom: aContext
Maybe adding a flag to Exception and avoiding that assert when the
exception is "in reraise mode" is better. I don't know.
Given that the main worker method, Context>>#copyTo:atEachStep:, is better
than Context>>copyTo:[bottomContextDo:]., these two could be reimplemented
in terms of it, e.g.:
Context>>copyTo: aContext
^self copyTo: aContext
atEachStep:
[:originalContext :copiedContext|
originalContext sender == aContext ifTrue:
[copiedContext privSender: nil]]
Context>>copyTo: aContext bottomContextDo: aBlock
^self copyTo: aContext
atEachStep:
[:originalContext :copiedContext|
originalContext sender == aContext ifTrue:
[copiedContext privSender: nil.
aBlock value: copiedContext]]
_,,,^..^,,,_
best, Eliot