"
COPYRIGHT (c) 1993 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
SystemStatusMonitor subclass:#ProcessMonitor
instanceVariableNames:'processes hideDead runColor suspendedColor waitColor cpuUsages
showDetail'
classVariableNames:''
poolDictionaries:''
category:'Interface-Tools'
!
!ProcessMonitor class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 1993 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
documentation
"
This view shows smalltalks (light-weight) processes, and also offers
a popup menu for various useful operations on them.
Especially 'debug' is useful, to see what a process is currently
doing.
The information shown is:
id - the numeric id of the process
name - the name (if any) of the process
(the name has no semantic meaning; it exists for the processMonitor only)
state - what is it doing;
wait - waiting on a semaphore
eventWait - waiting on a view-event semaphore
ioWait - waiting on an io-semaphore
timeWait - waiting for a time-semaphore
run - run, but currently not scheduled
active - really running (this info is useless, since at
update time, its always the update process which is
running)
suspended - suspended; not waiting on a semaphore
light - not yet started (i.e. has no stack yet)
prio - the processes priority (1..30)
usedStack - the current stack use
totalStack - the stack currently allocated (i.e. the maximum ever needed)
[see also:]
Process ProcessorScheduler
WindowGroup
SemaphoreMonitor
[author:]
Claus Gittinger
[start with:]
ProcessMonitor open
"
! !
!ProcessMonitor class methodsFor:'defaults'!
defaultIcon
|i|
i := Image fromFile:'ProcMon.xbm'.
i notNil ifTrue:[^ i].
^ super defaultIcon
"Modified: 23.1.1997 / 02:52:31 / cg"
!
defaultLabel
^ 'Process Monitor'
! !
!ProcessMonitor methodsFor:'drawing'!
titleLine
showDetail ifTrue:[
^ 'id group name state prio usedStack totalStack current-segment switch where'.
].
^ 'id group name state prio usedStack where'.
"Modified: 3.7.1996 / 13:57:38 / stefan"
"Modified: 24.7.1996 / 17:21:15 / cg"
!
updateList
"update list of processes"
|newList|
shown ifTrue:[
showDetail ifTrue:[
newList := Process allInstances asOrderedCollection.
] ifFalse:[
newList := ProcessorScheduler knownProcesses asOrderedCollection.
].
"sort by id - take care of nil ids of dead processes"
newList sort:[:p1 :p2 |
|id1 id2|
(p1 isNil or:[(id1 := p1 id) isNil])
ifTrue:[true]
ifFalse:[
(p2 isNil or:[(id2 := p2 id) isNil])
ifTrue:[false]
ifFalse:[id1 < id2]
]
].
newList ~= processes ifTrue:[
processes := WeakArray withAll:newList.
self updateStatus
].
].
updateBlock notNil ifTrue:[
Processor removeTimedBlock:listUpdateBlock.
Processor addTimedBlock:listUpdateBlock afterSeconds:listUpdateDelay
].
"Modified: 3.7.1996 / 13:37:29 / stefan"
!
updateStatus
"update status display of processes"
|oldList list line dIndex interrupted
aProcess nm st n found running sel space|
space := Character space.
shown ifTrue:[
oldList := listView list.
processes notNil ifTrue:[
list := OrderedCollection new:(processes size + 2).
list add:self titleLine.
list add:(String new:self titleLine size withAll:$-).
interrupted := Processor interruptedProcess.
dIndex := 1.
1 to:processes size do:[:index |
|con c totalStack sender id gId|
aProcess := processes at:index.
(aProcess notNil
and:[aProcess ~~ 0]) ifTrue:[
((id := aProcess id) notNil or:[hideDead not]) ifTrue:[
line := WriteStream on:(String new:200).
id printOn:line paddedTo:5.
gId := aProcess processGroupId.
gId == id ifTrue:[
"/ a group leader
'- ' printOn:line.
] ifFalse:[
gId printOn:line paddedTo:5.
].
(nm := aProcess name) isNil ifFalse:[
nm := nm printStringPaddedTo:28.
nm size >= 29 ifTrue:[
nm := (nm contractTo:28).
].
line nextPutAll:nm; nextPut:space.
] ifTrue:[
line next:29 put:space.
].
"/ n := cpuUsages at:(id) ifAbsent:[0].
"/ n ~~ 0 ifTrue:[
"/ line := line , ((n * 4) printStringLeftPaddedTo:3)
"/ ] ifFalse:[
"/ line := line , ' '
"/ ].
st := aProcess state.
(st == #run
and:[aProcess == interrupted]) ifTrue:[
c := ' *'.
running := true.
] ifFalse:[
c := ' '.
running := false.
].
line nextPutAll:c; nextPutAll:(st printStringPaddedTo:9).
line nextPutAll:(aProcess priority printStringLeftPaddedTo:3).
line nextPutAll:(aProcess usedStackSize printStringLeftPaddedTo:11).
con := aProcess suspendedContext.
con isNil ifTrue:[
aProcess == Processor activeProcess ifTrue:[
con := thisContext
]
].
showDetail ifTrue:[
id == 0 ifTrue:[
line nextPutAll:('unlimited' leftPaddedTo:13).
] ifFalse:[
n := aProcess numberOfStackSegments.
line nextPutAll:(aProcess totalStackSize printStringLeftPaddedTo:10).
line nextPut:$( ; nextPutAll:n printString; nextPut:$).
].
con notNil ifTrue:[
line nextPutAll:' '.
line nextPutAll:(((ObjectMemory addressOf:con) printStringRadix:16) leftPaddedTo:8 with:$0).
line nextPutAll:' .. '.
c := con.
[(sender := c sender) notNil] whileTrue:[
c := sender
].
line nextPutAll:(((ObjectMemory addressOf:c) printStringRadix:16) leftPaddedTo:8 with:$0).
] ifFalse:[
line next:20 put:space.
].
line nextPut:space.
line nextPutAll:(aProcess numberOfStackBoundaryHits printStringLeftPaddedTo:6).
].
con notNil ifTrue:[
c := con.
found := false.
running ifFalse:[
"/ search for a semaphore-wait in the top 10 contexts
1 to:10 do:[:n |
found ifFalse:[
c notNil ifTrue:[
(c receiver class == Semaphore) ifTrue:[
c selector == #wait ifTrue:[
found := true.
]
].
c := c sender.
]
]
].
].
found ifFalse:[
"/ search for a non-processor receiver in the top 10 contexts
c := con.
1 to:10 do:[:n |
|r|
found ifFalse:[
c notNil ifTrue:[
((r := c receiver) ~~ Processor
and:[r class ~~ Process]) ifTrue:[
found := true.
] ifFalse:[
c := c sender.
]
]
]
]
].
found ifFalse:[
c := con
].
[c notNil and:[c isBlockContext]] whileTrue:[
c := c home
].
c notNil ifTrue:[
sel := c selector.
sel isNil ifTrue:[
sel := '* unknown *'
].
line nextPutAll:' '.
line nextPutAll:c receiver class name.
line nextPutAll:'>>'; nextPutAll:sel.
]
].
list add:line contents.
processes at:dIndex put:aProcess.
dIndex := dIndex + 1
]
].
].
dIndex to:processes size do:[:index |
processes at:index put:nil
]
].
"avoid flicker"
(oldList notNil and:[oldList size == list size]) ifTrue:[
list keysAndValuesDo:[:idx :entry |
(oldList at:idx) ~= entry ifTrue:[
listView at:idx put:entry
]
]
] ifFalse:[
listView setList:list.
"the first two entries cannot be selected"
listView attributeAt:1 put:#disabled.
listView attributeAt:2 put:#disabled.
].
listView flush
].
updateBlock notNil ifTrue:[
Processor removeTimedBlock:updateBlock.
Processor addTimedBlock:updateBlock afterSeconds:updateDelay
]
"Modified: 3.7.1996 / 13:56:01 / stefan"
"Modified: 18.7.1996 / 20:19:59 / cg"
! !
!ProcessMonitor methodsFor:'initialization'!
initialize
super initialize.
hideDead := true.
showDetail := Smalltalk at:#SystemDebugging ifAbsent:false.
device hasColors ifTrue:[
runColor := Color green.
suspendedColor := Color yellow.
waitColor := Color red.
] ifFalse:[
runColor := suspendedColor := waitColor := Color black
].
"
ProcessMonitor open
"
"Modified: 23.1.1997 / 02:51:38 / cg"
!
realize
waitColor := waitColor on:device.
runColor := runColor on:device.
suspendedColor := suspendedColor on:device.
super realize.
"Modified: 23.1.1997 / 02:30:37 / cg"
! !
!ProcessMonitor methodsFor:'menu actions'!
abortProcess
"abort (raise AbortSignal in) the selected process"
self selectedProcessesDo:[:p |
p interruptWith:[AbortSignal raise]
]
!
debugProcess
"open a debugger on the selected process"
self selectedProcessesDo:[:p |
Debugger openOn:p
]
!
hideDead:aBoolean
"turn on/off hiding of dead (already terminated) processes"
hideDead := aBoolean
"Modified: 23.1.1997 / 02:34:01 / cg"
!
inspectSelection
"open an inspector on the selected process"
self selectedProcessesSend:#inspect
"Created: 23.1.1997 / 02:27:33 / cg"
!
lowerPrio
"lower the selected processes priority"
self selectedProcessesDo:[:p |
p priority:(p priority - 1)
]
!
raisePrio
"raise the selected processes priority"
self selectedProcessesDo:[:p |
p priority:(p priority + 1)
]
!
restartProcess
"abort (raise AbortSignal in) the selected process"
self selectedProcessesDo:[:p |
p restart.
]
!
resumeProcess
"resume the selected process (i.e. let it run) "
self selectedProcessesSend:#resume
!
statusMenu
"return a popUpMenu"
|labels selectors m sel allRestartable|
device ctrlDown ifTrue:[
labels := resources array:#(
'\c detail'
).
selectors := #(
tiggleDetail
).
] ifFalse:[
labels := resources array:#(
'inspect'
'debug'
'-'
'resume'
'suspend'
'stop'
'abort'
'terminate'
'terminate group'
'restart'
'-'
'raise prio'
'lower prio'
).
selectors := #(
inspectSelection
debugProcess
nil
resumeProcess
suspendProcess
stopProcess
abortProcess
terminateProcess
terminateProcessGroup
restartProcess
nil
raisePrio
lowerPrio
).
updateProcess isNil ifTrue:[
labels := (resources array:#('update' '-')) , labels.
selectors := #(updateView nil) , selectors
].
].
m := PopUpMenu labels:labels
selectors:selectors.
listView hasSelection ifFalse:[
m disableAll:#(
inspectSelection
debugProcess
resumeProcess
suspendProcess
stopProcess
restartProcess
abortProcess
terminateProcess
terminateProcessGroup
raisePrio
lowerPrio
)
] ifTrue:[
allRestartable := true.
self selectedProcessesDo:[:p |
p isRestartable ifFalse:[
allRestartable := false
].
].
allRestartable ifFalse:[
m disable:#restartProcess
].
].
m checkToggleAt:#toggleDetail put:showDetail.
^ m
"Created: 23.1.1997 / 03:05:54 / cg"
"Modified: 23.1.1997 / 03:10:09 / cg"
!
stopProcess
"stop the selected process - not even interrupts will wake it up"
self selectedProcessesSend:#stop
!
suspendProcess
"suspend the selected process - interrupts will let it run again"
self selectedProcessesSend:#suspend
!
terminateProcess
"terminate the selected process"
self selectedProcessesSend:#terminate
!
terminateProcessGroup
"terminate the selected process with all of its subprocesses"
self selectedProcessesSend:#terminateGroup
!
toggleDetail
"toggle detail"
showDetail := showDetail not.
self updateView
"Modified: 23.1.1997 / 02:33:03 / cg"
"Created: 23.1.1997 / 02:33:30 / cg"
! !
!ProcessMonitor methodsFor:'private'!
selectedProcessesDo:aBlock
"evaluate aBlock on all selected processes"
|p nr sel|
sel := listView selection.
sel isNil ifTrue:[^ self].
(sel isKindOf:Collection) ifTrue:[
sel do:[:n |
nr := n - 2. "for headlines"
nr notNil ifTrue:[
nr > 0 ifTrue:[
p := processes at:nr.
(p notNil and:[p ~~ 0]) ifTrue:[
aBlock value:p
]
]
]
]
] ifFalse:[
nr := sel - 2. "for headlines"
nr notNil ifTrue:[
nr > 0 ifTrue:[
p := processes at:nr.
(p notNil and:[p ~~ 0]) ifTrue:[
aBlock value:p
]
]
]
].
"Modified: 23.1.1997 / 03:10:53 / cg"
!
selectedProcessesSend:aSelector
"send a message to all selected processes"
self selectedProcessesDo:[:p |
p perform:aSelector
].
self updateView.
"Modified: 23.1.1997 / 02:34:49 / cg"
! !
!ProcessMonitor methodsFor:'user actions'!
doubleClicked
"open a debugger on the selected process"
self debugProcess
"Created: 23.1.1997 / 03:21:30 / cg"
! !
!ProcessMonitor class methodsFor:'documentation'!
version
^ '$Header: /cvs/stx/stx/libtool/ProcessMonitor.st,v 1.46 1997-01-23 02:37:05 cg Exp $'! !