[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
|