ProcessMonitor.st
author claus
Fri, 28 Oct 1994 04:31:16 +0100
changeset 49 6fe62433cfa3
parent 45 950b84ba89e6
child 52 7b48409ae088
permissions -rw-r--r--
*** empty log message ***

StandardSystemView subclass:#ProcessMonitor
	 instanceVariableNames:'listView processes listUpdateDelay updateDelay 
				updateBlock listUpdateBlock updateProcess hideDead
				runColor suspendedColor waitColor'
	 classVariableNames:''
	 poolDictionaries:''
	 category:'Interface-Tools'
!

!ProcessMonitor class methodsFor:'startup'!

open
    |m|

    m := self new.
    m label:'Process Monitor'.
    m icon:(Form fromFile:'PMonitor.icon' resolution:100).
    m minExtent:(100 @ 100).

    m open.
    ^ m

    "
     ProcessMonitor open
    "
! !

!ProcessMonitor methodsFor:'initialization'!

initialize
    |v menu|

    super initialize.

    hideDead := true.

    self extent:(font widthOf:'name/id                       state     prio   usedStack  maxStack')
		+ 40 @
		100.

    v := ScrollableView for:SelectionInListView in:self.
    v origin:0.0@0.0 corner:1.0@1.0.
    listView := v scrolledView.
    listView font:font.
    menu := (PopUpMenu 
		labels:#(
"/ hideDead functionality no longer needed; 
"/ since ProcSched knownProcesses only returns living ones
"/
"/                         '\c hide dead'
"/                         '-'
			 'inspect' 
			 'debug'  
			 '-'  
			 'resume'  
			 'suspend'  
			 'terminate'
			 '-'  
			 'raise prio'  
			 'lower prio'  
			)
	     selectors:#(
"/                         hideDead:
"/                         nil
			 inspectProcess  
			 debugProcess  
			 nil  
			 resumeProcess  
			 suspendProcess  
			 terminateProcess
			 nil  
			 raisePrio
			 lowerPrio
			)
		receiver:self
		     for:listView).
"/    menu checkToggleAt:#hideDead: put:hideDead.
    listView middleButtonMenu:menu. 

    listView multipleSelectOk:true.
    listView keyboardHandler:self.

    updateDelay := 0.5.
    listUpdateDelay := 5.

    "/ true 
    ProcessorScheduler isPureEventDriven
    ifTrue:[
	updateBlock := [self updateStatus].
	listUpdateBlock := [self updateList].
    ].

    device hasColors ifTrue:[
	runColor := Color green.
	suspendedColor := Color yellow.
	waitColor := Color red.
    ] ifFalse:[
	runColor := suspendedColor := waitColor := Color black
    ]

    "
     ProcessMonitor open
    "
!

realize
    super realize.

    updateBlock notNil ifTrue:[
	Processor addTimedBlock:updateBlock afterSeconds:updateDelay.
	Processor addTimedBlock:listUpdateBlock afterSeconds:listUpdateDelay.
    ] ifFalse:[
	updateProcess := [
	    "
	     every half second, the status is updated.
	     every 5 seconds, the list of processes is
	     built up again
	    "
	    [true] whileTrue:[
		1 to:9 do:[:i |
		    (Delay forSeconds:0.5) wait.
		    self updateStatus.
		].
		(Delay forSeconds:0.5) wait.
		self updateList.
	    ]
	]  forkAt:(Processor userSchedulingPriority + 1).
	updateProcess name:'process update'.
	"
	 raise my own priority
	"
	Processor activeProcess priority:(Processor userSchedulingPriority + 2)
    ].
    waitColor := waitColor on:device.
    runColor := runColor on:device.
    suspendedColor := suspendedColor on:device.
!

mapped
    super mapped.
    self updateStatus.
    self updateList.
! !

!ProcessMonitor methodsFor:'destroying'!

destroy
    updateBlock notNil ifTrue:[
	Processor removeTimedBlock:updateBlock.
	Processor removeTimedBlock:listUpdateBlock.
    ] ifFalse:[
	updateProcess terminate
    ].
    super destroy
! !

!ProcessMonitor methodsFor:'private'!

