[squeak-dev] Re: The broken user interrupt, or the saga of 100000 factorial.

Eliot Miranda eliot.miranda at gmail.com
Fri Dec 16 17:40:42 UTC 2011


Hi Andreas,

On Thu, Dec 15, 2011 at 11:00 PM, Andreas Raab <andreas.raab at gmx.de> wrote:

> On 12/16/2011 3:33, Levente Uzonyi wrote:
>
>> On Thu, 15 Dec 2011, Christopher Oliver wrote:
>>
>>  On Thu, 15 Dec 2011 11:35:55 +0100
>>> I added a tty output debug to
>>> MorphicProject>>interruptName:**preemptedProcess:, and I found
>>> that Processor>>preemptedProcess occasionally answers the system weak
>>> array finalization process. Yikes! This isn't what we want to debug at
>>> all. Are we being adequately clever
>>> in determining which process to debug?
>>>
>>
>> I'm pretty sure that the currently running process is interrupted. After
>> GC (which happens often during calculations with LargeIntegers) this is
>> likely to be the finalization process.
>>
>
> Correct. To make matters worse, when an interrupt is signaled in the midst
> of GC, the signal will be delivered after the GC cycle completes, therefore
> almost guaranteeing that the interrupted process will be the finalization
> process.
>
> And so the determination of the process to be interrupted is moderately
> stupid. What we'd really need to do is to start a slightly leaner version
> of CPUWatcher, i.e., instead of blindly interrupting whatever process is
> active, start sampling the running processes and after a short while
> (100-500 ms) decide which process to kick[*]. Plus, after that ensure that
> the UI is actually responsive so that the user can interact with the system
> and if not, keep kicking processes unless the system becomes interactive
> again. Alas, not a trivial task to be solved.
>
> [*] A more radical version would suspend *all* user processes and let the
> user decide which of the suspended processes to inspect. This might have
> some interesting side effects though...
>

it's smetimes helpful to look at other systems' approaches.  In VisualWorks
there is no special interrupt handling in the VM; the keyboard event comes
in like any other:

keyAt: keyNumber character: aCharacter alternative: alternativeCharacter
down: isDownTransition
"A keyboard key has been pressed or released; take appropriate action"

| keyboardEvent |
(self state isModifierKey: aCharacter) ifTrue: [^self].
(self *allProcessInterruptMatchesCharacter*: aCharacter
inTransition: isDownTransition)
ifTrue:
[^(#{CraftedSmalltalk.DebuggerService} valueOrDo: [Processor])
*interruptAllUserProcesses*].
(self warpToLauncherMatchesCharacter: aCharacter
inTransition: isDownTransition)
ifTrue:
[^#{VisualLauncher} ifDefinedDo: [:launcherClass | launcherClass
raiseOrOpen]].
(aCharacter = self state class *interruptKeyValue* and: [isDownTransition])
ifTrue:
[(self state *shiftDown* or: [(keyNumber bitAnd: 256) ~= 0])
ifTrue: [[*EmergencyWindow open*] fork]
ifFalse:
[(#{CraftedSmalltalk.DebuggerService} valueOrDo: [Processor])
*interruptActiveUserProcess*]]
ifFalse:
[isDownTransition
ifTrue: [keyboardEvent := KeyPressedEvent new]
ifFalse: [keyboardEvent := KeyReleasedEvent new].
keyboardEvent := keyboardEvent
code: aCharacter
meta: (self state metaState bitOr: (keyNumber bitShift: -8))
alternative: alternativeCharacter.
self addMetaInput: (keyboardEvent window: window)]

further, UserInterrupt is a signal that can be handled, and there is some
special interpretation applied before raising that signal:

ProcessorScheduler>>interruptActiveUserProcess

| proc deb |
proc := self runableProcesses
detect: [:p | p isSystemProcess not]
ifNone: [nil].
(proc isNil and: [Window currentWindow notNil])
ifTrue: [proc := Window currentWindow windowProcess].
proc isNil
ifTrue: [^self interruptAllUserProcesses].
(deb := proc environmentAt: #debugger) notNil
ifTrue: [^deb abortDebugOperationInProcess: proc].
proc isUnderDebug
ifTrue: [^DebuggerService abortDebuggingFor: proc].
proc interruptWith:
[Object userInterruptSignal
interruptWith: thisContext sender sender
errorString: (#exceptUserInterrupt << #dialogs >> 'User Interrupt')]

DebuggerService class>>interruptActiveUserProcess
| proc |
proc := self getActiveUserProcess.
proc isNil
ifTrue: [proc := self getCurrentWindowProcess].
proc isNil
ifTrue: [^self interruptAllUserProcesses].
proc isUnderDebug
ifTrue: [^proc debugger abortDebugOperationInProcess: proc].
proc interruptWith:
[Object userInterruptSignal
interruptWith: thisContext sender sender
errorString: (#UserInterrupt << #pdp >> 'User Interrupt')]

This is a variation on having a smarter Processor>>preemptedProcess.  It
seems to me that using the GUI to select the active process makes sense,
that when using the debugger, interrupting simulation makes sense, and that
making UserInterrupt a signal is a really, really good thing, especially
for deploying applications.


> Cheers,
>  - Andreas

-- 
best,
Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20111216/e0b6397a/attachment.htm


More information about the Squeak-dev mailing list