[squeak-dev] The Trunk: Kernel-eem.999.mcz

Eliot Miranda eliot.miranda at gmail.com
Sat Feb 20 03:00:11 UTC 2016


Hi Levente,

> On Feb 19, 2016, at 6:29 PM, Levente Uzonyi <leves at caesar.elte.hu> wrote:
> 
>> On Fri, 19 Feb 2016, commits at source.squeak.org wrote:
>> 
>> Eliot Miranda uploaded a new version of Kernel to project The Trunk:
>> http://source.squeak.org/trunk/Kernel-eem.999.mcz
>> 
>> ==================== Summary ====================
>> 
>> Name: Kernel-eem.999
>> Author: eem
>> Time: 18 February 2016, 11:03:09.008076 pm
>> UUID: 30222068-755f-4637-bbbb-6f775291e746
>> Ancestors: Kernel-bf.998
>> 
>> Fix isSuspended (my last commit was a regression; I had confused isSuspended with isBlocked).  Comment all the isFoo testing methods in process.  Add isBlocked.  Modify Process>>terminate to set the pc of the context of a process that is not auto-terminated to its endPC so that isTerminated and isSuspended can distinguish between processes either terminated or suspended.
>> 
>> =============== Diff against Kernel-bf.998 ===============
>> 
>> Item was added:
>> + ----- Method: Process>>isBlocked (in category 'testing') -----
>> + isBlocked
>> +    "A process is blocked if it is waiting on some list (i.e. a Semaphore), other than the runnable process lists."
>> +    | myPriority |
>> +    "Grab my prioirty now.  Even though evaluation is strictly right-to-left, accessing Processor could involve a send."
>> +    myPriority := priority.
>> +    ^myList
>> +        ifNil: [false]
>> +        ifNotNil: [:list| list ~~ (Processor waitingProcessesAt: myPriority)]!
> 
> The list variable seems unnecessary. myList should do it, because its value will be pushed onto the stack before it could be changed.

I'm being a bit over cautious here but I'm imagining that it's possible that deteferencing the global Processor might involve a send.  For example in the VW system global a are sent #value and with namespaces that might bind to a real method and hence be an interrupt point.

> 
>> 
>> Item was added:
>> + ----- Method: Process>>isRunnable (in category 'testing') -----
>> + isRunnable
>> +    "A process is runnable if it is the active process or is on one of the runnable process lists."
>> +    | myPriority |
>> +    "Grab my prioirty now.  Even though evaluation is strictly right-to-left, accessing Processor could involve a send."
>> +    myPriority := priority.
>> +    ^myList
>> +        ifNil: [^self == Processor activeProcess]
>> +        ifNotNil: [:list| list == (Processor waitingProcessesAt: myPriority)]!
> 
> Same as above.

Ditto :)
> 
>> 
>> Item was changed:
>> ----- Method: Process>>isSuspended (in category 'testing') -----
>> isSuspended
>> +    "A process is suspended if it has been suspended with the suspend primitive.
>> +     It is distinguishable from the active process and a terminated process by
>> +     having a non-nil suspendedContext that is either not the bottom context
>> +     or has not reached its endPC."
>> +    ^nil == myList
>> +      and: [nil ~~ suspendedContext
>> +      and: [suspendedContext isBottomContext
>> +            ifTrue: [suspendedContext closure
>> +                        ifNil: [suspendedContext methodClass ~~ Process
>> +                            or: [suspendedContext selector ~~ #terminate]]
>> +                        ifNotNil: [suspendedContext pc < suspendedContext closure endPC]]
>> +            ifFalse: [true]]]!
> 
> I find it hard to decode what this method does with all that boolean magic. IMHO early returns would make it a lot easier to understand what it actually does:
> 
>    myList ifNotNil: [ ^false ].
>    suspendedContext ifNil: [ ^false ].
>    suspendedContext isBottomContext ifFalse: [ ^true ].
>    suspendedContext closure ifNotNil: [ :closure |
>        ^suspendContext pc < closure endPC ].
>    ^suspendedContext methodClass ~~ Process
>        or: [ suspendedContext selector ~~ #terminate ]
> 
>> -    "A process is suspended if it is waiting on some list, other than the runnable process lists."
>> -    | myPriority |
>> -    "Grab my prioirty now.  Even though evaluation is strictly right-to-left, accessing Processor could involve a send."
>> -    myPriority := priority.
>> -    ^myList
>> -        ifNil: [false]
>> -        ifNotNil: [:list| list ~~ (Processor waitingProcessesAt: myPriority)]!
>> 
>> Item was changed:
>> ----- Method: Process>>isTerminated (in category 'testing') -----
>> isTerminated
>> +    "Answer if the receiver is terminated, or at least terminating."
>> -
>>    self isActiveProcess ifTrue: [^ false].
>>    ^suspendedContext isNil
>>      or: ["If the suspendedContext is the bottomContext it is the block in Process>>newProcess.
>> +           If so, and the pc is at the endPC, the block has already sent and returned
>> -           If so, and the pc is greater than the startpc, the block has alrteady sent and returned
>>           from value and there is nothing more to do."
>>        suspendedContext isBottomContext
>> +        and: [suspendedContext closure
>> +                        ifNil: [suspendedContext methodClass == Process
>> +                            and: [suspendedContext selector == #terminate]]
>> +                        ifNotNil: [suspendedContext pc >= suspendedContext closure endPC]]]!
> 
> Just like above.
> 
>> -        and: [suspendedContext pc > suspendedContext startpc]]!
>> 
>> Item was changed:
>> ----- Method: Process>>terminate (in category 'changing process state') -----
>> terminate
>>    "Stop the process that the receiver represents forever.  Unwind to execute pending ensure:/ifCurtailed: blocks before terminating."
>> 
>>    | ctxt unwindBlock oldList |
>>    self isActiveProcess ifTrue: [
>>        ctxt := thisContext.
>>        [    ctxt := ctxt findNextUnwindContextUpTo: nil.
>>            ctxt isNil
>>        ] whileFalse: [
>>            (ctxt tempAt: 2) ifNil:[
>>                ctxt tempAt: 2 put: nil.
>>                unwindBlock := ctxt tempAt: 1.
>>                thisContext terminateTo: ctxt.
>>                unwindBlock value].
>>        ].
>>        thisContext terminateTo: nil.
>>        self suspend.
>>    ] ifFalse:[
>>        "Always suspend the process first so it doesn't accidentally get woken up"
>>        oldList := self suspend.
>>        suspendedContext ifNotNil:[
>>            "Figure out if we are terminating a process that is in the ensure: block of a critical section.
>>             In this case, if the block has made progress, pop the suspendedContext so that we leave the
>>             ensure: block inside the critical: without signaling the semaphore/exiting the primitive section,
>>             since presumably this has already happened."
>>            (suspendedContext isClosureContext
>>             and: [(suspendedContext method pragmaAt: #criticalSection) notNil
>>             and: [suspendedContext startpc > suspendedContext closure startpc]]) ifTrue:
>>                [suspendedContext := suspendedContext home].
>> 
>>            "If we are 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]].
>> 
>>            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]]!
>> -                [self debug: ctxt title: 'Unwind error during termination']]]!
> 
> I guess you know already. :)
> 
> Levente
> 
> 


More information about the Squeak-dev mailing list