<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:"Calibri Light";
        panose-1:2 15 3 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
p.MsoNoSpacing, li.MsoNoSpacing, div.MsoNoSpacing
        {mso-style-priority:1;
        margin:0in;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
.MsoChpDefault
        {mso-style-type:export-only;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style>
</head>
<body lang="EN-US" link="blue" vlink="#954F72" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal">Hi Eliot,</p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I've recently discovered a bug in the Debugger causing your code for #reraise to crash the VM. Your code was ok all along, sorry for any confusion I may have caused. The Debugger fix is in Tools-jar.1189 in the Inbox.</p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Next, I realized you don't need a special #reraise method; you can run your scenario using #resignalAs: which will do the stitching for you. Your motivation example would look like:</p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">| home error |</p>
<p class="MsoNormal">home := thisContext.</p>
<p class="MsoNormal">Semaphore forMutualExclusion critical:</p>
<p class="MsoNormal">    [[nil new]</p>
<p class="MsoNormal">        on: Error</p>
<p class="MsoNormal">        do: [:ex| error := ex copyForReraiseTo: home disableUnwinds: true]].</p>
<p class="MsoNormal">error resignalAs: Error</p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I'm enclosing a fix for Context>>resumeEvaluating: I intend to post soon; the current version of resumeEvaluating: is unnecessarily duplicating the unwind algorithm and for some reason, in your example, cuts the stack in the Debugger under
 the Doit context. The enclosed fix works as expected.</p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">And lastly, I'm enclosing a correction of your #doStackCopyForReraiseTo:disableUnwinds: method; you haven't used the disableUnwindsBoolean argument.</p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Best,</p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Jaromir</p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNoSpacing"><span lang="CS">--</span></p>
<p class="MsoNoSpacing"><strong><span style="font-family:"Calibri Light",sans-serif;color:#333333;font-weight:normal">Jaromír Matas</span></strong><span style="font-family:"Calibri Light",sans-serif;color:#555555"><o:p></o:p></span></p>
<p class="MsoNoSpacing"><span style="font-family:"Calibri Light",sans-serif;color:#2E75B6">mail@jaromir.net<o:p></o:p></span></p>
<p class="MsoNormal"><span style="color:#8FAADC"><o:p> </o:p></span></p>
<p class="MsoNormal"><o:p> </o:p></p>
<div style="mso-element:para-border-div;border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal" style="border:none;padding:0in"><b>From: </b><a href="mailto:mail@jaromir.net">mail@jaromir.net</a><br>
<b>Sent: </b>Saturday, December 18, 2021 23:16<br>
<b>To: </b><a href="mailto:squeak-dev@lists.squeakfoundation.org">squeak-dev@lists.squeakfoundation.org</a>;
<a href="mailto:eliot.miranda@gmail.com">eliot.miranda@gmail.com</a><br>
<b>Subject: </b>Re: [squeak-dev] Exception reraise (needs review) [was Exception reraiseFrom: (needs review)]</p>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal" style="margin-bottom:12.0pt">Hi Eliot,<br>
<br>
I'd like to share some observations:<br>
<br>
(1)<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.<br>
<br>
I'm not sure I understand: #on:do: will certainly run unwinds but the ensure block [self signal] inside #critical: is below on:do: (meaning deeper); so my understanding is the ensure block is run normally after on:do: returns and not as an unwind during on:do:'s
 return. Not that it changes anything, just either the comment is incorrect or I am :) The semaphore recharges in any case and when the exception is reraised the ensure block's 'complete' variable is already set true so it won't evaluate again as desired.<br>
<br>
> 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>
<br>
Yes, closing the debugger would execute the ensure block when unwinding; I hope I understand the terminology though: unwind is the procedure during returns when the ensure blocks on the stack are identified and executed outside "normal linear flow of the computation";
 otherwise, when the ensure block is executed normally it wouldn't be called unwinding, right?<br>
<br>
(2)<br>
I tried debugging the motivation example:<br>
<br>
| 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>
When you step over, until #reraise and then step into #reraise and in and in again you get 'endIndex is out of bounds' error (in #postCopyFrom:to:). What's worse though is when you continue debugging (stepping) then in some cases the image irreparably crashes.
 I can't figure out why and can't see any pattern... Sometimes it just freezes beyond CMD+dot repair, or a grey screen appears or even some weird looking grey windows with scary titles start popping-up :) The only way to get rid of it is to kill it in the OS.
 The described sequence (stepOver 3 times, stepIn 3 times is just the fastest way to show the error; it can be replicated many other ways).<br>
<br>
(3)<br>
> Maybe adding a flag to Exception and avoiding that assert when the<br>
> exception is "in reraise mode" is better.  I don't know.<br>
<br>
yes, I tried; it works but the crashing while debugging was even worse...<br>
<br>
One last question: when you copy the stack fragment, you create a simple tree with the two branches sharing the same context you call 'home'. The original branch returns to 'home' and sends #reraise and the copied stack branch is then run - my question is:
 Does it matter that the copied branch will eventually return to a different pc position in the 'home' method than it's original version? I guess not but I'm not sure.<br>
