Another bug in Process>>#terminate in unwinding contexts ?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Another bug in Process>>#terminate in unwinding contexts ?

Jaromir Matas
Hi,
if you examine the following example you'll notice only the innermost unwind
context currently under evaluation will get completed during termination.
But the unwind contexts may be nested so I guess we should attempt
completing the outermost context rather than the innermost only.

| p |
p := [
[ ] ensure: [
        [ ] ensure: [Processor activeProcess suspend. Transcript show: 'x1'].
        Transcript show: 'x2']
] fork.
Processor yield.
p terminate

Expected output: x1 x2
Real output: x1
(`Processor activeProcess suspend` models a situation a process gets
suspended and then for whatever reason terminated)

This is the current implementation within #teminate:

                "If terminating a process halfways through an unwind, try to complete that
unwind block first."
                (suspendedContext findNextUnwindContextUpTo: nil) ifNotNil:
                        [:outer|
                         (suspendedContext findContextSuchThat:[:c| c closure == (outer tempAt:
1)]) ifNotNil:
                                [:inner| "This is an unwind block currently under evaluation"
                                 suspendedContext runUntilErrorOrReturnFrom: inner]].

I'm proposing this modification:

                "If terminating a process halfways through an unwind, try to complete that
unwind block first."
                ctxt := suspendedContext.
                [ctxt := ctxt findNextUnwindContextUpTo: nil.
                 ctxt ~~ nil] whileTrue:
                        [outerMost := ctxt].
                outerMost ifNotNil: ["This is the bottom-most unwind context currently
under evaluation;
                        now let's find the currently context executing its argument block
(tempAt: 1)"
                        (suspendedContext findContextSuchThat: [:c | c closure == (outerMost
tempAt: 1)]) ifNotNil:
                                [:inner | suspendedContext runUntilErrorOrReturnFrom: inner]].

Changeset:  Process-terminate_modify_outerMost.st
<http://forum.world.st/file/t372955/Process-terminate_modify_outerMost.st>  

Other bugs in terminate (and related):
[1]
http://forum.world.st/Bug-in-Process-gt-gt-terminate-Returning-from-unwind-contexts-td5127570.html
[2]
http://forum.world.st/The-Inbox-Kernel-jar-1376-mcz-td5127335.html#a5127372
[3]
http://forum.world.st/Refactoring-terminate-to-get-rid-of-cannot-return-errors-etc-td5127732.html
(The last is a part of my effort to refactor termination to at least deal
with the current bugs)





-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html

^[^ Jaromir
Reply | Threaded
Open this post in threaded view
|

Re: Another bug in Process>>#terminate in unwinding contexts ?

Jaromir Matas
Unfortunately there's one more bug in #terminate:

The existing code fails to execute unwind blocks after completing the
innermost unwind block. Examine the following example nesting two unwind
blocks halfway through execution and one outer unwind block not started yet:

| p |
p := [
        [
                [ ] ensure: ["x2"
                        [ ] ensure: ["x1"
                                Processor activeProcess suspend.
                                Transcript show: 'x1'].
                        Transcript show: 'x2']
        ] ensure: ["x3"
                Transcript show: 'x3']
] fork.
Processor yield.
p terminate

---> x1 (only!)

Process p is suspended halfway through an unwind block x1 and is terminated
- you'd expect #terminate to finish the unfinished unwind blocks x1 and x2
and execute an outer unwind block x3. But the result is only x1 is completed
and both x2 and x3 are ignored!

The reason x3 is ignored is that #runUntilErrorOrReturnFrom: resets
suspendedContext sender to nil so the rest of the code is doing nothing
useful. The fix is to update suspendedContext after
#runUntilErrorOrReturnFrom is returned from.

Process >> terminate
                "..."
                ctxt := suspendedContext.
                [ctxt := ctxt findNextUnwindContextUpTo: nil.
                 ctxt ~~ nil] whileTrue:
                        [(ctxt tempAt:2) ifNotNil: [outerMost := ctxt]].
                outerMost ifNotNil: ["This is the bottom-most unwind context currently
under evaluation;
                        now let's find the currently context executing its argument block
(tempAt: 1)"
                        (suspendedContext findContextSuchThat: [:c | c closure == (outerMost
tempAt: 1)]) ifNotNil:
                                [:inner |
                                        suspendedContext runUntilErrorOrReturnFrom: inner.
                                        "update suspendedContext"
                                        suspendedContext := outerMost]].
                "..."

Now the test example returns 'x1 x2 x3' as expected.

Updated changeset enclosed:  Process-terminate_modify_outerMost_v2.st
<http://forum.world.st/file/t372955/Process-terminate_modify_outerMost_v2.st>  

Thanks for your comments.



-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html

^[^ Jaromir