[squeak-dev] Re: MVC debugging

Florin Mateoc fmateoc at gmail.com
Wed Sep 8 19:35:27 UTC 2010


 On 9/8/2010 1:42 PM, David T. Lewis wrote:
> On Wed, Sep 08, 2010 at 12:11:45PM -0400, Florin Mateoc wrote:
>>  On 9/8/2010 6:46 AM, David T. Lewis wrote:
>>> Florin, Andreas,
>>>
>>> Great thanks for this progress! I do get a debugger window now (yay!).
>>> I'm just heading out the door for the day but look forward to playing
>>> with this later.
>>>
>>> Dave
>>>
>> I made a little more progress:
>>
>> there is a bug in MVCToolBuilder class>>isActiveBuilder, which only responds true when asked from within the UI process.
>> Well, there are other processes in MVC as well, and the interrupt handling happens to be from a forked process. As a
>> result, ToolBuilder default is always nil in a non-UI process.
>> My tentative solution for this is, (but I don't know how this works with multiple projects, if supported):
>>
>> isActiveBuilder
>>     "Answer whether I am the currently active builder"
>>     "This is really a way of answering whether 'Smalltalk isMVC'"
>>     ScheduledControllers ifNil:[^false].
>>     ^(ScheduledControllers activeControllerProcess ifNil:[^false]) isTerminated not
>>
>>
>> I would also qualify as a semi-bug the fact that the Default class variable in ToolBuilder is unused. What looks like
>> lazy initialization in #isActiveBuilder never sets the variable. This was quite confusing and it threw me off track for
>> a while. If it is not used, (the setter is never called, at least not in the base image, not even indirectly through the
>> class pool, I checked :) ), it should be removed.
>>
> Yes the unused Default in ToolBuilder is a semi-bug. Possibly it should be
> set as a side effect of entering a project (Project>>enter:revert:saveForRevert:).
> I remember looking at this during the Project refactoring, but I thought at
> the time that it was safer to leave it alone (setting a global variable as
> a side effect of some other operation seemed dangerous, and the dynamic
> calculation seemed to be working fine as it was).
>
> Possibly a nicer approach would be to vector it through Project such that
> the current project always knows its ToolBuilder. But this adds Toolbuilder
> dependency in the System package, which did not seem like a good idea
> either.
>
> Dave
>
>