<br>
Thanks for sharing this code, very interesting stuff to study!<br>
Best,<br>
<br>
<br>
<br>
~~~<br>
^[^    Jaromir<br>
<br>
Sent from Squeak Inbox Talk<br>
<br>
On 2021-12-15T11:10:49-08:00, eliot.miranda@gmail.com wrote:<br>
<br>
> Hi All, Hi Christoph, Levente, Jaromir, Vanessa,<br>
> <br>
> find attached an improved implementation of copying the stack of an<br>
> exception caught within a critical section stack for resignaling outside of<br>
> a critical section.  The improvement and main issue here is avoiding<br>
> running unwinds more than once.  Since the stack is copied, unwinds may be<br>
> effectively run again if unwound in the copied stack. This implementation<br>
> allows that to be avoided if desired.  Please review if you have time.<br>
> <br>
> Here's the motivating example; actually an extract of the comment<br>
> in Exception >> copyForReraiseTo:disableUnwinds:.<br>
> <br>
> | 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<br>
> error<br>
> as the result of the [nil new] on:...do:... expression. In doing so it will<br>
> run the ensure:<br>
> block inside Semaphore>>critical: and the semaphore will get back its one<br>
> excess<br>
> signal.  It is therefore essential that the copy of this unwind in the<br>
> copied exception's<br>
> stack is not run again, otherwise the semaphore will end up with two excess<br>
> 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<br>
> value to<br>
> the sender.  But if we close the debugger unwinds will be run and we *must<br>
> not*<br>
> run unwinds twice.<br>
> <br>
> On Tue, Dec 14, 2021 at 5:36 PM Eliot Miranda <eliot.miranda at gmail.com><br>
> wrote:<br>
> <br>
> > Hi All, Hi Levente, Jaromir, and Context hackers,<br>
> ><br>
> >     find attached a change set which supports re-raising a fatal<br>
> > exception, caught inside a critical section, outside the critical section.<br>
> > This is a key facility for debugging systems such as Croquet.  I expect<br>
> > it'll also be useful in delimited continuation contexts such as Seaside.<br>
> > The facility is closely related to Context>>copyTo: and<br>
> > Context>>copyTo:bottomContextDo:.  The main method is<br>
> > Exception>>copyForReraiseTo: aContext.<br>
> ><br>
> > This implementation is higher quality than<br>
> > Context>>copyTo:[bottomContextDo:].  It copies the stack and it also copies<br>
> > blocks that are created on the copied stack.  So the copied stack<br>
> > correctly copies blocks, and hence exception handlers.<br>
> ><br>
> > I'm thinking of adding this to trunk.  I would like it to be reviewed<br>
> > carefully before I do so.  Both implementation and selector names need<br>
> > reviewing, and tests and more use cases would be nice (I have a use case in<br>
> > Virtend/Croquet).<br>
> ><br>
> > Here's an example usage:<br>
> ><br>
> >     | 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>
> ><br>
> > A simpler usage would be<br>
> ><br>
> >     | 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>
> ><br>
> > This doesn't<br>
> > work because ProcessorScheduler>>#debugContext:title:full:contents: (et al)<br>
> > contains<br>
> ><br>
> >     self assert: [thisContext hasSender: aContext]<br>
> ><br>
> > and hence we have to stitch the copied stack into the current stack via<br>
> ><br>
> >     aContext privSender: signalContext.<br>
> >    thisContext privSender: aContext.<br>
> >    self outer<br>
> ><br>
> > inside Exception>>reraiseFrom: aContext<br>
> ><br>
> > Maybe adding a flag to Exception and avoiding that assert when the<br>
> > exception is "in reraise mode" is better.  I don't know.<br>
> ><br>
> ><br>
> > Given that the main worker method, Context>>#copyTo:atEachStep:, is better<br>
> > than Context>>copyTo:[bottomContextDo:]., these two could be reimplemented<br>
> > in terms of it, e.g.:<br>
> ><br>
> > Context>>copyTo: aContext<br>
> >     ^self copyTo: aContext<br>
> >             atEachStep:<br>
> >                 [:originalContext :copiedContext|<br>
> >                 originalContext sender == aContext ifTrue:<br>
> >                     [copiedContext privSender: nil]]<br>
> ><br>
> > Context>>copyTo: aContext bottomContextDo: aBlock<br>
> >     ^self copyTo: aContext<br>
> >             atEachStep:<br>
> >                 [:originalContext :copiedContext|<br>
> >                 originalContext sender == aContext ifTrue:<br>
> >                     [copiedContext privSender: nil.<br>
> >                     aBlock value: copiedContext]]<br>
> ><br>
> ><br>
> > _,,,^..^,,,_<br>
> > best, Eliot<br>
> ><br>
> <br>
> <br>
> -- <br>
> _,,,^..^,,,_<br>
> best, Eliot<br>
> -------------- next part --------------<br>
> An HTML attachment was scrubbed...<br>
> URL: <<a href="http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20211215/ed08069f/attachment.html">http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20211215/ed08069f/attachment.html</a>><br>
> -------------- next part --------------<br>
> A non-text attachment was scrubbed...<br>
> Name: reraise-methods.st<br>
> Type: application/octet-stream<br>
> Size: 5244 bytes<br>
> Desc: not available<br>
> URL: <<a href="http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20211215/ed08069f/attachment.obj">http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20211215/ed08069f/attachment.obj</a>><br>
> <br>
> <o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
</body>
</html>