<div dir="ltr"><div dir="ltr"><div class="gmail_default" style="font-size:small">Hi All, Hi Christoph, Levente, Jaromir, Vanessa,</div></div><div><br></div><div class="gmail_default" style="font-size:small">find attached an improved implementation of copying the stack of an exception caught within a critical section stack for resignaling outside of a critical section.  The improvement and main issue here is avoiding running unwinds more than once.  Since the stack is copied, unwinds may be effectively run again if unwound in the copied stack. This implementation allows that to be avoided if desired.  Please review if you have time.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">Here's the motivating example; actually an extract of the comment in Exception >> copyForReraiseTo:disableUnwinds:.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small">              | home error |<br>                home := thisContext.<br>          Semaphore forMutualExclusion critical:<br>    [[nil new]<br>        on: Error<br>        do: [:ex| error := ex copyForReraiseTo: home disableUnwinds: true]].<br>             error reraise<br><br>        Once the exception has been copied, on:do: will run unwinds and answer the error<br>      as the result of the [nil new] on:...do:... expression. In doing so it will run the ensure:<br>   block inside Semaphore>>critical: and the semaphore will get back its one excess<br>        signal.  It is therefore essential that the copy of this unwind in the copied exception's<br>        stack is not run again, otherwise the semaphore will end up with two excess signals.<br>  This is why unwinds can be disabled in the copy.<br><br>    It is important to understand why we disable unwinds.  Proceeding is clearly<br>         dangerous; we might re-enter code in a critical section, and do something<br>     untoward. The only safe thing to do is close the debugger, or return a value to<br>       the sender.  But if we close the debugger unwinds will be run and we *must not*<br>      run unwinds twice.<br></div><div class="gmail_default" style="font-size:small"></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Dec 14, 2021 at 5:36 PM Eliot Miranda <<a href="mailto:eliot.miranda@gmail.com">eliot.miranda@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div style="font-size:small">Hi All, Hi Levente, Jaromir, and Context hackers,</div><div style="font-size:small"><br></div><div style="font-size:small">    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.</div><div style="font-size:small"><br></div><div style="font-size:small">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.</div><div style="font-size:small"><br></div><div style="font-size:small">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).</div><div style="font-size:small"><br></div><div style="font-size:small">Here's an example usage:</div><div style="font-size:small"><br></div><div style="font-size:small">    | sender error |<br>    sender := thisContext sender.<br>    Mutex new critical:<br>        [[nil new]<br>            on: Error<br>            do: [:ex| error := ex copyForReraiseTo: sender]].<br>    error reraiseFrom: thisContext<br></div><div style="font-size:small"><br></div><div style="font-size:small">A simpler usage would be</div><div style="font-size:small"><br></div><div style="font-size:small">    | home error |<br>    home := thisContext.<br>    Mutex new critical:<br>        [[nil new]<br>            on: Error<br>            do: [:ex| error := ex copyForReraiseTo: home]].<br>    error outer<br></div><div style="font-size:small"><br></div><div style="font-size:small">This doesn't work because ProcessorScheduler>>#debugContext:title:full:contents: (et al) contains</div><div style="font-size:small"><br></div><div style="font-size:small">    self assert: [thisContext hasSender: aContext]</div><div style="font-size:small"><br></div><div style="font-size:small">and hence we have to stitch the copied stack into the current stack via</div><div style="font-size:small"><br></div><div style="font-size:small">    aContext privSender: signalContext.</div>  <span class="gmail_default" style="font-size:small">    </span>thisContext privSender: aContext.<br>    <span class="gmail_default" style="font-size:small">    </span>self outer<div><br></div><div><div style="font-size:small">inside Exception>>reraiseFrom: aContext</div><div><br></div><div style="font-size:small">Maybe adding a flag to Exception and avoiding that assert when the exception is "in reraise mode" is better.  I don't know.</div><div style="font-size:small"><br></div><div style="font-size:small"><br></div><div style="font-size:small">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.:</div><div style="font-size:small"><br></div><div style="font-size:small">Context>>copyTo: aContext<br></div><div style="font-size:small">    ^self copyTo: aContext</div><div style="font-size:small">            atEachStep:</div><div style="font-size:small">                [:originalContext :copiedContext|</div><div style="font-size:small">                originalContext sender == aContext ifTrue:</div><div style="font-size:small">                    [copiedContext privSender: nil]]</div><div style="font-size:small"><br></div><div style="font-size:small"><div>Context>>copyTo: aContext bottomContextDo: aBlock<br></div><div>    ^self copyTo: aContext</div><div>            atEachStep:</div><div>                [:originalContext :copiedContext|</div><div>                originalContext sender == aContext ifTrue:</div><div>                    [copiedContext privSender: nil.</div><div>                    aBlock value: copiedContext]]</div><div><br></div><br></div><div><div dir="ltr"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div></div></div></div>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div></div>