Debugging forked processes [BUG][FIX]

Bob Arning arning at
Fri Jun 18 02:17:22 UTC 1999

Several folks have commented recently on getting walkbacks when clicking on the top pane of the debugger. Looking into this, there are at least two potential problems. If you want to experience them firsthand, 

Experience 1:
evaluate ([nil+1] fork)
hit the debug button on the pre-debug window that appears
evaluate ([nil+1] fork) again
hit the debug button on the pre-debug window that appears
now try moving one of the debugger windows by dragging its title bar. If your system behaves like mine, you will be seeing strange visual artifacts. You *may* also get additional walkbacks.

Experience 2:
In one of the debuggers above, click on the line '[] in UndefinedObject>>DoIt' in the top pane. Again, be prepared for trouble.

Analysis 1:
The debugger suspends the active process and (in Morphic, anyway) spawns a new one to handle events. The problem is that if the walkback occurred in a process *other* than the main event process, then there will now be two (or more) processes running the main event loop. They can step on each other in setting and clearing the <activeHand> as well as producing strange visual behavior.

Analysis 2:
When expressions are evaluated in a workspace, a method is temporarily added to some class (like UndefinedObject) and then removed after the evaluation is complete. The problem is that if the expression forks another process, that process may encounter a walkback *after* the method (#DoIt) has been removed. This leads to a walkback in the debugger since it is unable to find the source for the method.

Fix 1:
If some process is still running the main event loop, then the debugger need not (read: better not) start another one.

Fix 2:
Fail a bit more gracefully when the method being debugged no longer exists.

Note: Nether of these fixes is ideal in my mind and I will give them some more thought, but since I've been bitten by these a number of times and since others have mentioned this as well, here is what I have:



'From Squeak 2.4b of April 23, 1999 on 17 June 1999 at 9:55:13 pm'!
PasteUpMorph subclass: #WorldMorph
	instanceVariableNames: 'hands activeHand viewBox canvas damageRecorder stepList lastStepTime lastCycleTime '
	classVariableNames: 'DisableDeferredUpdates MinCycleLapse StillAlive '
	poolDictionaries: ''
	category: 'Morphic-Kernel'!

!Debugger methodsFor: 'initialize' stamp: 'RAA 6/17/1999 20:38'!
openFullNoSuspendLabel: aString
	"Create and schedule a full debugger with the given label. Do not terminate the current active process."

	| topView |
	Smalltalk isMorphic ifTrue:
		[self openFullMorphicLabel: aString.
		^ Project current spawnNewProcessIfNeeded].
	topView _ self buildMVCDebuggerViewLabel: aString minSize: 300 at 200.
	topView controller openNoTerminate.
	^ topView
! !

!Debugger methodsFor: 'initialize' stamp: 'RAA 6/17/1999 20:38'!
openNotifierContents: msgString label: label
	"Create and schedule a notifier view with the given label and message. A notifier view shows just the message or the first several lines of the stack, with a menu that allows the user to open a full debugger if so desired."
	"NOTE: When this method returns, a new process has been scheduled to run the windows, and thus this notifier, but the previous active porcess has not been suspended.  The sender will do this."
	| msg topView p |
	Sensor flushKeyboard.
	(label beginsWith: 'Space is low')
		ifTrue: [msg _ self lowSpaceChoices, msgString]
		ifFalse: [msg _ msgString].

	World ifNotNil:
		[self buildMorphicNotifierLabelled: label message: msg.
		^ Project current spawnNewProcessIfNeeded].

	Display fullScreen.
	Cursor normal show.
	topView _ self buildMVCNotifierViewLabel: label message: msg minSize: 350@((14 * 5) + 16).
	ScheduledControllers activeController
		ifNil: [p _ Display boundingBox center]
		ifNotNil: [p _ ScheduledControllers activeController view displayBox center].
	topView controller openNoTerminateDisplayAt: (p max: (200 at 60)).
	^ topView
! !

!Debugger methodsFor: 'context stack (message list)' stamp: 'RAA 6/17/1999 21:50'!
	"Answer the source code of the currently selected context."
	contents _ [self selectedContext sourceCode] ifError: [ :err :rcvr |
"',(err reject: [ :each | each == $"]),'"'
	Preferences browseWithPrettyPrint ifTrue: [contents _ self selectedClass compilerClass new
					format: contents
					in: self selectedClass
					notifying: nil].
	^ contents _ contents asText makeSelectorBoldIn: self selectedClass! !

!Project methodsFor: 'active process' stamp: 'RAA 6/17/1999 21:47'!

	world isMorph ifFalse: [^self spawnNewProcess].	"does this ever happen?"
	world stillAlive: false.
	(Delay forSeconds: 1) wait.
	world stillAlive ifFalse: [^self spawnNewProcess].
	! !

!SyntaxError class methodsFor: 'instance creation' stamp: 'RAA 6/17/1999 20:38'!
open: aSyntaxError
	"Answer a standard system view whose model is an instance of me."
	| topView |
	<primitive: 19> "Simulation guard"
	World ifNotNil:
		[self buildMorphicViewOn: aSyntaxError.
		Project current spawnNewProcessIfNeeded.
		^ Processor activeProcess suspend].
	topView _ self buildMVCViewOn: aSyntaxError.
	topView controller openNoTerminateDisplayAt: Display extent // 2.
	Cursor normal show.
	Processor activeProcess suspend.
! !

!WorldMorph methodsFor: 'interaction loop' stamp: 'RAA 6/17/1999 20:21'!
	"Do one cycle of the interactive loop. This method is called repeatedly when the world is running."

	"process user input events"
	hands do: [:h |
		self activeHand: h.
		h processEvents.
		self activeHand: nil].

	self runStepMethods.
	self displayWorldSafely.
	StillAlive _ true.
! !

!WorldMorph methodsFor: 'interaction loop' stamp: 'RAA 6/17/1999 20:37'!
	^StillAlive ifNil: [false]
! !

!WorldMorph methodsFor: 'interaction loop' stamp: 'RAA 6/17/1999 20:36'!
stillAlive: aBoolean
	StillAlive _ aBoolean
! !

More information about the Squeak-dev mailing list