selectedProcessesDo:aBlock
    |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 ifTrue:[
		       aBlock value:p
		    ]
		]
	    ]
	]
    ] ifFalse:[
	nr := sel - 2.     "for headlines"
	nr notNil ifTrue:[
	    nr > 0 ifTrue:[
		p := processes at:nr.
		p notNil ifTrue:[
		   aBlock value:p
		]
	    ]
	]
    ].
! !

!ProcessMonitor methodsFor:'menu actions'!

hideDead:aBoolean
    hideDead := aBoolean
!

debugProcess
    self selectedProcessesDo:[:p |
       Debugger openOn:p
    ]
! 

inspectProcess
    self selectedProcessesDo:[:p |
       p inspect
    ]
! 

terminateProcess
    self selectedProcessesDo:[:p |
       p terminate
    ]
! 

resumeProcess
    self selectedProcessesDo:[:p |
       p resume
    ]
! 

suspendProcess
    self selectedProcessesDo:[:p |
       p suspend
    ]
! 

raisePrio
    self selectedProcessesDo:[:p |
       p priority:(p priority + 1)
    ]
! 

lowerPrio
    self selectedProcessesDo:[:p |
       p priority:(p priority - 1)
    ]
! !

!ProcessMonitor methodsFor:'events'!

canHandle:key
    ^ key == #InspectIt
!

keyPress:key x:x y:y
    key == #InspectIt ifTrue:[
	^ self inspectProcess.
    ].
    ^ super keyPress:key x:x y:y
! !

!ProcessMonitor methodsFor:'drawing'!

updateList
    "update list of processes"

    |newList|

    shown ifTrue:[
	(Smalltalk at:#SystemDebugging ifAbsent:[false]) ifTrue:[
	    newList := Process allInstances.
	] 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 addTimedBlock:listUpdateBlock afterSeconds:listUpdateDelay
    ].
!

updateStatus
    "update status display of processes"

    |oldList list line dIndex con interrupted|

    shown ifTrue:[
	oldList := listView list.
	processes notNil ifTrue:[
	    list := OrderedCollection new.
	    list add:'id   name                     state    prio   usedStack  totalStack'.
	    list add:'-------------------------------------------------------------------'.

	    interrupted := Processor interruptedProcess.

	    dIndex := 1.
	    1 to:processes size do:[:index |
		|aProcess nm st|

		aProcess := processes at:index.
		aProcess notNil ifTrue:[
		    (aProcess id notNil or:[hideDead not]) ifTrue:[
			line := aProcess id printStringPaddedTo:5.
			(nm := aProcess name) isNil ifFalse:[
			    nm := nm printString
			] ifTrue:[
			    nm := ' '
			].
			nm size >= 24 ifTrue:[
			    nm := (nm copyTo:23) , ' '
			] ifFalse:[
			    nm := (nm printStringPaddedTo:24).
			].
			line := line , nm.
			st := aProcess state.
			(st == #run
			 and:[aProcess == interrupted]) ifTrue:[
			    line := line , '*' , (st printStringPaddedTo:9).
			] ifFalse:[
			    line := line , ' ' , (st printStringPaddedTo:9).
			].
			line := line , (aProcess priority printStringLeftPaddedTo:3).
			line := line , (aProcess usedStackSize printStringLeftPaddedTo:11).
			line := line , (aProcess totalStackSize printStringLeftPaddedTo:10).
			line := line , '(' , aProcess numberOfStackSegments printString , ')'.
			(Smalltalk at:#SystemDebugging ifAbsent:[false]) ifTrue:[
			    con := aProcess suspendedContext.
			    con isNil ifTrue:[
				aProcess == Processor activeProcess ifTrue:[
				    con := thisContext
				]
			    ].
			    con notNil ifTrue:[
				line := line , '    '.
				line := line , ((ObjectMemory addressOf:con) printStringRadix:16).
				line := line , ' .. '.
				[con sender notNil] whileTrue:[
				    con := con sender
				].
				line := line , ((ObjectMemory addressOf:con) printStringRadix:16).
			    ]
			].
			list add:line.
			processes at:dIndex put:aProcess.
			dIndex := dIndex + 1
		    ]
		].
	    ].
	    dIndex to:processes size do:[:index |
		processes at:index put:nil
	    ]
	].
	list ~= oldList ifTrue:[
	    "avoid flicker"
	    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.
	    ]
	].
    ].
    updateBlock notNil ifTrue:[
	Processor addTimedBlock:updateBlock afterSeconds:updateDelay
    ]
! !