[squeak-dev] The Inbox: Tools-lrnp.1147.mcz

Marcel Taeumel marcel.taeumel at hpi.de
Wed Apr 27 15:34:34 UTC 2022

Hi Lauren --

-1 on this version/implementation
+1 on the idea

I like the overall direction to keep the system running and not annoy the user too much if they make a mistake.

Yet, I think this one needs more discussion and iteration. I challenge the intrusive way you use to count the open debuggers. I would like to see a more lightweight watcher process.

I don't think that either "number of max open debuggers" nor "min delay between debuggers" etc. is an option that a user can come up with for their current system and scenario. Well, not even the input-timeout for our list filters is really good. This is a kind of tricky UX challenge. The false-positive might be dangerous. The n+1-th debugger might be the one with useful information.

We might need domain-specific groups of debuggers. One window for each group.

Can you provide an example? How to trigger a flood of debuggers. Maybe we can find a way to group new debuggers somehow? For Morphic drawing errors, I already implemented such a domain-specific rule. See WorldState >> #displayWorldSafely:.

Am 23.04.2022 23:36:45 schrieb commits at source.squeak.org <commits at source.squeak.org>:
A new version of Tools was added to project The Inbox:

==================== Summary ====================

Name: Tools-lrnp.1147
Author: lrnp
Time: 23 April 2022, 3:35:52.83495 pm
UUID: 343ce1d0-c9d3-47ec-8648-93be4d21471c
Ancestors: Tools-tpr.1146, Tools.lrnp-squeak5.3-debuggerFloodPrevention-20220423.6

debugger window flooding protection

Prevent the debugger from grinding the image to a halt by opening an endless torrent of windows. When a (by default) 6th debugger window would be opened within 3 seconds of opening the previous 5, the project is immediately suspended and exited so the user can attempt recovery or generate a debug log.

Comes with a preference to change the rate limit.

=============== Diff against Tools-tpr.1146 ===============

Item was changed:
CodeHolder subclass: #Debugger
instanceVariableNames: 'interruptedProcess contextStack contextStackIndex contextStackList receiverInspector receiverInspectorState contextVariablesInspector contextVariablesInspectorState externalInterrupt proceedValue selectingPC savedCursor isolationHead failedProject labelString message untilExpression'
+ classVariableNames: 'ContextStackKeystrokes ErrorReportServer FullStackSize InterruptUIProcessIfBlockedOnErrorInBackgroundProcess MaximumOpenDebuggers NotifierStackSize SavedExtent StackSizeLimit WantsAnnotationPane'
- classVariableNames: 'ContextStackKeystrokes ErrorReportServer FullStackSize InterruptUIProcessIfBlockedOnErrorInBackgroundProcess NotifierStackSize SavedExtent StackSizeLimit WantsAnnotationPane'
poolDictionaries: ''
category: 'Tools-Debugger'!
+ Debugger class
+ instanceVariableNames: 'openInstances'!

!Debugger commentStamp: 'mt 12/17/2019 12:19' prior: 0!
I represent the machine state at the time of an interrupted process. I also represent a query path into the state of the process. The debugger is typically viewed through a window that views the stack of suspended contexts, the code for, and execution point in, the currently selected message, and inspectors on both the receiver of the currently selected message, and the variables in the current context.

Special note on recursive errors:
Some errors affect Squeak's ability to present a debugger. This is normally an unrecoverable situation. However, if such an error occurs in an isolation layer, Squeak will attempt to exit from the isolation layer and then present a debugger. Here is the chain of events in such a recovery.

* A recursive error is detected.
* The current project is queried for an isolationHead
* Changes in the isolationHead are revoked
* The parent project of isolated project is returned to
* The debugger is opened there and execution resumes.

If the user closes that debugger, execution continues in the outer project and layer. If, after repairing some damage, the user proceeds from the debugger, then the isolationHead is re-invoked, the failed project is re-entered, and execution resumes in that world.


In September 2019, we added MorphicDebugger and MVCDebugger to untangle framework-specific features in our debugger infrastructure. However, this is just an intermediate step. The overall goal would be to remove those two subclasses again while preserving their functionality. Mostly, MVC and Morphic differ in their GUI-process management. This means that "proceed" and "close" work differently depending on the process that is being debugged. --- One idea is to attach that framework-specific information to the process objects. See Process >> #environmentAt: and #environmentAt:put:. Also see ToolSet's #handle* and #debug* methods.!
+ Debugger class
+ instanceVariableNames: 'openInstances'!

Item was added:
+ ----- Method: Debugger class>>checkDebuggerFlood (in category 'opening') -----
+ checkDebuggerFlood
+ "See if I am trying to open many debugger windows very quickly.
+ When flooding is detected the current project is suspended so the user can attempt to recover their image. See #recursiveError:."
+ openInstances ifNil: [openInstances := 0].
+ openInstances <= self maximumOpenDebuggers
+ ifTrue: [|proc|
+ openInstances := openInstances + 1.
+ proc := nil.
+ proc := [
+ (Delay forSeconds: 3) wait.
+ openInstances := openInstances - 1 max: 0.
+ proc terminate] newProcess.
+ proc priority: Processor lowIOPriority.
+ proc resume.
+ Processor yield]
+ ifFalse: [openInstances := 0. Project current recursiveError: 'Debugger Flooding Detected']!

Item was changed:
----- Method: Debugger class>>initialize (in category 'class initialization') -----
ContextStackKeystrokes := Dictionary new
at: $e put: #send;
at: $t put: #doStep;
at: $T put: #stepIntoBlock;
at: $p put: #proceed;
at: $r put: #restart;
at: $f put: #fullStack;
at: $w put: #where;
+ SavedExtent := self new initialExtent.
+ openInstances := 0.
- SavedExtent := self new initialExtent

"Debugger initialize"!

Item was added:
+ ----- Method: Debugger class>>maximumOpenDebuggers (in category 'preferences') -----
+ maximumOpenDebuggers
+ category: 'debug'
+ description: 'Limit the number of debugger windows that can be opened within a 3 second sliding window. When the limit is reached the current project will be exited to either MVC (if in Morphic) or Morphic (if in MVC).
+ Recommended minimum is 5, also the default.'
+ type: #Integer>
+ ^MaximumOpenDebuggers ifNil: [5]!

Item was added:
+ ----- Method: Debugger class>>maximumOpenDebuggers: (in category 'preferences') -----
+ maximumOpenDebuggers: anInteger
+ self assert: anInteger >= 1 description: 'value must be 1 or higher'.
+ MaximumOpenDebuggers := anInteger!

Item was changed:
----- Method: Debugger class>>openOn:context:label:contents:fullView: (in category 'opening') -----
openOn: process context: context label: titleOrNil 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 := Processor activeProcess.
+ self checkDebuggerFlood.

"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].!

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20220427/f9f24c1f/attachment.html>

More information about the Squeak-dev mailing list