[squeak-dev] The Inbox: Kernel-jar.1376.mcz

Eliot Miranda eliot.miranda at gmail.com
Sun Feb 28 23:35:16 UTC 2021


Hi Jaromir,

On Sun, Feb 28, 2021 at 11:08 AM Jaromir Matas <m at jaromir.net> wrote:

> Hi, the following example shows a slight inconsistency in the process
> terminantion logic:
>
>    p := Process forContext: ([] asContextWithSender: thisContext) priority:
> 40
>
>    p isTerminated   --> false
>
>    p terminate
>
>    p isTerminated   --> false
>
>
> I'm aware the example is nonsensical but I guess the terminate =>
> isTerminated logic should be followed anyway.
>
> I propose the following change in the #isTerminated condition. The idea is
> if suspendedContext is the bottomContext and pc >= endPC then it should be
> considered terminated regardless of whether there is or isn't a closure.
> The
> rest of the condition remains intact. All tests green.
>
> I also suggest a new wording of the comment (the bottomContext block
> doesn't
> necessarily need to be the block in BlockClosure>>newProcess so I removed
> the note).
>
> The suggested version:
>
> isTerminated
>         "Answer if the receiver is terminated, or at least terminating."
>         self isActiveProcess ifTrue: [^ false].
>         ^suspendedContext isNil
>           or: ["If the suspendedContext is the bottomContext and the pc is
> at the endPC,
>                 then there is nothing more to do."
>                 suspendedContext isBottomContext
>                 and: [suspendedContext pc >= suspendedContext endPC
>                                 or: [suspendedContext closure
>                                                 ifNil: [suspendedContext
> methodClass == Process
>                                                         and:
> [suspendedContext selector == #terminate]]
>                                                 ifNotNil: [false]]]]
>
>
>
I like this.  But isn't this a little bit better?

isTerminated
"Answer if the receiver is terminated, or at least terminating."
self isActiveProcess ifTrue: [^ false].
^suspendedContext isNil
 or: ["If the suspendedContext is the bottomContext and the pc is at the
endPC,
then there is nothing more to do."
suspendedContext isBottomContext
and: [suspendedContext pc >= suspendedContext endPC
or: [suspendedContext closure isNil
and: [suspendedContext methodClass == Process
and: [suspendedContext selector == #terminate]]]]]
I'm also tempted to state in a comment why being in other than a block in
Process>>#terminate implies the methods is essentially done terminating.
And there in lies the rub, to quote Shakespeare.  Would a hack like
adding a first temporary in Process>>#terminate called e.g.
terminationStatus and having Process>>terminate assign to it when
termination is essentially complete be better?

e.g.

isTerminated
"Answer if the receiver is terminated, or at least terminating."
self isActiveProcess ifTrue: [^ false].
^suspendedContext isNil
  or: ["If the suspendedContext is the bottomContext and the pc is at the
endPC,
then there is nothing more to do."
suspendedContext isBottomContext
and: [suspendedContext pc >= suspendedContext endPC
or: [suspendedContext closure isNil
and: [suspendedContext methodClass == Process
and: [suspendedContext selector == #terminate
and: [(suspendedContext localAt: 1) == #terminated]]]]]]


terminate
"Stop the process that the receiver represents forever.
Unwind to execute pending ensure:/ifCurtailed: blocks before terminating.
If the process is in the middle of a critical: critical section, release it
properly.
 N.B. terminationStatus is for the benefit of Process>>#isTerminated."

| terminationStatus ctxt unwindBlock oldList |
self isActiveProcess ifTrue:
[ctxt := thisContext.
[ctxt := ctxt findNextUnwindContextUpTo: nil.
 ctxt ~~ nil] whileTrue:
[(ctxt tempAt: 2) ifNil:
["N.B. Unlike Context>>unwindTo: we do not set complete (tempAt: 2) to
true."
unwindBlock := ctxt tempAt: 1.
thisContext terminateTo: ctxt.
unwindBlock value]].
>>> terminationStatus := #terminated.
thisContext terminateTo: nil.
self suspend.
"If the process is resumed this will provoke a cannotReturn: error.
Would self debug: thisContext title: 'Resuming a terminated process' be
better?"
^self].

"Always suspend the process first so it doesn't accidentally get woken up.
N.B. If oldList is a LinkedList then the process is runnable. If it is a
Semaphore/Mutex et al
then the process is blocked, and if it is nil then the process is already
suspended."
oldList := self suspend.
suspendedContext ifNotNil:
["Release any method marked with the <criticalSection> pragma.
 The argument is whether the process is runnable."
self releaseCriticalSection: (oldList isNil or: [oldList class ==
LinkedList]).

"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]].

>>> terminationStatus := #terminated.
ctxt := self popTo: suspendedContext bottomContext.
ctxt == suspendedContext bottomContext ifFalse:
[self debug: ctxt title: 'Unwind error during termination'].
"Set the context to its endPC for the benefit of isTerminated."
ctxt pc: ctxt endPC]

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

_,,,^..^,,,_
best, Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20210228/245d31da/attachment.html>


More information about the Squeak-dev mailing list