[Cuis-dev] Unwind mechanism during termination is broken and inconsistent
Juan Vuletich
juan at jvuletich.org
Fri Jun 4 06:43:24 PDT 2021
Hi Jaromir,
I've just pushed your latest to GitHub. I included a note with links to
this email thread in #terminate. I also added the new tests; and your
examples as a class method in Process, for future reference.
This is an important piece of work. Thanks a lot!
Cheers,
--
Juan Vuletich
www.cuis-smalltalk.org
https://github.com/Cuis-Smalltalk/Cuis-Smalltalk-Dev
https://github.com/jvuletich
https://www.linkedin.com/in/juan-vuletich-75611b3
@JuanVuletich
On 6/1/2021 9:09 AM, Jaromir Matas via Cuis-dev wrote:
>
> Hi Juan,
>
> I’m enclosing a finalized version of #terminate with the following
> changes:
>
> 1) whole termination code wrapped in #valueEnsured as suggested in the
> previous message
>
> 2) changed approach to BlockCannotReturn: error and adopted Christoph
> Thiede’s solution allowing the debugger to Proceed from the error to
> the sender of the failing non-local return. It makes sense in the
> debugger to leave all choices open for the user – Proceeding means
> ignoring the failed non-local return but why not - it could have been
> a typo after all :) So I’m taking back my suggestion to disable the
> Proceed button during unwinding – too restrictive. This change allows
> for debugging examples like:
>
> [^2] fork
>
> Or even:
>
> [[self error] ensure: [^2]] fork
>
> Previously these would crash the image.
>
> To make this work with #terminate and notify the user I added a
> ProceedBlockCannotReturn warning.
>
> 3) #complete:to: is a helper method to improve readability of
> #terminte and also to deal with two special exceptions:
> BlockCannotReturn and MessageNotUnderstood. The latter exception was
> purposely written to allow for writing methods while debugging which
> introduced a potential for an infinite recursion I had to deal with
> (see notes in #complete:to: )
>
> 4) I’ve also integrated a fix to a stepOver bug in this example:
>
> [^2] ensure: [Transcript show: 'done']
>
> If you step through and then step over ^2 you get a BlockCannotReturn
> error – that’s a bug
>
> The problem is #return:from: supplies the first unwind context to
> #aboutToReturn:through: but this first unwind context was determined
> before the debugger inserted an #ensure context during the stepover
> simulation. My fix is to supply nil and let #resume:through: find the
> first unwind context at the right moment.
>
> This fix modifies #resume:through: and #return:from: methods only and
> is independent of the #teminate suite.
>
> Please let me know if you find any inconsistencies… I hope not ;)
>
> My best regards,
>
> Jaromir
>
> *From: *Jaromir Matas via Cuis-dev <mailto:cuis-dev at lists.cuis.st>
> *Sent: *Tuesday, May 25, 2021 9:32
> *To: *Juan Vuletich <mailto:juan at jvuletich.org>;
> cuis-dev at lists.cuis.st <mailto:cuis-dev at lists.cuis.st>
> *Cc: *Jaromir Matas <mailto:mail at jaromir.net>
> *Subject: *Re: [Cuis-dev] Unwind mechanism during termination is
> broken and inconsistent
>
> Hi Juan,
>
> I’ve explored a scenario when you are terminating a process, i.e.
> unwinding it’s ensure etc contexts and in the middle of it the process
> running the unwinds gets interrupted and terminated. In such case this
> process unwinds its stack and terminates but the original process is
> just left hanging as a suspended process (potentially indefinitely) or
> as a chain of contexts that get garbage collected eventually.
>
> With the new terminate there’s an elegant solution to this scenario:
> wrap the whole termination code in #valueEnsured and the intruding
> process will correctly unwind both the original and the terminator
> process :) I’ve enclosed a test and modified #terminate only. Please
> take a look, I can’t see anything wrong with this approach.
>
> Best regards,
>
> Jaromir
>
> *From: *Jaromir Matas <mailto:mail at jaromir.net>
> *Sent: *Sunday, May 23, 2021 19:10
> *To: *Juan Vuletich <mailto:juan at jvuletich.org>;
> cuis-dev at lists.cuis.st <mailto:cuis-dev at lists.cuis.st>
> *Subject: *FW: [Cuis-dev] Unwind mechanism during termination is
> broken and inconsistent
>
> Hi Juan,
>
> I'm enclosing a test covering a situation where the top context itself
> is an unwind context. The test explores three scenarios based on the
> position where the execution was suspended: before entering the unwind
> block, right after setting complete := true but before executing the
> unwind block and after returning from the unwind block. #terminate
> should execute the unwind block in the first two cases but not in the
> last one.
>
> Squeak has a convenient method Process>>#forBlock:runUntil: to step
> right into the desired position. So I just inlined its code into the
> test to make it work the same way :)
>
> Regarding the tests demonstrating the unwind behavior in case of
> unhandled errors and subsequent Abandoning or Proceeding the debugger
> - it looks like Squeak has a machinery to do that (debugger tests) but
> I can't see anything similar in Cuis that would simulate opening and
> abandoning a debugger... Any advice?
>
> Many thanks for all your feedback,
>
> Best regards,
>
> Jaromir
>
> PS: Yesterday my message bounced back due to it’s size, I’m forwarding
> it again and trimming history.
>
> *From: *Jaromir Matas <mailto:mail at jaromir.net>
> *Sent: *Saturday, May 22, 2021 23:16
> *To: *Juan Vuletich <mailto:juan at jvuletich.org>; Discussion of Cuis
> Smalltalk <mailto:cuis-dev at lists.cuis.st>
> *Subject: *RE: [Cuis-dev] Unwind mechanism during termination is
> broken and inconsistent
>
> Hi Juan,
>
> Many thanks for your feedback.
>
> I've made some final changes to the changeset:
>
> 1) extracted a repeating code to a method called Process>>complete:to:
> which calls #runUnwindUntilErrorOrReturnFrom: and deals with potential
> infinite loops caused by some errors.
>
> 2) as a result the unwind code pattern used in #terminate is almost
> identical to the one in #resume:through: - which I think is better for
> readability - when people can recognize a pattern right away :)
>
> 3) adjusted the part searching for the outer-most unwind context to
> catch even the top context if it's an unwind context.
>
> 4) In order to rein in the infinite loops or crashes caused by the
> BlockCannotReturn error I added a local variable isRecursive to
> BlockCannotReturn exception to be able to deal with a starting
> infinite loop. This is an example brought to my attention Christoph
> Thiede:
>
> ```
>
> "Both statements need to be executed separately in a Workspace"
>
> a := [true ifTrue: [^ 1] yourself]
>
> [a value] on: BlockCannotReturn do: [:ex | ex resume]
>
> ```
>
> With the proposed fix there's no need to change the isResumable
> setting of the BlockCannotReturn I suggested previously. Resuming
> doesn't hurt any longer :)
>
> Regarding my suggestion to disable the Proceed button when debugging
> an error that happened during unwind - I'm no longer so sure it's a
> good idea to limit the freedom of the user in such a border situation
> like debugging an unwind error :) I suggest to leave it open, "use at
> your own risk" type of thing, for the moment.
>
> > I think you are right in the previous email, and we'd integrate your
> latest change.I have already checked that none of the tests we
> recently added breaks because of it. If you could turn some of the
> arguments you provide into tests, it would be great.
>
> I must admit I still haven't learned to build tests involving errors
> etc. :) But at least I updated and enclosed the list of examples that
> can be used as test scenarios and added some more extreme ones.
>
> Juan, please review the enclosed changeset and let me know if you find
> something suspicious. Please feel free to change any names I picked or
> do any changes you find useful.
>
> Best regards,
>
> Jaromir
>
> *From: *Juan Vuletich <mailto:juan at jvuletich.org>
> *Sent: *Friday, May 21, 2021 21:08
> *To: *Discussion of Cuis Smalltalk <mailto:cuis-dev at lists.cuis.st>
> *Cc: *Jaromir Matas <mailto:mail at jaromir.net>; Hernan Wilkinson
> <mailto:hernan.wilkinson at 10pines.com>
> *Subject: *Re: [Cuis-dev] Unwind mechanism during termination is
> broken and inconsistent
>
> Hi Jaromir,
>
> On 5/16/2021 5:26 PM, Jaromir Matas via Cuis-dev wrote:
>
> Hi Juan,
>
> I'm enclosing an updated changeset (please disregard the previous
> one); I made a stupid assumption about
> #runUntilErrorOrReturnFrom:. The new changeset leaves it untouched
> and adds its replica called #runUnwindUntilErrorOrReturnFrom: with
> the required functionality.
>
>
> I think you are right in the previous email, and we'd integrate your
> latest change.I have already checked that none of the tests we
> recently added breaks because of it. If you could turn some of the
> arguments you provide into tests, it would be great.
>
> I'd like to point out a little issue with the proposed semantics
> of nested errors during termination:
>
> Below’s a simple example. If you abandon the first debugger it
> means you want to terminate the execution and unwind the
> terminated process but an error happens during the unwind. You get
> another debugger reporting the error and asking you what to do
> next - to debug the error or proceed. But proceeding a termination
> really means to proceed with the **unwind business only** and not
> to proceed with the original computation. Here's my point: Hitting
> Proceed will resume the original computation beyond the unwind
> blocks but Abandon will only finish the unwind procedure which is
> exactly what we want. In Squeak I simply disabled the Proceed
> button but in Cuis I couldn't see such a simple solution so I left
> it unresolved.
>
> [self error: 'x1'] ensure: [
>
> [self error: 'x2'] ensure: [
>
> Transcript show: '2'].
>
> Transcript show: '1'].
>
> Transcript show: '0'
>
> ---> you want to see '21' but proceeding the debugger will give
> you '210' where '0' is printed outside of unwind blocks.
>
> So just that you know there's still a little inconsistency in the
> termination semantics.
>
>
> I see. The issue is how to disable a button so it doesn't act? The
> simplest way is by saying `aButton lock: true`. We could add #enable
> and #disable to PluggableButtonMorph (calling self lock: ). Or perhaps
> call it #isEnabled: like in MenuItemMorph, although it is an ugly
> name. Can you prepare a change set like this? That would be great. I
> mean, I don't know where those calls should be made!
>
> One more question: do you have an idea why BlockCannotReturn error
> is considered resumable? I'd say it's unresumable by definition…?
> Thanks :)
>
>
> Well, that method is pretty old, and in the mean time, exception
> handling has gotten a lot better, thanks to several batches of
> improvements, latter ones by you. So, please provide a patch to change
> that, so it properly carries your initials.
>
> best regards,
>
> Jaromir
>
>
> Thanks again Jaromir for this amazing work.
>
> Cheers,
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cuis.st/mailman/archives/cuis-dev/attachments/20210604/33592cf5/attachment-0001.htm>
More information about the Cuis-dev
mailing list