Tim Felgentreff uploaded a new version of Graphics to project The Trunk:
http://source.squeak.org/trunk/Graphics-tfel.326.mcz
==================== Summary ====================
Name: Graphics-tfel.326
Author: tfel
Time: 19 February 2016, 2:17:46.541729 pm
UUID: 934ee205-38fd-4dcc-a877-b238d9e47a3a
Ancestors: Graphics-tfel.325
use VM primitive to flip screen buffers when drawing rectangles to the screen
=============== Diff against Graphics-tfel.325 ===============
Item was changed:
----- Method: Rectangle>>newRectButtonPressedDo: (in category 'transforming') -----
newRectButtonPressedDo: newRectBlock
"Track the outline of a new rectangle until mouse button
changes. newFrameBlock produces each new rectangle from the
previous. Only tracks while mouse is down."
| rect newRect buttonNow delay |
delay := Delay forMilliseconds: 10.
buttonNow := Sensor anyButtonPressed.
rect := self.
Display
border: rect
width: 2
rule: Form reverse
fillColor: Color gray.
[buttonNow]
whileTrue: [delay wait.
buttonNow := Sensor anyButtonPressed.
newRect := newRectBlock value: rect.
newRect = rect
ifFalse: [Display
border: rect
width: 2
rule: Form reverse
fillColor: Color gray.
Display
border: newRect
width: 2
rule: Form reverse
fillColor: Color gray.
+ Display forceToScreen.
rect := newRect]].
Display
border: rect
width: 2
rule: Form reverse
fillColor: Color gray.
Project current pointerMoved.
Sensor processEvent: Sensor createMouseEvent.
^ rect!
Item was changed:
----- Method: Rectangle>>newRectFrom: (in category 'transforming') -----
newRectFrom: newRectBlock
"Track the outline of a new rectangle until mouse button changes.
newFrameBlock produces each new rectangle from the previous"
| rect newRect buttonStart buttonNow delay |
delay := Delay forMilliseconds: 10.
buttonStart := buttonNow := Sensor anyButtonPressed.
rect := self.
Display border: rect width: 2 rule: Form reverse fillColor: Color gray.
[buttonNow == buttonStart] whileTrue:
[delay wait.
buttonNow := Sensor anyButtonPressed.
newRect := newRectBlock value: rect.
newRect = rect ifFalse:
[Display border: rect width: 2 rule: Form reverse fillColor: Color gray.
Display border: newRect width: 2 rule: Form reverse fillColor: Color gray.
+ Display forceToScreen.
rect := newRect]].
Display border: rect width: 2 rule: Form reverse fillColor: Color gray.
Project current pointerMoved.
Sensor processEvent: Sensor createMouseEvent.
^ rect!
Tim Felgentreff uploaded a new version of Graphics to project The Trunk:
http://source.squeak.org/trunk/Graphics-tfel.326.mcz
==================== Summary ====================
Name: Graphics-tfel.326
Author: tfel
Time: 19 February 2016, 2:17:46.541729 pm
UUID: 934ee205-38fd-4dcc-a877-b238d9e47a3a
Ancestors: Graphics-tfel.325
use VM primitive to flip screen buffers when drawing rectangles to the screen
=============== Diff against Graphics-tfel.325 ===============
Item was changed:
----- Method: Rectangle>>newRectButtonPressedDo: (in category 'transforming') -----
newRectButtonPressedDo: newRectBlock
"Track the outline of a new rectangle until mouse button
changes. newFrameBlock produces each new rectangle from the
previous. Only tracks while mouse is down."
| rect newRect buttonNow delay |
delay := Delay forMilliseconds: 10.
buttonNow := Sensor anyButtonPressed.
rect := self.
Display
border: rect
width: 2
rule: Form reverse
fillColor: Color gray.
[buttonNow]
whileTrue: [delay wait.
buttonNow := Sensor anyButtonPressed.
newRect := newRectBlock value: rect.
newRect = rect
ifFalse: [Display
border: rect
width: 2
rule: Form reverse
fillColor: Color gray.
Display
border: newRect
width: 2
rule: Form reverse
fillColor: Color gray.
+ Display forceToScreen.
rect := newRect]].
Display
border: rect
width: 2
rule: Form reverse
fillColor: Color gray.
Project current pointerMoved.
Sensor processEvent: Sensor createMouseEvent.
^ rect!
Item was changed:
----- Method: Rectangle>>newRectFrom: (in category 'transforming') -----
newRectFrom: newRectBlock
"Track the outline of a new rectangle until mouse button changes.
newFrameBlock produces each new rectangle from the previous"
| rect newRect buttonStart buttonNow delay |
delay := Delay forMilliseconds: 10.
buttonStart := buttonNow := Sensor anyButtonPressed.
rect := self.
Display border: rect width: 2 rule: Form reverse fillColor: Color gray.
[buttonNow == buttonStart] whileTrue:
[delay wait.
buttonNow := Sensor anyButtonPressed.
newRect := newRectBlock value: rect.
newRect = rect ifFalse:
[Display border: rect width: 2 rule: Form reverse fillColor: Color gray.
Display border: newRect width: 2 rule: Form reverse fillColor: Color gray.
+ Display forceToScreen.
rect := newRect]].
Display border: rect width: 2 rule: Form reverse fillColor: Color gray.
Project current pointerMoved.
Sensor processEvent: Sensor createMouseEvent.
^ rect!
Tim Felgentreff uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-tfel.1001.mcz
==================== Summary ====================
Name: Kernel-tfel.1001
Author: tfel
Time: 19 February 2016, 12:50:25.522776 pm
UUID: 26062a02-5ef1-43e2-b6d1-228cedef5a72
Ancestors: Kernel-eem.1000
Fix fallback code in Large(Positive|Negative)Integer>>normalize. The code incorrectly assumed that if you max/min integer is larger than -2**30 / 2**30-1 then you are on 64bit. Some VMs do not do Integer tagging, and for those the check should be as on the machine level (-2**31 / 2**31-1)
=============== Diff against Kernel-eem.1000 ===============
Item was changed:
----- Method: LargeNegativeInteger>>normalize (in category 'converting') -----
normalize
"Check for leading zeroes and return shortened copy if so"
| sLen val len oldLen minVal |
<primitive: 'primNormalizeNegative' module: 'LargeIntegers'>
"First establish len = significant length"
len := oldLen := self digitLength.
[len = 0 ifTrue: [^0].
(self digitAt: len) = 0]
whileTrue: [len := len - 1].
"Now check if in SmallInteger range.
Fast compute SmallInteger minVal digitLength"
+ sLen := SmallInteger minVal < -16r80000000 "we're definitely on 64bit if we are smaller than (-2 raisedTo: 31)"
- sLen := SmallInteger minVal < -16r40000000
ifTrue: [8]
ifFalse: [4].
len <= sLen ifTrue:
[minVal := SmallInteger minVal.
(len < sLen
or: [(self digitAt: sLen) < minVal lastDigit])
ifTrue: ["If high digit less, then can be small"
val := 0.
len to: 1 by: -1 do:
[:i | val := (val *256) - (self digitAt: i)].
^ val].
1 to: sLen do: "If all digits same, then = minVal"
[:i | (self digitAt: i) = (minVal digitAt: i)
ifFalse: ["Not so; return self shortened"
len < oldLen
ifTrue: [^ self growto: len]
ifFalse: [^ self]]].
^ minVal].
"Return self, or a shortened copy"
len < oldLen
ifTrue: [^ self growto: len]
ifFalse: [^ self]!
Item was changed:
----- Method: LargePositiveInteger>>normalize (in category 'converting') -----
normalize
"Check for leading zeroes and return shortened copy if so"
| sLen val len oldLen |
<primitive: 'primNormalizePositive' module:'LargeIntegers'>
"First establish len = significant length"
len := oldLen := self digitLength.
[len = 0 ifTrue: [^0].
(self digitAt: len) = 0]
whileTrue: [len := len - 1].
"Now check if in SmallInteger range. Fast compute SmallInteger maxVal digitLength"
+ sLen := SmallInteger maxVal > 16r7FFFFFFF "we're definitely on 64bit if we are larger than (2 raisedTo: 31) - 1"
- sLen := SmallInteger maxVal > 16r3FFFFFFF
ifTrue: [8]
ifFalse: [4].
(len <= sLen
and: [(self digitAt: sLen) <= (SmallInteger maxVal digitAt: sLen)])
ifTrue: ["If so, return its SmallInt value"
val := 0.
len to: 1 by: -1 do:
[:i | val := (val *256) + (self digitAt: i)].
^ val].
"Return self, or a shortened copy"
len < oldLen
ifTrue: [^ self growto: len]
ifFalse: [^ self]!
Tim Felgentreff uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-tfel.1001.mcz
==================== Summary ====================
Name: Kernel-tfel.1001
Author: tfel
Time: 19 February 2016, 12:50:25.522776 pm
UUID: 26062a02-5ef1-43e2-b6d1-228cedef5a72
Ancestors: Kernel-eem.1000
Fix fallback code in Large(Positive|Negative)Integer>>normalize. The code incorrectly assumed that if you max/min integer is larger than -2**30 / 2**30-1 then you are on 64bit. Some VMs do not do Integer tagging, and for those the check should be as on the machine level (-2**31 / 2**31-1)
=============== Diff against Kernel-eem.1000 ===============
Item was changed:
----- Method: LargeNegativeInteger>>normalize (in category 'converting') -----
normalize
"Check for leading zeroes and return shortened copy if so"
| sLen val len oldLen minVal |
<primitive: 'primNormalizeNegative' module: 'LargeIntegers'>
"First establish len = significant length"
len := oldLen := self digitLength.
[len = 0 ifTrue: [^0].
(self digitAt: len) = 0]
whileTrue: [len := len - 1].
"Now check if in SmallInteger range.
Fast compute SmallInteger minVal digitLength"
+ sLen := SmallInteger minVal < -16r80000000 "we're definitely on 64bit if we are smaller than (-2 raisedTo: 31)"
- sLen := SmallInteger minVal < -16r40000000
ifTrue: [8]
ifFalse: [4].
len <= sLen ifTrue:
[minVal := SmallInteger minVal.
(len < sLen
or: [(self digitAt: sLen) < minVal lastDigit])
ifTrue: ["If high digit less, then can be small"
val := 0.
len to: 1 by: -1 do:
[:i | val := (val *256) - (self digitAt: i)].
^ val].
1 to: sLen do: "If all digits same, then = minVal"
[:i | (self digitAt: i) = (minVal digitAt: i)
ifFalse: ["Not so; return self shortened"
len < oldLen
ifTrue: [^ self growto: len]
ifFalse: [^ self]]].
^ minVal].
"Return self, or a shortened copy"
len < oldLen
ifTrue: [^ self growto: len]
ifFalse: [^ self]!
Item was changed:
----- Method: LargePositiveInteger>>normalize (in category 'converting') -----
normalize
"Check for leading zeroes and return shortened copy if so"
| sLen val len oldLen |
<primitive: 'primNormalizePositive' module:'LargeIntegers'>
"First establish len = significant length"
len := oldLen := self digitLength.
[len = 0 ifTrue: [^0].
(self digitAt: len) = 0]
whileTrue: [len := len - 1].
"Now check if in SmallInteger range. Fast compute SmallInteger maxVal digitLength"
+ sLen := SmallInteger maxVal > 16r7FFFFFFF "we're definitely on 64bit if we are larger than (2 raisedTo: 31) - 1"
- sLen := SmallInteger maxVal > 16r3FFFFFFF
ifTrue: [8]
ifFalse: [4].
(len <= sLen
and: [(self digitAt: sLen) <= (SmallInteger maxVal digitAt: sLen)])
ifTrue: ["If so, return its SmallInt value"
val := 0.
len to: 1 by: -1 do:
[:i | val := (val *256) + (self digitAt: i)].
^ val].
"Return self, or a shortened copy"
len < oldLen
ifTrue: [^ self growto: len]
ifFalse: [^ self]!
Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-eem.1000.mcz
==================== Summary ====================
Name: Kernel-eem.1000
Author: eem
Time: 18 February 2016, 11:18:00.405861 pm
UUID: 70e6b96c-ca2f-4f79-8253-239575f13beb
Ancestors: Kernel-eem.999
Make Process>>resume primitive. Andreas fixed the ancestor of the Cog VM so that the resume primitive fails if the suspendedContext is not a context. This renders Tim's suspendedCOntext ifNil: [^self primitiveFailed] guard obsolete. Hence nuke primitiveResume.
=============== Diff against Kernel-eem.999 ===============
Item was removed:
- ----- Method: Process>>primitiveResume (in category 'changing process state') -----
- primitiveResume
- "Primitive. Allow the process that the receiver represents to continue. Put
- the receiver in line to become the activeProcess. Fail if the receiver is
- already waiting in a queue (in a Semaphore or ProcessScheduler).
- Essential. See Object documentation whatIsAPrimitive."
-
- <primitive: 87>
- self primitiveFailed!
Item was changed:
----- Method: Process>>resume (in category 'changing process state') -----
resume
+ "Primitive. Allow the process that the receiver represents to continue. Put
+ the receiver in line to become the activeProcess. Fail if the receiver is
+ already waiting in a queue (in a Semaphore or ProcessScheduler). Fail if
+ the receiver's suspendedContext is not a context.
+ Essential. See Object documentation whatIsAPrimitive."
- "Allow the process that the receiver represents to continue. Put
- the receiver in line to become the activeProcess. Check for a nil
- suspendedContext, which indicates a previously terminated Process that
- would cause a vm crash if the resume attempt were permitted"
+ <primitive: 87>
+ self primitiveFailed!
- suspendedContext ifNil: [^ self primitiveFailed].
- ^ self primitiveResume!
Eliot Miranda uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-eem.1000.mcz
==================== Summary ====================
Name: Kernel-eem.1000
Author: eem
Time: 18 February 2016, 11:18:00.405861 pm
UUID: 70e6b96c-ca2f-4f79-8253-239575f13beb
Ancestors: Kernel-eem.999
Make Process>>resume primitive. Andreas fixed the ancestor of the Cog VM so that the resume primitive fails if the suspendedContext is not a context. This renders Tim's suspendedCOntext ifNil: [^self primitiveFailed] guard obsolete. Hence nuke primitiveResume.
=============== Diff against Kernel-eem.999 ===============
Item was removed:
- ----- Method: Process>>primitiveResume (in category 'changing process state') -----
- primitiveResume
- "Primitive. Allow the process that the receiver represents to continue. Put
- the receiver in line to become the activeProcess. Fail if the receiver is
- already waiting in a queue (in a Semaphore or ProcessScheduler).
- Essential. See Object documentation whatIsAPrimitive."
-
- <primitive: 87>
- self primitiveFailed!
Item was changed:
----- Method: Process>>resume (in category 'changing process state') -----
resume
+ "Primitive. Allow the process that the receiver represents to continue. Put
+ the receiver in line to become the activeProcess. Fail if the receiver is
+ already waiting in a queue (in a Semaphore or ProcessScheduler). Fail if
+ the receiver's suspendedContext is not a context.
+ Essential. See Object documentation whatIsAPrimitive."
- "Allow the process that the receiver represents to continue. Put
- the receiver in line to become the activeProcess. Check for a nil
- suspendedContext, which indicates a previously terminated Process that
- would cause a vm crash if the resume attempt were permitted"
+ <primitive: 87>
+ self primitiveFailed!
- suspendedContext ifNil: [^ self primitiveFailed].
- ^ self primitiveResume!
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)]!
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)]!
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]]]!
- "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]]]!
- 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']]]!
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)]!
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)]!
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]]]!
- "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]]]!
- 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']]]!