[squeak-dev] The Trunk: Kernel-eem.999.mcz
Levente Uzonyi
leves at caesar.elte.hu
Sat Feb 20 03:20:26 UTC 2016
Hi Eliot,
On Fri, 19 Feb 2016, Eliot Miranda wrote:
> 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.
>
I mean in case of
myList ifNil: [ ^false ]
^myList ~~ (Processor waitingProcessesAt: myPriority)
The second line will work because the value of myList is on the left side
of #~~, so it will have been pushed onto the stack when Processor will be
dereferenced.
Levente
>>
>>>
>>> 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
|