Finally! There were a couple of bugs in ControlManager>>interruptName:preemptedProcess: (e.g. Debugger does not
implement #controller)
I went ahead and simplified it a bit and spelled out the assumptions (as comments).
With this changeset the notifier now opens for the user interrupt, and you can also do "[1 halt] fork"

Florin

-------------- next part --------------
'From Squeak4.1 of 17 April 2010 [latest update: #9957] on 8 September 2010 at 3:30:48 pm'!

!ControlManager methodsFor: 'scheduling' stamp: 'fm 9/8/2010 15:29'!
interruptName: labelString preemptedProcess: theInterruptedProcess
	"Create a Notifier on the active scheduling process with the given label. Make the Notifier the active controller."

	"This method is assumed to be called from a non-UI process"
	activeControllerProcess suspend.

	activeController ~~ nil ifTrue: [
		"Carefully de-emphasis the current window."
		activeController view topView deEmphasizeForDebugger].

	"This will just scheduleNoTerminate the newly built controller"
	Debugger
			openInterrupt: labelString
			onProcess: activeControllerProcess.

	self searchForActiveController! !


!Debugger methodsFor: 'initialize' stamp: 'fm 9/8/2010 01:42'!
openFullNoSuspendLabel: aString
	"Create and schedule a full debugger with the given label. Do not terminate the current active process."

	| oldContextStackIndex |
	oldContextStackIndex := contextStackIndex.
	self expandStack. "Sets contextStackIndex to zero."
	ToolBuilder open1: self label: aString.
	self toggleContextStackIndex: oldContextStackIndex.! !

!Debugger methodsFor: 'initialize' stamp: 'fm 9/8/2010 15:16'!
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 builder spec |
	Sensor flushKeyboard.
	savedCursor := Sensor currentCursor.
	Sensor currentCursor: Cursor normal.
	(label beginsWith: 'Space is low')
		ifTrue: [msg := self lowSpaceChoices, (msgString ifNil: [''])]
		ifFalse: [msg := msgString].
	builder := ToolBuilder default.
	spec := self buildNotifierWith: builder label: label message: msg.
	self expandStack.
	builder open1: spec.
	errorWasInUIProcess := Project spawnNewProcessIfThisIsUI: interruptedProcess.
! !


!Debugger class methodsFor: 'opening' stamp: 'fm 9/8/2010 02:02'!
openOn: process context: context label: title contents: contentsStringOrNil fullView: bool
	"Open a notifier in response to an error, halt, or notify. A notifier view just shows a short view of the sender stack and provides a menu that lets the user open a full debugger."

	| controller errorWasInUIProcess debugger |
	Smalltalk isMorphic
		ifTrue: [errorWasInUIProcess := Project spawnNewProcessIfThisIsUI: process]
		ifFalse: [controller := ScheduledControllers activeControllerProcess == process
				ifTrue: [ScheduledControllers activeController].
				debugger := self new process: process controller: controller context: context.
				bool
						ifTrue: [debugger openFullNoSuspendLabel: title]
						ifFalse: [debugger openNotifierContents: contentsStringOrNil label: title]].
	WorldState addDeferredUIMessage: [ 
		[
			debugger := self new process: process controller: controller context: context.
			Smalltalk isMorphic
				ifTrue: ["schedule debugger in deferred UI message to address redraw
						problems after opening a debugger e.g. from the testrunner."
					"WorldState addDeferredUIMessage: "
					bool
						ifTrue: [debugger openFullNoSuspendLabel: title]
						ifFalse: [debugger openNotifierContents: contentsStringOrNil label: title]]
				ifFalse: ["deferred UI message would require special controller in MVC"
					bool
						ifTrue: [debugger openFullNoSuspendLabel: title]
						ifFalse: [debugger openNotifierContents: contentsStringOrNil label: title]].
			debugger errorWasInUIProcess: errorWasInUIProcess.
			Preferences logDebuggerStackToFile ifTrue: [
				Smalltalk logError: title inContext: context to: 'SqueakDebug.log'].
			Smalltalk isMorphic
				ifFalse: [ScheduledControllers searchForActiveController "needed since openNoTerminate (see debugger #open...) does not set up activeControllerProcess if activeProcess (this fork) is not the current activeControllerProcess (see #scheduled:from:)"].
		] on: Error do: [:ex |
			self primitiveError: 
				'Orginal error: ', 
				title asString, '.
	Debugger error: ', 
				([ex description] on: Error do: ['a ', ex class printString]), ':'
		]
	].
	process suspend.
! !


!MVCToolBuilder methodsFor: 'opening' stamp: 'fm 9/8/2010 15:23'!
open1: anObject
	"Build and open the object. Answer the widget opened."
	| window |
	window := self build: anObject.
	window controller openNoTerminate.
	^window! !

!MVCToolBuilder methodsFor: 'opening' stamp: 'fm 9/8/2010 01:41'!
open1: anObject label: aString
	"Build an open the object, labeling it appropriately.  Answer the widget opened."
	| window |
	window := self build: anObject.
	window label: aString.
	window controller openNoTerminate.
	^window! !


!MorphicToolBuilder methodsFor: 'opening' stamp: 'fm 9/8/2010 01:39'!
open1: anObject
	"Build and open the object. Answer the widget opened."
	| morph |
	anObject isMorph 
		ifTrue:[morph := anObject]
		ifFalse:[morph := self build: anObject].
	(morph isKindOf: MenuMorph)
		ifTrue:[morph popUpInWorld: World].
	(morph isKindOf: SystemWindow)
		ifTrue:[morph openInWorldExtent: morph extent]
		ifFalse:[morph openInWorld].
	^morph! !

!MorphicToolBuilder methodsFor: 'opening' stamp: 'fm 9/8/2010 01:41'!
open1: anObject label: aString
	"Build an open the object, labeling it appropriately.  Answer the widget opened."
	| window |
	window := self open: anObject.
	window setLabel: aString.
	^window! !


!ToolBuilder class methodsFor: 'instance creation' stamp: 'fm 9/8/2010 02:10'!
open1: aClass label: aString
	^self default open1: aClass label: aString! !


!MVCToolBuilder class methodsFor: 'accessing' stamp: 'fm 9/8/2010 11:52'!
isActiveBuilder
	"Answer whether I am the currently active builder"
	"This is really a way of answering whether 'Smalltalk isMVC'"
	ScheduledControllers ifNil:[^false].
	^(ScheduledControllers activeControllerProcess ifNil:[^false]) isTerminated not! !



More information about the Squeak-dev mailing list