Marcel Taeumel uploaded a new version of Tools to project The Trunk:
http://source.squeak.org/trunk/Tools-mt.1031.mcz
==================== Summary ====================
Name: Tools-mt.1031
Author: mt
Time: 15 March 2021, 11:22:01.998586 am
UUID: a69323cb-b4ee-8e4f-963d-780b2d40e73d
Ancestors: Tools-mt.1030
Complements Kernel-mt.1381
Fixes for debugger invocation during code simulation. See http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-c…
=============== Diff against Tools-mt.1030 ===============
Item was changed:
----- Method: Debugger class>>openOn:context:label:contents:fullView: (in category 'opening') -----
+ openOn: process context: context label: titleOrNil contents: contentsStringOrNil fullView: bool
- openOn: process context: context label: title contents: contentsStringOrNil fullView: bool
"Kind of private. Open a notifier or a full debugger in response to an error, halt, or notify. Opens a project-specific debugger. Decorates that invocation with (1) recursive-error detection and (2) error logging, which are both independent from the active GUI framework, that is, MVC or Morphic.
Note that clients should debug processes through Process >> #debug instead of calling this method directly."
+ | ap title |
+ title := titleOrNil ifNil: ['Debugger' translated].
- | ap |
ap := Processor activeProcess.
"If the active process re-enters this method again, something went wrong with invoking the debugger."
ap hasRecursiveError ifTrue: [
ap clearErrorRecursionFlag.
^ ToolSet handleRecursiveError: title].
"Explicitely handle logging exceptions. No need to bother the recursion mechanism here."
[Preferences logDebuggerStackToFile
ifTrue: [Smalltalk logSqueakError: title inContext: context]
] on: Error do: [:ex |
Preferences disable: #logDebuggerStackToFile.
ToolSet debugException: ex].
"If project-specific debuggers mess up, we have to flag that recursion here. Se above."
[ap setErrorRecursionFlag.
self informExistingDebugger: context label: title.
^ Project current debuggerClass
openOn: process context: context label: title contents: contentsStringOrNil fullView: bool
] ensure: [ap clearErrorRecursionFlag].!
Item was changed:
----- Method: ProcessBrowser class>>debugProcess: (in category 'process control') -----
debugProcess: aProcess
+ (aProcess isActiveProcess ifTrue: [Processor] ifFalse: [aProcess])
+ debugWithTitle: 'Interrupted from the Process Browser' translated
+ full: true.!
- aProcess debugWithTitle: 'Interrupted from the Process Browser'.
- !
Item was changed:
----- Method: StandardToolSet class>>debugProcess:context:label:contents:fullView: (in category 'debugging') -----
debugProcess: aProcess context: aContext label: aString contents: contents fullView: aBool
+ (aProcess isTerminated and: [aString isNil or: [aString beginsWith: 'Debug it']]) ifTrue: [
+ ^ Project uiManager inform: 'Nothing to debug. Process has terminated.\Expression optimized.' withCRs translated].
- (aProcess isTerminated and: [aString beginsWith: 'Debug it']) ifTrue: [
- ^ Project uiManager inform: 'Nothing to debug. Process has terminated.\Expression optimized.' withCRs].
^ Debugger
openOn: aProcess
context: aContext
label: aString
contents: contents
fullView: aBool!
Item was changed:
----- Method: StandardToolSet class>>handleError: (in category 'debugging - handlers') -----
handleError: anError
+ "Double dispatch. Let the processor take care of that error, which usually calls back here to #debugProcess:..."
- "Double dispatch. Let the active process take care of that error, which usually calls back here to #debugProcess:..."
+ ^ Processor
+ debugContext: anError signalerContext
+ title: anError description
+ full: false
+ contents: nil!
- ^ Processor activeProcess
- debug: anError signalerContext
- title: anError description!
Item was changed:
----- Method: StandardToolSet class>>handleWarning: (in category 'debugging - handlers') -----
handleWarning: aWarning
+ "Double dispatch. Let the processor take care of that warning, which usually calls back here to #debugProcess:..."
- "Double dispatch. Let the active process take care of that warning, which usually calls back here to #debugProcess:..."
| message |
message := '{1}\\{2}' withCRs asText format: {
"First, show the actual text of this warning."
aWarning messageText.
"Second, append some helpful information that apply to all kinds of warnings."
('{1} {2}' asText format: {
'Select "Proceed" to continue or close this window to cancel the operation.' translated.
'If you do not want to be interrupted anymore, you can {1} this kind of warning. You can also {2}, which resets such warnings on the next image startup.' translated asText format: {
"Provide clickable text links so that the user can directly suppress warnings."
'always suppress' asText
addAttribute: (PluggableTextAttribute evalBlock: [
aWarning class suppressWarnings.
self inform: ('All ''{1}'' warnings will be suppressed.' translated format: {aWarning class name})]).
'suppress temporarily' asText
addAttribute: (PluggableTextAttribute evalBlock: [
aWarning class suppressAndResetOnStartUp.
self inform: ('All ''{1}'' warnings will be suppressed\and reset on the next image startup.' withCRs translated format: {aWarning class name})])}.
}) addAttribute: (
"Show this helpful information in a smaller font."
TextFontReference toFont: Preferences standardButtonFont)}.
+ ^ Processor
+ debugContext: aWarning signalerContext
- ^ Processor activeProcess
- debug: aWarning signalerContext
title: 'Warning' translated
full: false
contents: message!
Marcel Taeumel uploaded a new version of System to project The Trunk:
http://source.squeak.org/trunk/System-mt.1222.mcz
==================== Summary ====================
Name: System-mt.1222
Author: mt
Time: 15 March 2021, 11:20:11.977586 am
UUID: 6148616b-707b-654f-8306-990a1e3f3bf6
Ancestors: System-mt.1221
Complements Kernel-mt.1381
Fixes for debugger invocation during code simulation. See http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-c…
=============== Diff against System-mt.1221 ===============
Item was changed:
----- Method: Process>>debug (in category '*System-debugging') -----
debug
+ "See the comment in #debugWithTitle:full:contents:."
+ ^ self debugWithTitle: nil!
- ^ self debugWithTitle: 'Debug'!
Item was removed:
- ----- Method: Process>>debug: (in category '*System-debugging') -----
- debug: context
-
- ^ self debug: context title: 'Debug'!
Item was removed:
- ----- Method: Process>>debug:title: (in category '*System-debugging') -----
- debug: context title: title
- "Open debugger on self with context shown on top"
-
- ^ self debug: context title: title full: false
- !
Item was removed:
- ----- Method: Process>>debug:title:full: (in category '*System-debugging') -----
- debug: context title: title full: bool
-
- ^ self
- debug: context
- title: title
- full: bool
- contents: nil!
Item was removed:
- ----- Method: Process>>debug:title:full:contents: (in category '*System-debugging') -----
- debug: context title: title full: bool contents: contents
- "Open debugger on self with context shown on top"
-
- | topCtxt |
- topCtxt := self isActiveProcess ifTrue: [thisContext] ifFalse: [self suspendedContext].
- (topCtxt hasContext: context) ifFalse: [^ self error: 'context not in process'].
- ^ ToolSet debugProcess: self context: context label: title contents: contents fullView: bool!
Item was changed:
----- Method: Process>>debugWithTitle: (in category '*System-debugging') -----
debugWithTitle: title
+ "See the comment in #debugWithTitle:full:contents:."
^ self debugWithTitle: title full: true!
Item was changed:
----- Method: Process>>debugWithTitle:full: (in category '*System-debugging') -----
debugWithTitle: title full: aBoolean
+ "See the comment in #debugWithTitle:full:contents:."
^ self debugWithTitle: title full: aBoolean contents: nil!
Item was changed:
----- Method: Process>>debugWithTitle:full:contents: (in category '*System-debugging') -----
debugWithTitle: title full: bool contents: contents
+ "BEWARE!! Open a debugger on the receiver, which must neither be running nor be simulated. Examples include workspace do-its, test execution, and helper processes. If you want to begin with a certain context, use #runUntil: before calling to here.
+
+ [ 3 + 4 ] newProcess debug.
+ (Process forBlock: [ 3 + 4 ]) debug.
+
+ Note that for debugging the currently running process, which might currently simulate the receiver, use ProcessorScheduler >> #debugWithTitle:.
+
+ (IMPLEMENTATION NOTE: The debugger interface is capable of debugging the active process correctly. However, unconditionally sending debug messages to the active process, in the past, led to a very tedious number of infinite debugger chains in an edge case when the effectiveProcess differs from the genuineProcess being executed by the VM (see ProcessorScheduler >> #activeProcess). This edge case occurs when a debugger is raised while another process is being simulated (aka process-faithful debugging, see #evaluate:onBehalfOf:), so at the very least Kernel methods should never send this message to the active process. For more information, see http://forum.world.st/I-broke-the-debugger-td5110752.html)"
- "Automatically choose the top context."
+ self assert: [self suspendedContext notNil "= not running"].
+ self assert: [self isActiveProcess not "= not even simulated"].
+
+ ^ ToolSet
+ debugProcess: self
+ context: self suspendedContext
+ label: title
+ contents: contents
+ fullView: bool!
- ^ self
- debug: (self isActiveProcess ifTrue: [thisContext] ifFalse: [self suspendedContext])
- title: title
- full: bool
- contents: contents!
Item was added:
+ ----- Method: ProcessorScheduler>>debugContext:title:full:contents: (in category '*System-Applications-debugging') -----
+ debugContext: aContext title: title full: aBoolean contents: contents
+ "Open a debugger on the currently running (i.e. genuine) process. Note that that process might actually simulate another process, which ends up here by checking #isActiveProcess. If no code simulation is involved, the genuine process will be suspended along the way -- and hopefully replaced to keep the system responsive. For the simulated case, an existing debugger should take over and leave the genuine process running, that is, simulating. Examples include (a) handling unhandled errors in a tool set and (b) introspecting thisContext to reveal dialog invocation.
+
+ Processor debugWithTitle: 'Debug' full: false contents: 'Carpe Squeak!!'
+
+ Note that, outside code simulation, suspended processes can be debugged directly via Process >> #debugWithTitle:. "
+
+ self assert: [thisContext hasSender: aContext].
+
+ ^ ToolSet
+ debugProcess: genuineProcess
+ context: aContext
+ label: title
+ contents: contents
+ fullView: aBoolean!
Item was added:
+ ----- Method: ProcessorScheduler>>debugContextThat:title: (in category '*System-Applications-debugging') -----
+ debugContextThat: aBlock title: title
+ "See the comment in #debugContext:title:full:contents:."
+
+ ^ self
+ debugContext: (thisContext sender findContextSuchThat: aBlock)
+ title: title
+ full: true
+ contents: nil!
Item was added:
+ ----- Method: ProcessorScheduler>>debugContextThat:title:full: (in category '*System-Applications-debugging') -----
+ debugContextThat: aBlock title: title full: aBoolean
+ "See the comment in #debugContext:title:full:contents:."
+
+ ^ self
+ debugContext: (thisContext sender findContextSuchThat: aBlock)
+ title: title
+ full: aBoolean
+ contents: nil!
Item was added:
+ ----- Method: ProcessorScheduler>>debugContextThat:title:full:contents: (in category '*System-Applications-debugging') -----
+ debugContextThat: aBlock title: title full: aBoolean contents: contents
+ "See the comment in #debugContext:title:full:contents:."
+
+ ^ self
+ debugContext: (thisContext sender findContextSuchThat: aBlock)
+ title: title
+ full: aBoolean
+ contents: contents!
Item was added:
+ ----- Method: ProcessorScheduler>>debugWithTitle: (in category '*System-Applications-debugging') -----
+ debugWithTitle: title
+ "See the comment in #debugContext:title:full:contents:."
+
+ ^ self
+ debugContext: thisContext sender
+ title: title
+ full: true
+ contents: nil!
Item was added:
+ ----- Method: ProcessorScheduler>>debugWithTitle:full: (in category '*System-Applications-debugging') -----
+ debugWithTitle: title full: aBoolean
+ "See the comment in #debugContext:title:full:contents:."
+
+ ^ self
+ debugContext: thisContext sender
+ title: title
+ full: aBoolean
+ contents: nil!
Item was added:
+ ----- Method: ProcessorScheduler>>debugWithTitle:full:contents: (in category '*System-Applications-debugging') -----
+ debugWithTitle: title full: aBoolean contents: contents
+ "See the comment in #debugContext:title:full:contents:."
+
+ ^ self
+ debugContext: thisContext sender
+ title: title
+ full: aBoolean
+ contents: contents!
Item was changed:
----- Method: ToolSet class>>debugProcess:context:label:contents:fullView: (in category 'debugging') -----
debugProcess: aProcess context: aContext label: aString contents: contents fullView: aBool
+ "Open a debugger on the given process, which might be active, suspended, or terminated. You can also use the convenience protocol for debugging on Process and ProcessorScheduler. NOTE that you should not pass Processor activeProcess directly to this method. Always use the indirection via ProcessorScheduler >>#debug... See also the comment in Process >> #debugWithTitle:full:contents:."
- "Open a debugger on the given process, which might be active, suspended, or terminated."
^ self default
+ ifNil: [(self confirm: 'Debugger request -- proceed?' translated) ifFalse: [Processor terminateActive]]
- ifNil: [(self confirm: 'Debugger request -- proceed?') ifFalse: [Processor terminateActive]]
ifNotNil: [:ts | ts debugProcess: aProcess context: aContext label: aString contents: contents fullView: aBool]!
Item was changed:
----- Method: WrappedBreakpoint>>run:with:in: (in category 'evaluation') -----
run: aSelector with: anArray in: aReceiver
| process |
process := Process
forContext: (Context
sender: thisContext sender
receiver: aReceiver
method: method
arguments: anArray)
priority: Processor activeProcess priority.
+ process
+ debugWithTitle: 'Breakpoint in ' , method methodClass name , '>>#' , method selector.
- ToolSet
- debugProcess: process
- context: process suspendedContext
- label: 'Breakpoint in ' , method methodClass name , '>>#' , method selector
- contents: nil
- fullView: true.
Project current spawnNewProcessIfThisIsUI: Processor activeProcess.
thisContext swapSender: nil.
Processor activeProcess terminate!
Marcel Taeumel uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-mt.1381.mcz
==================== Summary ====================
Name: Kernel-mt.1381
Author: mt
Time: 15 March 2021, 11:19:02.546586 am
UUID: 11976771-8ccb-e941-83da-2ae26c3a9f55
Ancestors: Kernel-mt.1380
Fixes for debugger invocation during code simulation. See http://forum.world.st/Please-try-out-Fixes-for-debugger-invocation-during-c…
=============== Diff against Kernel-mt.1380 ===============
Item was changed:
(PackageInfo named: 'Kernel') preamble: '"below, add code to be run before the loading of this package"
+ ProcessorScheduler instVarNames at: 2 put: ''genuineProcess''.'!
- BlockClosure instVarNames at: 2 put: ''startpcOrMethod'''!
Item was changed:
----- Method: Context>>cannotReturn: (in category 'private-exceptions') -----
cannotReturn: result
+ closureOrNil ifNotNil: [^ self cannotReturn: result to: self home sender].
+ Processor debugWithTitle: 'Computation has been terminated!!' translated full: false.!
- closureOrNil notNil ifTrue:
- [^self cannotReturn: result to: self home sender].
- Processor activeProcess
- debug: thisContext
- title: 'computation has been terminated'
- full: false.!
Item was changed:
----- Method: Context>>doPrimitive:method:receiver:args: (in category 'private') -----
doPrimitive: primitiveIndex method: meth receiver: receiver args: arguments
"Simulate a primitive method whose index is primitiveIndex. The simulated receiver and
arguments are given as arguments to this message. If successful, push result and return
resuming context, else ^ {errCode, PrimitiveFailToken}. Any primitive which provokes
execution needs to be intercepted and simulated to avoid execution running away."
| value |
"Judicious use of primitive 19 (a null primitive that doesn't do anything) prevents
the debugger from entering various run-away activities such as spawning a new
process, etc. Injudicious use results in the debugger not being able to debug
interesting code, such as the debugger itself. Hence use primitive 19 with care :-)"
"SystemNavigation new browseAllSelect: [:m| m primitive = 19]"
+ primitiveIndex = 19 ifTrue: [
+ [self notify: ('The code being simulated is trying to control a process ({1}). Process controlling cannot be simulated. If you proceed, things may happen outside the observable area of the simulator.' translated format: {meth reference})]
+ ifCurtailed: [self push: nil "Cheap fix of the context's internal state"]].
+
- primitiveIndex = 19 ifTrue:
- [Processor activeProcess
- debug: self
- title:'Code simulation error'
- full: false].
-
((primitiveIndex between: 201 and: 222)
and: [(self objectClass: receiver) includesBehavior: BlockClosure]) ifTrue:
[(primitiveIndex = 206
or: [primitiveIndex = 208]) ifTrue: "[Full]BlockClosure>>valueWithArguments:"
[^receiver simulateValueWithArguments: arguments first caller: self].
((primitiveIndex between: 201 and: 209) "[Full]BlockClosure>>value[:value:...]"
or: [primitiveIndex between: 221 and: 222]) ifTrue: "[Full]BlockClosure>>valueNoContextSwitch[:]"
[^receiver simulateValueWithArguments: arguments caller: self]].
primitiveIndex = 83 ifTrue: "afr 9/11/1998 19:50" "Object>>perform:[with:...]"
[^self send: arguments first to: receiver with: arguments allButFirst].
primitiveIndex = 84 ifTrue: "afr 9/11/1998 19:50 & eem 8/18/2009 17:04" "Object>>perform:withArguments:"
[^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (self objectClass: receiver)].
primitiveIndex = 100 ifTrue: "eem 8/18/2009 16:57" "Object>>perform:withArguments:inSuperclass:"
[^self send: arguments first to: receiver with: (arguments at: 2) lookupIn: (arguments at: 3)].
"Mutex>>primitiveEnterCriticalSection
Mutex>>primitiveTestAndSetOwnershipOfCriticalSection"
(primitiveIndex = 186 or: [primitiveIndex = 187]) ifTrue:
+ [| effective |
+ effective := Processor activeProcess effectiveProcess.
+ "active == effective"
+ value := primitiveIndex = 186
+ ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: effective]
+ ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: effective].
- ["Transcript
- cr;
- nextPutAll: 'Processor activeProcess ';
- nextPutAll: (Processor activeProcess == receiver owningProcess ifTrue: [#==] ifFalse: [#~~]);
- nextPutAll: ' owner';
- flush."
- value := primitiveIndex = 186
- ifTrue: [receiver primitiveEnterCriticalSectionOnBehalfOf: Processor activeProcess]
- ifFalse: [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf: Processor activeProcess].
^(self isPrimFailToken: value)
ifTrue: [value]
ifFalse: [self push: value]].
primitiveIndex = 188 ifTrue: "Object>>withArgs:executeMethod:
CompiledMethod class>>receiver:withArguments:executeMethod:
VMMirror>>ifFail:object:with:executeMethod: et al"
[| n args methodArg thisReceiver |
((n := arguments size) between: 2 and: 4) ifFalse:
[^self class primitiveFailTokenFor: #'unsupported operation'].
((self objectClass: (args := arguments at: n - 1)) == Array
and: [(self objectClass: (methodArg := arguments at: n)) includesBehavior: CompiledMethod]) ifFalse:
[^self class primitiveFailTokenFor: #'bad argument'].
methodArg numArgs = args size ifFalse:
[^self class primitiveFailTokenFor: #'bad number of arguments'].
thisReceiver := arguments at: n - 2 ifAbsent: [receiver].
methodArg primitive > 0 ifTrue:
[methodArg isQuick ifTrue:
[^self push: (methodArg valueWithReceiver: thisReceiver arguments: args)].
^self doPrimitive: methodArg primitive method: meth receiver: thisReceiver args: args].
^Context
sender: self
receiver: thisReceiver
method: methodArg
arguments: args].
primitiveIndex = 118 ifTrue: "[receiver:]tryPrimitive:withArgs:; avoid recursing in the VM"
[(arguments size = 3
and: [(self objectClass: arguments second) == SmallInteger
and: [(self objectClass: arguments last) == Array]]) ifTrue:
[^self doPrimitive: arguments second method: meth receiver: arguments first args: arguments last].
(arguments size = 2
and: [(self objectClass: arguments first) == SmallInteger
and: [(self objectClass: arguments last) == Array]]) ifFalse:
[^self class primitiveFailTokenFor: nil].
^self doPrimitive: arguments first method: meth receiver: receiver args: arguments last].
value := primitiveIndex = 120 "FFI method"
ifTrue: [(meth literalAt: 1) tryInvokeWithArguments: arguments]
ifFalse:
[primitiveIndex = 117 "named primitives"
ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments]
ifFalse: "should use self receiver: receiver tryPrimitive: primitiveIndex withArgs: arguments but this is only in later VMs (and appears to be broken)"
[receiver tryPrimitive: primitiveIndex withArgs: arguments]].
^(self isPrimFailToken: value)
ifTrue: [value]
ifFalse: [self push: value]!
Item was changed:
----- Method: ObjectTracer>>doesNotUnderstand: (in category 'very few messages') -----
doesNotUnderstand: aMessage
+ "Present a debugger before proceeding to re-send the message. All external messages (those not caused by the re-send) get trapped here."
- "Present a debugger before proceeding to re-send the message"
+ self flag: #workaround. "ct: After the selection of buttons in the debugger has been refactored, return to a simple Warning here. See: http://forum.world.st/The-Trunk-Kernel-mt-1303-mcz-tp5112200p5112211.html"
+ Processor
+ debugWithTitle: ('Object Tracer ({1})' translated format: {self identityHash})
- "All external messages (those not caused by the re-send) get trapped here"
- Processor activeProcess
- debugWithTitle: 'Object Tracer (', self identityHash, ')'
full: false
contents: ('On an instance of\ {1} ({2})\\About to perform\ {3}\\Using the following arguments\ {4}' translated withCRs
format: {
thisContext objectClass: tracedObject.
tracedObject identityHash.
aMessage selector storeString.
aMessage arguments printString}).
+
-
^ aMessage sendTo: tracedObject!
Item was changed:
----- Method: Process>>evaluate:onBehalfOf: (in category 'private') -----
evaluate: aBlock onBehalfOf: aProcess
+ "Evaluate aBlock setting effectiveProcess to aProcess. Used in the execution simulation machinery to ensure that Processor activeProcess evaluates correctly when debugging, which is also known as process-faithful debugging."
+
+ | oldEffectiveProcess |
+ aProcess == self ifTrue: [^ aBlock value]. "Optimization"
+
+ oldEffectiveProcess := effectiveProcess.
- "Evaluate aBlock setting effectiveProcess to aProcess, and all other variables other than
- the scheduling ones to those of aProcess. Used in the execution simulation machinery
- to ensure that Processor activeProcess evaluates correctly when debugging."
- | range savedVariables |
- "range accesses everything after myList, e.g. threadId, effectiveProcess, name, island, env"
- range := 5 to: Process instSize.
- savedVariables := range collect: [:i| self instVarAt: i].
- range do:
- [:i| self instVarAt: i put: (aProcess instVarAt: i)].
effectiveProcess := aProcess.
+ ^ aBlock ensure: [effectiveProcess := oldEffectiveProcess]!
- ^aBlock ensure:
- ["write back any assigned-to variables."
- range do:
- [:i| | v |
- ((v := self instVarAt: i) ~~ (aProcess instVarAt: i)
- and: [v notNil]) ifTrue:
- [aProcess instVarAt: i put: v]].
- "restore old values"
- range with: savedVariables do:
- [:i :var| self instVarAt: i put: var]]!
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.
If the process is in the middle of a critical: critical section, release it properly."
| 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]].
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]].
ctxt := self popTo: suspendedContext bottomContext.
ctxt == suspendedContext bottomContext ifFalse:
+ [self debugWithTitle: 'Unwind error during termination' translated full: false].
- [self debug: ctxt title: 'Unwind error during termination'].
"Set the context to its endPC for the benefit of isTerminated."
ctxt pc: ctxt endPC]!
Item was changed:
Object subclass: #ProcessorScheduler
+ instanceVariableNames: 'quiescentProcessLists genuineProcess'
- instanceVariableNames: 'quiescentProcessLists activeProcess'
classVariableNames: 'BackgroundProcess HighIOPriority LowIOPriority SystemBackgroundPriority SystemRockBottomPriority TimingPriority UserBackgroundPriority UserInterruptPriority UserSchedulingPriority'
poolDictionaries: ''
category: 'Kernel-Processes'!
!ProcessorScheduler commentStamp: '<historical>' prior: 0!
My single instance, named Processor, coordinates the use of the physical processor by all Processes requiring service.!
Item was changed:
----- Method: ProcessorScheduler>>activePriority (in category 'accessing') -----
activePriority
"Answer the priority level of the currently running Process."
+ ^ self activeProcess priority!
- ^activeProcess effectiveProcess priority!
Item was changed:
----- Method: ProcessorScheduler>>activeProcess (in category 'accessing') -----
activeProcess
+ "Answer the active process (from the user's perspective), which can be simulated by the genuinely running process (from the system's perspective). See Process >> #evaluate:onBehalfOf:."
- "Answer the currently running Process."
+ ^genuineProcess effectiveProcess!
- ^activeProcess effectiveProcess!
Item was changed:
----- Method: ProcessorScheduler>>terminateActive (in category 'process state change') -----
terminateActive
"Terminate the process that is currently running."
+ self activeProcess terminate.!
- activeProcess effectiveProcess terminate!
David T. Lewis uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-dtl.931.mcz
==================== Summary ====================
Name: Collections-dtl.931
Author: dtl
Time: 11 March 2021, 5:44:43.577146 pm
UUID: 1ed239e3-d108-43c3-8b6e-de8c43d842d1
Ancestors: Collections-nice.930
Set logic methods should be discoverable, so give them a method category. Add an implementation of Collection>>symmetricDifference: so that the basic set operations of union, intersection, difference, and symmetric difference are available.
=============== Diff against Collections-nice.930 ===============
Item was changed:
+ ----- Method: Collection>>difference: (in category 'set logic') -----
- ----- Method: Collection>>difference: (in category 'enumerating') -----
difference: aCollection
"Answer the set theoretic difference of two collections."
^ self reject: [:each | aCollection includes: each]!
Item was changed:
+ ----- Method: Collection>>intersection: (in category 'set logic') -----
- ----- Method: Collection>>intersection: (in category 'enumerating') -----
intersection: aCollection
"Answer the set theoretic intersection of two collections."
^ self select: [:each | aCollection includes: each]!
Item was added:
+ ----- Method: Collection>>symmetricDifference: (in category 'set logic') -----
+ symmetricDifference: aCollection
+ "Answer the set theoretic symmetric difference of two collections."
+
+ ^ (self difference: aCollection) union: (aCollection difference: self)
+ !
Item was changed:
+ ----- Method: Collection>>union: (in category 'set logic') -----
- ----- Method: Collection>>union: (in category 'enumerating') -----
union: aCollection
"Answer the set theoretic union of two collections."
^ self asSet addAll: aCollection; yourself!
Item was changed:
+ ----- Method: HashedCollection>>union: (in category 'set logic') -----
- ----- Method: HashedCollection>>union: (in category 'enumerating') -----
union: aCollection
"Answer the set theoretic union of the receiver and aCollection, using the receiver's notion of equality and not side effecting the receiver at all."
^ self copy addAll: aCollection; yourself
!
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1740.mcz
==================== Summary ====================
Name: Morphic-mt.1740
Author: mt
Time: 11 March 2021, 2:11:59.965436 pm
UUID: 3512b5b2-7e73-134e-ae42-dfedc359858f
Ancestors: Morphic-mt.1739
Minor clean-up in initial halo dispatch:
- Do not ask for #handlesMouseDown: but only #wantsHaloFromClick.
- Do not rely on aContainer being the actual world (e.g. aPasteUp) but maybe any (inner) container.
- Leave two assertions as documentation.
Effective rules for halo dispatch not changed. The bug with protruding submorphs is still present.
=============== Diff against Morphic-mt.1739 ===============
Item was changed:
----- Method: MorphicHaloDispatcher>>dispatchHalo:createFor: (in category 'dispatching') -----
+ dispatchHalo: anEvent createFor: aContainer
+ "Invoke a halo on any aContainer's submorph that wants it. Dispatch uses anEvent's #position. The dispatch only ends in that container if no other morph wants it. Note that the event's #shiftPressed state determines whether the dispatch goes innermost-to-outermost (if pressed) or the other way around (if not pressed).
+
+ If there already is a halo, check whether the event still points into the same hierarchy. If it does, do nothing here but rely on the halo itself to process the event (see implementors of #transferHalo:from:). If, however, the event points to a different hierarchy in the container, invoke a new halo and discard the current one. We do this here because the current halo should not bother with its container but only its #target."
- dispatchHalo: anEvent createFor: aMorph
- "Invoke halos around the top-most world container at aUserInputEvent's #position. If it was already halo'd, zero-in on its next inward component morph at that position. Holding Shift during the click reverses this traversal order."
| stack innermost haloTarget |
+ "The stack is the frontmost (i.e. innermost) to backmost (i.e. outermost) morph."
+ stack := (aContainer morphsAt: anEvent position unlocked: true) select:
+ [ : each | each wantsHaloFromClick ].
+ "self assert: [ stack last == aContainer ]."
- "the stack is the top-most morph to bottom-most."
- stack := (aMorph morphsAt: anEvent position unlocked: true) select:
- [ : each | each wantsHaloFromClick or: [ each handlesMouseDown: anEvent ] ].
innermost := anEvent hand halo
ifNil: [ stack first ]
ifNotNil:
+ [ : existingHalo |
+ "self assert: [ existingHalo wantsHaloFromClick not ]. "
+ stack
+ detect: [ : each | each owner == aContainer ]
- [ : existingHalo |
- (stack := stack copyWithout: existingHalo) "No halos on halos"
- detect: [ : each | each owner == aMorph ]
ifFound:
+ [ : topInContainer | "Is existingHalo's target part of the same topInContainer as the morph clicked?"
+ (existingHalo target withAllOwners includes: topInContainer)
- [ : worldContainer | "Is existingHalo's target part of the same worldContainer as the morph clicked?"
- (existingHalo target withAllOwners includes: worldContainer)
ifTrue: [ "same hierarchy, let #transferHalo: continue to handle it for now." ^ false ]
ifFalse:
[ "different hierarchy, remove + add."
anEvent hand removeHalo.
anEvent shiftPressed
ifTrue: [ stack first ]
+ ifFalse: [ topInContainer ] ] ]
- ifFalse: [ worldContainer ] ] ]
ifNone: [ "existingHalo is on the World, defer to #transferHalo: for now." ^ false ] ].
"If modifier key is pressed, start at innermost (the target), otherwise the outermost (direct child of the world (self))."
+ haloTarget := (innermost == aContainer or: [ anEvent shiftPressed ])
- haloTarget := (innermost == aMorph or: [anEvent shiftPressed])
ifTrue: [ innermost ]
ifFalse:
+ [ "Find the outermost owner that wants it. Ignore containment above aContainer."
+ stack := innermost withAllOwners.
+ (stack first: (stack findFirst: [ : each | each owner == aContainer ])) reversed
- [ "Find the outermost owner that wants it."
- innermost withAllOwners reversed allButFirst
detect: [ : each | each wantsHaloFromClick ]
ifNone: [ "haloTarget has its own mouseDown handler, don't halo." ^ false ] ].
"Now that we have the haloTarget, show the halo."
self invokeHaloOrMove: anEvent on: haloTarget.
^ true!
Marcel Taeumel uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-mt.1380.mcz
==================== Summary ====================
Name: Kernel-mt.1380
Author: mt
Time: 9 March 2021, 11:40:18.855529 am
UUID: cef64cd0-d892-584e-8bce-6f5dac0202fc
Ancestors: Kernel-eem.1379
Make sure that special object no. 38 is FullBlockClosure.
See discussion at http://forum.world.st/Smalltalk-specialObjectsArray-at-38-tp5125148p5125164…
=============== Diff against Kernel-eem.1379 ===============
Item was added:
+ ----- Method: FullBlockClosure class>>initialize (in category 'class initialization') -----
+ initialize
+ "Also see SmalltalkImage >> #recreateSpecialObjectsArray."
+
+ (Smalltalk specialObjectsArray at: 38)
+ ifNil: [Smalltalk specialObjectsArray at: 38 put: self].!
Nicolas Cellier uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-nice.930.mcz
==================== Summary ====================
Name: Collections-nice.930
Author: nice
Time: 8 March 2021, 3:46:35.811868 pm
UUID: 923d86a7-1d60-4d7f-975a-c20e365efc5a
Ancestors: Collections-nice.929
Fix my horrible bug before it gets noticed **Blush**
I stupidely tested against Array (good) with #yourself as the collect: block (bad idea!)
=============== Diff against Collections-nice.929 ===============
Item was changed:
----- Method: LimitedPrecisionInterval>>collect: (in category 'enumerating') -----
collect: aBlock
"Evaluate aBlock with each of the receiver's elements as the argument.
Collect the resulting values into a collection like the receiver. Answer
the new collection.
Implementation notes: see do: for an explanation on loop detail"
| result |
result := self species new: self size.
1 to: result size do:
[:i |
"(self at: i) is inlined here to avoid repeated bound checking"
+ result at: i put: (aBlock value: i - 1 * step + start)].
- result at: i put: i - 1 * step + start].
^ result!