# HG changeset patch # User penk # Date 1043162258 -3600 # Node ID 99d11fbee2af5d6d5264667ec62c0063bf2632cf # Parent b14fcc67ff8e303a4f5a864b0adcb6fea13a29b2 initial checkin diff -r b14fcc67ff8e -r 99d11fbee2af ProcessMonitorV2.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ProcessMonitorV2.st Tue Jan 21 16:17:38 2003 +0100 @@ -0,0 +1,1787 @@ +"{ Package: 'stx:libtool' }" + +SystemStatusMonitorV2 subclass:#ProcessMonitorV2 + instanceVariableNames:'processList tableColumns selectedProcesses updateSema showDetail + hasSelection selctionRestartable showProcessId showGroup + showState showPrio showUsedStack showTotalStack + showCurrentSegment showSwitch showWhere currentSortOrder + processTable processes showDead sortBlock selectionRestartable' + classVariableNames:'' + poolDictionaries:'' + category:'Monitors-ST/X' +! + +Object subclass:#ProcessItem + instanceVariableNames:'processId processGroup processName processState processPrio + processUsedStack processTotalStack processWhere processInstance + processCurrentSegment processSwitch prioVal idVal groupVal' + classVariableNames:'' + poolDictionaries:'' + privateIn:ProcessMonitorV2 +! + +!ProcessMonitorV2 class methodsFor:'documentation'! + +documentation +" + documentation to be added. + + [author:] + Christian Penk (penk@bierfix) + + [instance variables:] + + [class variables:] + + [see also:] + +" +! + +examples +" + Starting the application: + [exBegin] + ProcessMonitorV2 open + + [exEnd] + + more examples to be added: + [exBegin] + ... add code fragment for + ... executable example here ... + [exEnd] +" +! + +history + "Created: / 14.1.2003 / 11:16:10 / penk" +! ! + +!ProcessMonitorV2 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' +! ! + +!ProcessMonitorV2 class methodsFor:'help specs'! + +helpSpec + "This resource specification was automatically generated + by the UIHelpTool of ST/X." + + "Do not manually edit this!! If it is corrupted, + the UIHelpTool may not be able to read the specification." + + " + UIHelpTool openOnClass:ProcessMonitorV2 + " + + + + ^ super helpSpec addPairsFrom:#( + +#toggleDetails +'' + +) +! ! + +!ProcessMonitorV2 class methodsFor:'image specs'! + +detailsMenuIconDown + "This resource specification was automatically generated + by the ImageEditor of ST/X." + + "Do not manually edit this!! If it is corrupted, + the ImageEditor may not be able to read the specification." + + " + self detailsMenuIconDown inspect + ImageEditor openOnClass:self andSelector:#detailsMenuIconDown + Icon flushCachedIcons + " + + + + ^Icon + constantNamed:#'ProcessMonitorV2 class detailsMenuIconDown' + ifAbsentPut:[(Depth1Image new) width: 7; height: 5; photometric:(#palette); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@b') ; colorMapFromArray:#[0 0 0 255 255 255]; mask:((Depth1Image new) width: 7; height: 5; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@A@(UJ(b') ; yourself); yourself] +! + +detailsMenuIconUp + "This resource specification was automatically generated + by the ImageEditor of ST/X." + + "Do not manually edit this!! If it is corrupted, + the ImageEditor may not be able to read the specification." + + " + self detailsMenuIconUp inspect + ImageEditor openOnClass:self andSelector:#detailsMenuIconUp + Icon flushCachedIcons + " + + + + ^Icon + constantNamed:#'ProcessMonitorV2 class detailsMenuIconUp' + ifAbsentPut:[(Depth1Image new) width: 7; height: 5; photometric:(#palette); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@b') ; colorMapFromArray:#[0 0 0 255 255 255]; mask:((Depth1Image new) width: 7; height: 5; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'*%P(D@@b') ; yourself); yourself] +! + +viewDetailsIcon + "This resource specification was automatically generated + by the ImageEditor of ST/X." + + "Do not manually edit this!! If it is corrupted, + the ImageEditor may not be able to read the specification." + + " + self viewDetailsIcon inspect + ImageEditor openOnClass:self andSelector:#viewDetailsIcon + Icon flushCachedIcons + " + + + + ^Icon + constantNamed:#'ProcessMonitorV2 class viewDetailsIcon' + ifAbsentPut:[(Depth1Image new) width: 16; height: 16; photometric:(#palette); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@b') ; colorMapFromArray:#[0 0 0 255 255 255]; mask:((Depth1Image new) width: 16; height: 16; photometric:(#blackIs0); bitsPerSample:(#(1 )); samplesPerPixel:(1); bits:(ByteArray fromPackedString:'@@@@@@@@]+X@@@@@]+X@@@@@]+X@@@@@]+X@@@@@@@@b') ; yourself); yourself] +! ! + +!ProcessMonitorV2 class methodsFor:'interface specs'! + +windowSpec + "This resource specification was automatically generated + by the UIPainter of ST/X." + + "Do not manually edit this!! If it is corrupted, + the UIPainter may not be able to read the specification." + + " + UIPainter new openOnClass:ProcessMonitorV2 andSelector:#windowSpec + ProcessMonitorV2 new openInterface:#windowSpec + ProcessMonitorV2 open + " + + + + ^ + #(#FullSpec + #name: #windowSpec + #window: + #(#WindowSpec + #label: 'ProcessMonitorV2' + #name: 'ProcessMonitorV2' + #min: #(#Point 10 10) + #max: #(#Point 1024 768) + #bounds: #(#Rectangle 16 42 781 379) + #menu: #mainMenu + ) + #component: + #(#SpecCollection + #collection: #( + #(#MenuPanelSpec + #name: 'ToolBar1' + #layout: #(#LayoutFrame 0 0.0 0 0 0 1.0 32 0) + #menu: #toolBarMainMenu + #textDefault: true + ) + #(#DataSetSpec + #name: 'Process Table' + #layout: #(#LayoutFrame 0 0.0 32 0.0 0 1.0 0 1.0) + #model: #selectedProcesses + #menu: #tableMenu + #hasHorizontalScrollBar: true + #hasVerticalScrollBar: true + #dataList: #processList + #useIndex: false + #has3Dsepartors: false + #doubleClickSelector: #doubleClickedAt: + #columnHolder: #tableColumns + #multipleSelectOk: true + #verticalSpacing: 0 + #postBuildCallback: #postBuildProcessTable: + ) + ) + + ) + ) +! ! + +!ProcessMonitorV2 class methodsFor:'menu specs'! + +mainMenu + "This resource specification was automatically generated + by the MenuEditor of ST/X." + + "Do not manually edit this!! If it is corrupted, + the MenuEditor may not be able to read the specification." + + " + MenuEditor new openOnClass:ProcessMonitorV2 andSelector:#mainMenu + (Menu new fromLiteralArrayEncoding:(ProcessMonitorV2 mainMenu)) startUp + " + + + + ^ + #(#Menu + #( + #(#MenuItem + #label: 'Exit' + #itemValue: #closeRequest + #translateLabel: true + ) + #(#MenuItem + #label: 'Help' + #translateLabel: true + #startGroup: #right + #submenu: + #(#Menu + #( + #(#MenuItem + #label: 'Documentation' + #itemValue: #openDocumentation + #translateLabel: true + ) + #(#MenuItem + #label: '-' + ) + #(#MenuItem + #label: 'About this Application' + #itemValue: #openAboutThisApplication + #translateLabel: true + ) + ) + nil + nil + ) + ) + ) + nil + nil + ) +! + +tableMenu + "This resource specification was automatically generated + by the MenuEditor of ST/X." + + "Do not manually edit this!! If it is corrupted, + the MenuEditor may not be able to read the specification." + + " + MenuEditor new openOnClass:ProcessMonitorV2 andSelector:#tableMenu + (Menu new fromLiteralArrayEncoding:(ProcessMonitorV2 tableMenu)) startUp + " + + + + ^ + #(#Menu + #( + #(#MenuItem + #enabled: #hasSelection + #label: 'Inspect' + #itemValue: #inspectSelection + #translateLabel: true + ) + #(#MenuItem + #enabled: #hasSelection + #label: 'Debug' + #itemValue: #debugProcess + #translateLabel: true + ) + #(#MenuItem + #label: '-' + ) + #(#MenuItem + #enabled: #hasSelection + #label: 'Resume' + #itemValue: #resumeProcess + #translateLabel: true + ) + #(#MenuItem + #enabled: #hasSelection + #label: 'Suspend' + #itemValue: #suspendProcess + #translateLabel: true + ) + #(#MenuItem + #enabled: #hasSelection + #label: 'Stop' + #itemValue: #stopProcess + #translateLabel: true + ) + #(#MenuItem + #label: '-' + ) + #(#MenuItem + #enabled: #hasSelection + #label: 'Abort' + #itemValue: #abortProcess + #translateLabel: true + ) + #(#MenuItem + #enabled: #hasSelection + #label: 'Terminate' + #itemValue: #terminateProcess + #translateLabel: true + ) + #(#MenuItem + #enabled: #hasSelection + #label: 'Hard Terminate' + #itemValue: #hardTerminateProcess + #translateLabel: true + ) + #(#MenuItem + #enabled: #hasSelection + #label: 'Terminate Group' + #itemValue: #terminateProcessGroup + #translateLabel: true + ) + #(#MenuItem + #enabled: #selectionRestartable + #label: 'Restart' + #itemValue: #restartProcess + #translateLabel: true + ) + #(#MenuItem + #label: '-' + ) + #(#MenuItem + #enabled: #hasSelection + #label: 'Raise Prio' + #itemValue: #raisePrio + #translateLabel: true + ) + #(#MenuItem + #enabled: #hasSelection + #label: 'Lower Prio' + #itemValue: #lowerPrio + #translateLabel: true + ) + #(#MenuItem + #label: '-' + ) + #(#MenuItem + #label: 'Update' + #itemValue: #updateView + #translateLabel: true + ) + ) + nil + nil + ) +! + +toolBarMainMenu + "This resource specification was automatically generated + by the MenuEditor of ST/X." + + "Do not manually edit this!! If it is corrupted, + the MenuEditor may not be able to read the specification." + + " + MenuEditor new openOnClass:ProcessMonitorV2 andSelector:#toolBarMainMenu + (Menu new fromLiteralArrayEncoding:(ProcessMonitorV2 toolBarMainMenu)) startUp + " + + + + ^ + #(#Menu + #( + #(#MenuItem + #enabled: #hasSelection + #label: 'Inspect' + #itemValue: #inspectSelection + #translateLabel: true + #isButton: true + #labelImage: #(#ResourceRetriever #SystemBrowser #watchIcon) + ) + #(#MenuItem + #activeHelpKey: #toggleDetails + #label: 'View Details' + #translateLabel: true + #isButton: true + #startGroup: #right + #submenuChannel: #viewDetailsMenuSpec + #labelImage: #(#ResourceRetriever #ProcessMonitorV2 #viewDetailsIcon) + ) + ) + nil + nil + ) +! + +viewDetailsMenuSpec + "This resource specification was automatically generated + by the MenuEditor of ST/X." + + "Do not manually edit this!! If it is corrupted, + the MenuEditor may not be able to read the specification." + + " + MenuEditor new openOnClass:ProcessMonitorV2 andSelector:#viewDetailsMenuSpec + (Menu new fromLiteralArrayEncoding:(ProcessMonitorV2 viewDetailsMenuSpec)) startUp + " + + + + ^ + #(#Menu + #( + #(#MenuItem + #label: 'Id' + #translateLabel: true + #hideMenuOnActivated: false + #indication: #showProcessId + ) + #(#MenuItem + #label: 'Group' + #translateLabel: true + #hideMenuOnActivated: false + #indication: #showGroup + ) + #(#MenuItem + #label: 'State' + #translateLabel: true + #hideMenuOnActivated: false + #indication: #showState + ) + #(#MenuItem + #label: 'Prio' + #translateLabel: true + #hideMenuOnActivated: false + #indication: #showPrio + ) + #(#MenuItem + #label: 'Used Stack' + #translateLabel: true + #hideMenuOnActivated: false + #indication: #showUsedStack + ) + #(#MenuItem + #label: 'Total Stack' + #translateLabel: true + #hideMenuOnActivated: false + #indication: #showTotalStack + ) + #(#MenuItem + #label: 'Current-Segment' + #translateLabel: true + #hideMenuOnActivated: false + #indication: #showCurrentSegment + ) + #(#MenuItem + #label: 'Switch' + #translateLabel: true + #hideMenuOnActivated: false + #indication: #showSwitch + ) + #(#MenuItem + #label: 'Where' + #translateLabel: true + #hideMenuOnActivated: false + #indication: #showWhere + ) + #(#MenuItem + #label: '-' + ) + #(#MenuItem + #label: 'Show dead Processes' + #translateLabel: true + #indication: #showDead + ) + ) + nil + nil + ) +! ! + +!ProcessMonitorV2 class methodsFor:'tableColumns specs'! + +tableColumns + "This resource specification was automatically generated + by the DataSetBuilder of ST/X." + + "Do not manually edit this!! If it is corrupted, + the DataSetBuilder may not be able to read the specification." + + " + DataSetBuilder new openOnClass:ProcessMonitorV2 andSelector:#tableColumns + " + + + + ^#( + #(#DataSetColumnSpec + #label: 'Id' + #id: #id + #labelAlignment: #left + #labelButtonType: #Button + #labelActionSelector: #sortProcessListBy: + #labelActionArgument: 'idVal' + #width: 45 + #type: #number + #model: #processId + #canSelect: false + #showRowSeparator: false + #showColSeparator: false + ) + #(#DataSetColumnSpec + #label: 'Group' + #id: #group + #labelAlignment: #left + #labelButtonType: #Button + #labelActionSelector: #sortProcessListBy: + #labelActionArgument: 'groupVal' + #width: 45 + #model: #processGroup + #canSelect: false + #showRowSeparator: false + #showColSeparator: false + ) + #(#DataSetColumnSpec + #label: 'Name' + #id: #name + #labelAlignment: #left + #labelButtonType: #Button + #labelActionSelector: #sortProcessListBy: + #labelActionArgument: 'processName' + #width: 200 + #model: #processName + #canSelect: false + #showRowSeparator: false + #showColSeparator: false + ) + #(#DataSetColumnSpec + #label: 'State' + #id: #state + #labelAlignment: #left + #labelButtonType: #Button + #labelActionSelector: #sortProcessListBy: + #labelActionArgument: 'processState' + #width: 100 + #model: #processState + #canSelect: false + #showRowSeparator: false + #showColSeparator: false + ) + #(#DataSetColumnSpec + #label: 'Prio' + #id: #prio + #labelAlignment: #left + #labelButtonType: #Button + #labelActionSelector: #sortProcessListBy: + #labelActionArgument: 'prioVal' + #width: 40 + #model: #processPrio + #canSelect: false + #showRowSeparator: false + #showColSeparator: false + ) + #(#DataSetColumnSpec + #label: 'Used Stack' + #id: #usedStack + #labelAlignment: #left + #labelButtonType: #Button + #labelActionSelector: #sortProcessListBy: + #labelActionArgument: 'processUsedStack' + #columnAlignment: #right + #width: 75 + #type: #number + #model: #processUsedStack + #canSelect: false + #showRowSeparator: false + #showColSeparator: false + ) + #(#DataSetColumnSpec + #label: 'Total Stack' + #id: #totalStack + #labelAlignment: #left + #labelButtonType: #Button + #labelActionSelector: #sortProcessListBy: + #labelActionArgument: 'processTotalStack' + #columnAlignment: #right + #width: 75 + #model: #processTotalStack + #canSelect: false + #showRowSeparator: false + #showColSeparator: false + ) + #(#DataSetColumnSpec + #label: 'Current-Segment' + #id: #currentSegment + #labelAlignment: #left + #labelButtonType: #Button + #labelActionSelector: #sortProcessListBy: + #labelActionArgument: 'processCurrentSegment' + #width: 110 + #model: #processCurrentSegment + #canSelect: false + #showRowSeparator: false + #showColSeparator: false + ) + #(#DataSetColumnSpec + #label: 'Switch' + #id: #switch + #labelAlignment: #left + #labelButtonType: #Button + #labelActionSelector: #sortProcessListBy: + #labelActionArgument: 'processSwitch' + #columnAlignment: #right + #width: 55 + #type: #number + #model: #processSwitch + #canSelect: false + #showRowSeparator: false + #showColSeparator: false + ) + #(#DataSetColumnSpec + #label: 'Where' + #id: #where + #labelAlignment: #left + #labelButtonType: #Button + #labelActionSelector: #sortProcessListBy: + #labelActionArgument: 'processWhere' + #model: #processWhere + #canSelect: false + #showRowSeparator: false + #showColSeparator: false + ) + ) + +! ! + +!ProcessMonitorV2 methodsFor:'actions'! + +doubleClickedAt:anItemIndex + "open a debugger on the selected process" + + self debugProcess +! + +getProcessList + "select processes to display. + Subclasses may redefine this" + + |coll| + + self needFullInformation ifTrue:[ + coll := Process allSubInstances asOrderedCollection. + ] ifFalse:[ + coll := ProcessorScheduler knownProcesses asOrderedCollection. + ]. + ^ coll +! + +selectedProcessesDo:aBlock + | sel| + + sel := self selectedProcesses value. + sel isNil ifTrue:[^ self]. + + sel do:[:processItem | + aBlock value:(processItem processInstance). + ] +! + +selectedProcessesSend:aSelector + "send a message to all selected processes" + + self selectedProcessesDo:[:p | + p perform:aSelector + ]. + self updateView. +! ! + +!ProcessMonitorV2 methodsFor:'aspects'! + +currentSortOrder + "return/create the 'currentSortOrder' value holder (automatically generated)" + + currentSortOrder isNil ifTrue:[ + currentSortOrder := Dictionary new asValue. + ]. + ^ currentSortOrder +! + +hasSelection + + hasSelection isNil ifTrue:[ + hasSelection := ValueHolder new. + ]. + ^ hasSelection +! + +processList + + processList isNil ifTrue:[ + processList := List new. + ]. + ^ processList. +! + +selectedProcesses + + selectedProcesses isNil ifTrue:[ + selectedProcesses := ValueHolder new. + selectedProcesses addDependent:self. + ]. + ^ selectedProcesses. +! + +selectionRestartable + + selectionRestartable isNil ifTrue:[ + selectionRestartable := ValueHolder new. + ]. + ^ selectionRestartable +! + +showDead + "return/create the 'showDead' value holder (automatically generated)" + + showDead isNil ifTrue:[ + showDead := false asValue. + showDead addDependent:self. + ]. + ^ showDead +! + +sortBlock + + sortBlock isNil ifTrue:[ + sortBlock := [:a :b | + a idVal < b idVal + ] + ]. + ^ sortBlock +! + +tableColumns + + tableColumns isNil ifTrue:[ + tableColumns := self class tableColumns asValue. + ]. + ^ tableColumns. +! ! + +!ProcessMonitorV2 methodsFor:'aspects column'! + +showCurrentSegment + "return/create the 'showCurrentSegment' value holder (automatically generated)" + + showCurrentSegment isNil ifTrue:[ + showCurrentSegment := showDetail asValue. + showCurrentSegment onChangeSend:#viewedColumnsChanged to:self. + ]. + ^ showCurrentSegment +! + +showGroup + "return/create the 'showGroup' value holder (automatically generated)" + + showGroup isNil ifTrue:[ + showGroup := true asValue. + showGroup onChangeSend:#viewedColumnsChanged to:self. + ]. + ^ showGroup +! + +showPrio + "return/create the 'showPrio' value holder (automatically generated)" + + showPrio isNil ifTrue:[ + showPrio := true asValue. + showPrio onChangeSend:#viewedColumnsChanged to:self. + ]. + ^ showPrio +! + +showProcessId + + showProcessId isNil ifTrue:[ + showProcessId := true asValue. + showProcessId onChangeSend:#viewedColumnsChanged to:self + ]. + ^ showProcessId +! + +showState + "return/create the 'showState' value holder (automatically generated)" + + showState isNil ifTrue:[ + showState := true asValue. + showState onChangeSend:#viewedColumnsChanged to:self + ]. + ^ showState +! + +showSwitch + "return/create the 'showSwitch' value holder (automatically generated)" + + showSwitch isNil ifTrue:[ + showSwitch := showDetail asValue. + showSwitch onChangeSend:#viewedColumnsChanged to:self + ]. + ^ showSwitch +! + +showTotalStack + "return/create the 'showTotalStack' value holder (automatically generated)" + + showTotalStack isNil ifTrue:[ + showTotalStack := showDetail asValue. + showTotalStack onChangeSend:#viewedColumnsChanged to:self + ]. + ^ showTotalStack +! + +showUsedStack + "return/create the 'showUsedStack' value holder (automatically generated)" + + showUsedStack isNil ifTrue:[ + showUsedStack := showDetail asValue. + showUsedStack onChangeSend:#viewedColumnsChanged to:self + ]. + ^ showUsedStack +! + +showWhere + "return/create the 'showWhere' value holder (automatically generated)" + + showWhere isNil ifTrue:[ + showWhere := true asValue. + showWhere onChangeSend:#viewedColumnsChanged to:self + ]. + ^ showWhere +! ! + +!ProcessMonitorV2 methodsFor:'change & update'! + +selectionChanged + + |allRestartable| + + self hasSelection value:(self selectedProcesses value notEmptyOrNil). + self hasSelection value ifFalse:[ + self selectionRestartable value:false. + ^ self + ]. + allRestartable := true. + self selectedProcessesDo:[:p | + p isRestartable ifFalse:[ + allRestartable := false + ]. + ]. + self selectionRestartable value:allRestartable. + ^ self. +! + +update:something with:aParameter from:changedObject + "Invoked when an object that I depend upon sends a change notification." + + "stub code automatically generated - please change as required" + + changedObject == self selectedProcesses ifTrue:[ + self selectionChanged. + ^ self + ]. + changedObject == self showDead ifTrue:[ + self updateStatus:nil. + ^ self + ]. + super update:something with:aParameter from:changedObject +! + +viewedColumnsChanged + + | columns buffer locCurrentSortOrder currentSortOrderColumn currentSortOrderReverse selection| + + selection := self selectedProcesses value. + columns := OrderedCollection new. + self class tableColumns do:[:el| + columns add:(DataSetColumnSpec new fromLiteralArrayEncoding:el). + ]. + buffer := columns copy. + locCurrentSortOrder := self currentSortOrder value. + currentSortOrderColumn := locCurrentSortOrder at:#column ifAbsent:nil. + currentSortOrderReverse := locCurrentSortOrder at:#reverse ifAbsent:nil. + buffer do:[:col | + | id | + id := col id. + id notNil ifTrue:[ + (col labelActionArgument notNil and:[col labelActionArgument asSymbol == currentSortOrderColumn]) ifTrue:[ + | label icon| + label := col label. + icon := currentSortOrderReverse ifTrue:[self class detailsMenuIconDown] ifFalse:[self class detailsMenuIconUp]. + col label:(LabelAndIcon label:label icon:icon). + ]. + (id == #id and:[self showProcessId value not]) ifTrue:[ + columns remove:col. + ] ifFalse:[ + (id == #group and:[self showGroup value not]) ifTrue:[ + columns remove:col. + ] ifFalse:[ + (id == #prio and:[self showPrio value not]) ifTrue:[ + columns remove:col. + ] ifFalse:[ + (id == #currentSegment and:[self showCurrentSegment value not]) ifTrue:[ + columns remove:col. + ] ifFalse:[ + (id == #state and:[self showState value not]) ifTrue:[ + columns remove:col. + ] ifFalse:[ + (id == #switch and:[self showSwitch value not]) ifTrue:[ + columns remove:col. + ] ifFalse:[ + (id == #totalStack and:[self showTotalStack value not]) ifTrue:[ + columns remove:col. + ] ifFalse:[ + (id == #usedStack and:[self showUsedStack value not]) ifTrue:[ + columns remove:col. + ] ifFalse:[ + (id == #where and:[self showWhere value not]) ifTrue:[ + columns remove:col. + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ]. + updateSema critical:[ + self tableColumns value:columns. + self selectedProcesses value:selection. + ]. + self updateList. +! ! + +!ProcessMonitorV2 methodsFor:'event handling'! + +processEvent:anEvent + "filter keyboard events. + Return true, if I have eaten the event" + + |focusView key rawKey| + + anEvent isKeyPressEvent ifTrue:[ + focusView := anEvent targetView. + key := anEvent key. + rawKey := anEvent rawKey. + + (focusView == processList) ifTrue:[ + key == #InspectIt ifTrue:[ + self inspectSelection. + ^ true. + ]. + ] + ]. + ^ false +! ! + +!ProcessMonitorV2 methodsFor:'initialization & release'! + +closeDownViews + "This is a hook method generated by the Browser. + It will be invoked when your app/dialog-window is really closed. + See also #closeDownViews, which is invoked before and may suppress the close + or ask the user for confirmation." + + "/ change the code below as required ... + "/ This should cleanup any leftover resources + "/ (for example, temporary files) + "/ super closeRequest will initiate the closeDown + + "/ add your code here + + "/ do not remove the one below ... + ^ super closeDownViews +! + +initialize + + super initialize. + + showDetail := (Smalltalk at:#SystemDebugging ifAbsent:false). + updateSema := Semaphore forMutualExclusion. + updateDelay := 0.5. + listUpdateDelay := 5. + + "/ event mode is no longer used; + "/ this event support may vanish + Processor isPureEventDriven ifTrue:[ + updateBlock := [self updateStatus:nil]. + listUpdateBlock := [self updateList]. + ]. +! + +postBuildProcessTable:aWidget + + processTable := aWidget scrolledView. + processTable wantsFocusWithPointerEnter. +! + +postBuildWith:aBuilder + + ^ super postBuildWith:aBuilder +! + +postOpenWith:aBuilder + + super postOpenWith:aBuilder. + self viewedColumnsChanged. + self updateList. + self startUpdateProcess. + self selectionChanged. + self windowGroup addPreEventHook:self. +! ! + +!ProcessMonitorV2 methodsFor:'menu actions'! + +abortProcess + "abort (raise AbortSignal in) the selected process" + + self selectedProcessesDo:[:p | + p abort + ] +! + +debugProcess + "open a debugger on the selected process" + + self selectedProcessesDo:[:p | + Debugger openOn:p + ] +! + +debugWhenResumed + self selectedProcessesDo:[:p | + p addInterruptAction:[Debugger enter] + ] +! + +hardTerminateProcess + "hard terminate the selected process" + + self selectedProcessesSend:#terminateNoSignal +! + +inspectSelection + "open an inspector on the selected process" + + self selectedProcessesSend:#inspect +! + +lowerPrio + "lower the selected processes priority" + + self selectedProcessesDo:[:p | + p priority:(p priority - 1) + ] +! + +openAboutThisApplication + "This method was generated by the Browser. + It will be invoked when the menu-item 'help-about' is selected." + + "/ could open a customized aboutBox here ... + super openAboutThisApplication +! + +openDocumentation + "This method was generated by the Browser. + It will be invoked when the menu-item 'help-documentation' is selected." + + "/ change below as required ... + + "/ to open an HTML viewer on some document (under 'doc/online//' ): + HTMLDocumentView openFullOnDocumentationFile:'TOP.html'. + + "/ add application-specific help files under the 'doc/online//help/appName' + "/ directory, and open a viewer with: + "/ HTMLDocumentView openFullOnDocumentationFile:'help//TOP.html'. +! + +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 +! + +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. + self updateList. +! + +terminateProcessGroup + "terminate the selected process with all of its subprocesses" + + self selectedProcessesSend:#terminateGroup. + self updateList. +! ! + +!ProcessMonitorV2 methodsFor:'queries'! + +needFullInformation + + ^ true +"/ ^ (self showUsedStack value or:[ +"/ self showTotalStack value or:[ +"/ self showCurrentSegment value or:[ +"/ self showSwitch value]]]) +! + +showDetail +! ! + +!ProcessMonitorV2 methodsFor:'queries - table string'! + +getCurrentSegmentStringFor:con + + con notNil ifTrue:[ + | contextCount c sender| + contextCount := 1. + c := con. + [(sender := c sender) notNil] whileTrue:[ + c := sender. + contextCount := contextCount + 1. + ]. + ^ (((ObjectMemory addressOf:con) printStringRadix:16), + ' .. ', + ((ObjectMemory addressOf:c) printStringRadix:16)). + ]. +! + +getGroupStringFor:aProcess + + |gId| + + gId := aProcess processGroupId. + ((gId == aProcess id) or:[gId isNil]) ifTrue:[ + "/ a group leader + ^ '-'. + ] ifFalse:[ + ^ gId. + ]. +! + +getPrioStringFor:aProcess + + |prioRange| + + Processor supportDynamicPriorities ifTrue:[ + (prioRange := aProcess priorityRange) isNil ifTrue:[ + ^ aProcess priority asString. + ] ifFalse:[ + ^ (aProcess priority asString, + ' [', + prioRange start printString, + '..', + prioRange stop printString, + ']'). + ]. + ]. +! + +getStateStringFor:aProcess running:isRunning + + |st stateCharacter | + + st := aProcess state. + isRunning ifTrue:[ + stateCharacter := '* '. + ] ifFalse:[ + [ + (Processor scheduledProcesses includes:aProcess) ifTrue:[ + stateCharacter := '+ ' + ] ifFalse:[ + stateCharacter := ' '. + ]. + ] valueUninterruptably. + ]. + ^ stateCharacter, (st asString). +! + +getTotalStackStringFor:aProcess + + + aProcess id == 0 ifTrue:[ + ^ 'unlimited'. + ] ifFalse:[ + | tStackSize noOfSegs | + ((tStackSize := aProcess totalStackSize) notNil and:[ + (noOfSegs := aProcess numberOfStackSegments) notNil + ]) ifTrue:[ + ^ ((tStackSize printString), + ' (', + (noOfSegs printString), + ')' ) + ] + ]. +! + +getWhereStringFor:con running:isRunning + + con notNil ifTrue:[ + | c found skipping| + c := con. + found := false. + isRunning 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, non-process + "/ 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 + ]. + + "/ skip, until an interesting context is + "/ found. + "/ this skips intermediate contexts, which lead + "/ to the sema-wait (for example, unwind blocks, + "/ delay-stuff etc.) + + skipping := true. + [skipping] whileTrue:[ + skipping := false. + (c notNil + and:[c receiver == Delay + or:[c receiver class == Delay]]) ifTrue:[ + c := c sender. + skipping := true. + ]. + + [c notNil + and:[c receiver isBlock + and:[c selector startsWith:'value']]] whileTrue:[ + c := c sender. + skipping := true. + ]. + + [c notNil + and:[c receiver isBlock + and:[c selector = 'ensure:']]] whileTrue:[ + c := c sender. + skipping := true. + ]. + + [c notNil + and:[c receiver == OperatingSystem + and:[c selector == #unblockInterrupts]]] whileTrue:[ + c := c sender. + skipping := true. + ]. + + [c notNil and:[c isBlockContext]] whileTrue:[ + c := c home. + skipping := true. + ]. + ]. + + c notNil ifTrue:[ + | sel | + sel := c selector. + sel isNil ifTrue:[ + sel := '* unknown *' + ]. + ^ (c receiver class name, + '>>', + sel). + ] + ]. +! ! + +!ProcessMonitorV2 methodsFor:'sorting'! + +sortProcessListBy:instanceName + "method to sort the list of BugReport" + + | aSymbol isReverse cmpOp currentSortOrder| + + aSymbol := instanceName asSymbol. + isReverse := false. + currentSortOrder := self currentSortOrder value. + currentSortOrder isEmpty ifTrue:[ + currentSortOrder at:#column put:aSymbol. + currentSortOrder at:#reverse put:false. + ] ifFalse:[ + (currentSortOrder at:#column) = aSymbol ifTrue:[ + "/ same column like before - change sort order ifReverse is true + isReverse := currentSortOrder at:#reverse. + currentSortOrder at:#reverse put:(isReverse not). + ] ifFalse:[ + "/ another column - remark column + currentSortOrder at:#column put:aSymbol. + ] + ]. + self viewedColumnsChanged. + (currentSortOrder at:#reverse) ifTrue:[ + cmpOp := #'>' + ] ifFalse:[ + cmpOp := #'<' + ]. + sortBlock := [:a :b | + |entry1 entry2| + + entry1 := (a perform:aSymbol). + entry2 := (b perform:aSymbol). + entry1 perform:cmpOp with:entry2 + ]. + updateSema critical:[ + | oldList | + oldList := self processList copy. + self processList contents:(oldList sort:sortBlock) + ]. +! ! + +!ProcessMonitorV2 methodsFor:'update process'! + +createItemWith:aProcess + + | running con processItem| + + processItem := ProcessItem new. + + processItem processInstance:aProcess. + + processItem processId:aProcess id. + processItem idVal:aProcess id ? -1. + + processItem processGroup:(self getGroupStringFor:aProcess). + processItem groupVal:(processItem processGroup isNumber ifTrue:[processItem processGroup] ifFalse:[-1]). + + processItem processName:aProcess name ? ''. + + running := (aProcess state == #run and:[aProcess == Processor interruptedProcess]). + + processItem processState:(self getStateStringFor:aProcess running:running). + + processItem prioVal:(aProcess priority). + processItem processPrio:(self getPrioStringFor:aProcess). + + processItem processUsedStack:aProcess usedStackSize. + + processItem processTotalStack:(self getTotalStackStringFor:aProcess). + + con := aProcess suspendedContext. + con isNil ifTrue:[ + aProcess == Processor activeProcess ifTrue:[ + con := thisContext + ] + ]. + + processItem processCurrentSegment:(self getCurrentSegmentStringFor:con). + + processItem processSwitch:(aProcess numberOfStackBoundaryHits printString). + + processItem processWhere:(self getWhereStringFor:con running:running). + + ^ processItem +! + +startUpdateProcess + updateBlock notNil ifTrue:[ + Processor addTimedBlock:updateBlock afterSeconds:updateDelay. + Processor addTimedBlock:listUpdateBlock afterSeconds:listUpdateDelay. + ] ifFalse:[ + updateProcess := [ + [ + |id cnt myDelay| + + myDelay := Delay forSeconds:updateDelay. + + " + every updateDelay (0.5), we look which process runs; + every half second, the status is updated. + every listUpdateDelay (5s), the list of processes is + built up again + " + [true] whileTrue:[ + ((listUpdateDelay // updateDelay) max:2) - 1 timesRepeat:[ + myDelay wait. + self updateStatus:nil. + ]. + myDelay wait. + self updateList. + ] + ] valueOnUnwindDo:[ + updateProcess := nil + ] + ] forkAt:(Processor userSchedulingPriority + 1). + updateProcess name:'monitor [' , + Processor activeProcess id printString , + '] update'. + " + raise my own priority + " + Processor activeProcess priority:(Processor userSchedulingPriority + 2) + ]. +! + +updateList + + |newList| + + processTable shown ifTrue:[ + newList := self getProcessList. + + "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:[ + self updateStatus:newList + ]. + ]. + updateBlock notNil ifTrue:[ + Processor removeTimedBlock:listUpdateBlock. + Processor addTimedBlock:listUpdateBlock afterSeconds:listUpdateDelay + ]. +! + +updateStatus:newProcessList + + |startTime oldSelection newSelection newList dIndex index aProcess processItem endTime deltaT| + + startTime := AbsoluteTime now. + + processTable shown ifTrue:[ + newProcessList notNil ifTrue:[ + processes := WeakArray withAll:newProcessList. + ((processes findFirst:[:pro1| pro1 id == 0]) ~= 0) ifTrue:[ + Transcript showCR:'have'. + ]. + ]. + processes notNil ifTrue:[ + newList := OrderedCollection new. + + dIndex := 1. + index := 1. + + "/ use while-loop; + "/ processList may change size .... + + [index <= processes size] whileTrue:[ + aProcess := processes at:index. + index := index + 1. + (aProcess notNil + and:[aProcess ~~ 0]) ifTrue:[ + ((aProcess id) notNil or:[self showDead value]) ifTrue:[ + processItem := self createItemWith:aProcess. + (((newList select:[:pro2| (pro2 processInstance == processItem processInstance)]) size) > 0) ifTrue:[ + Transcript showCR:'process ', processItem processInstance name asString, ' already in list at ', index asString. + ]. + newList add:processItem. + processes at:dIndex put:aProcess. + ] + ]. + dIndex := dIndex + 1 + ] + ]. + updateSema critical:[ + oldSelection := self selectedProcesses value. + newList sort:self sortBlock. + processList contents:(newList asList). + oldSelection notNil ifTrue:[ + newSelection := OrderedCollection new. + oldSelection do:[:processItem | + index := newList findFirst:[:anItem | (anItem processInstance == processItem processInstance)]. + index ~~ 0 ifTrue:[ + newSelection add:(newList at:index). + ]. + ] + ]. + self selectedProcesses value:newSelection. + ] + ]. + endTime := AbsoluteTime now. + deltaT := (endTime millisecondDeltaFrom:startTime) / 1000.0. +"/ Transcript show:deltaT; show:' ' ; showCR:(updateDelay / 10.0). + deltaT > (updateDelay / 5) ifTrue:[ + "/ the update took longer than 20% - make delay longer, to reduce cpu load. + updateDelay := updateDelay * 2. + "/ Transcript show:'+++ '; showCR:updateDelay. + ] ifFalse:[ + updateDelay > 0.5 ifTrue:[ + deltaT < (updateDelay / 20) ifTrue:[ + "/ the update took less than 5% - make delay smaller for better animation. + updateDelay := (updateDelay / 2) max:0.5. + "/ Transcript show:'--- ';showCR:updateDelay. + ]. + ]. + ]. + + updateBlock notNil ifTrue:[ + Processor removeTimedBlock:updateBlock. + Processor addTimedBlock:updateBlock afterSeconds:updateDelay + ] +! + +updateView + self updateList. + self updateStatus:nil +! ! + +!ProcessMonitorV2::ProcessItem methodsFor:'accessing'! + +groupVal + "return the value of the instance variable 'groupVal' (automatically generated)" + + ^ groupVal +! + +groupVal:something + "set the value of the instance variable 'groupVal' (automatically generated)" + + groupVal := something. +! + +idVal + "return the value of the instance variable 'idVal' (automatically generated)" + + ^ idVal +! + +idVal:something + "set the value of the instance variable 'idVal' (automatically generated)" + + idVal := something. +! + +prioVal + "return the value of the instance variable 'prioVal' (automatically generated)" + + ^ prioVal +! + +prioVal:something + "set the value of the instance variable 'prioVal' (automatically generated)" + + prioVal := something. +! + +processCurrentSegment + "return the value of the instance variable 'processCurrentSegment' (automatically generated)" + + ^ processCurrentSegment +! + +processCurrentSegment:something + "set the value of the instance variable 'processCurrentSegment' (automatically generated)" + + processCurrentSegment := something. +! + +processGroup + "return the value of the instance variable 'processGroup' (automatically generated)" + + ^ processGroup +! + +processGroup:something + "set the value of the instance variable 'processGroup' (automatically generated)" + + processGroup := something. +! + +processId + "return the value of the instance variable 'processId' (automatically generated)" + + ^ processId +! + +processId:something + "set the value of the instance variable 'processId' (automatically generated)" + + processId := something. +! + +processInstance + "return the value of the instance variable 'processInstance' (automatically generated)" + + ^ processInstance +! + +processInstance:something + "set the value of the instance variable 'processInstance' (automatically generated)" + + processInstance := something. +! + +processName + "return the value of the instance variable 'processName' (automatically generated)" + + ^ processName +! + +processName:something + "set the value of the instance variable 'processName' (automatically generated)" + + processName := something. +! + +processPrio + "return the value of the instance variable 'processPrio' (automatically generated)" + + ^ processPrio +! + +processPrio:something + "set the value of the instance variable 'processPrio' (automatically generated)" + + processPrio := something. +! + +processState + "return the value of the instance variable 'processState' (automatically generated)" + + ^ processState +! + +processState:something + "set the value of the instance variable 'processState' (automatically generated)" + + processState := something. +! + +processSwitch + "return the value of the instance variable 'processSwitch' (automatically generated)" + + ^ processSwitch +! + +processSwitch:something + "set the value of the instance variable 'processSwitch' (automatically generated)" + + processSwitch := something. +! + +processTotalStack + "return the value of the instance variable 'processTotalStack' (automatically generated)" + + ^ processTotalStack +! + +processTotalStack:something + "set the value of the instance variable 'processTotalStack' (automatically generated)" + + processTotalStack := something. +! + +processUsedStack + "return the value of the instance variable 'processUsedStack' (automatically generated)" + + ^ processUsedStack +! + +processUsedStack:something + "set the value of the instance variable 'processUsedStack' (automatically generated)" + + processUsedStack := something. +! + +processWhere + "return the value of the instance variable 'processWhere' (automatically generated)" + + ^ processWhere +! + +processWhere:something + "set the value of the instance variable 'processWhere' (automatically generated)" + + processWhere := something. +! ! + +!ProcessMonitorV2 class methodsFor:'documentation'! + +version + ^ '$Header: /cvs/stx/stx/libtool/ProcessMonitorV2.st,v 1.1 2003-01-21 15:17:24 penk Exp $' +! ! diff -r b14fcc67ff8e -r 99d11fbee2af SystemStatusMonitorV2.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SystemStatusMonitorV2.st Tue Jan 21 16:17:38 2003 +0100 @@ -0,0 +1,34 @@ +"{ Package: 'stx:libtool' }" + +ApplicationModel subclass:#SystemStatusMonitorV2 + instanceVariableNames:'listUpdateDelay updateDelay updateBlock listUpdateBlock + updateProcess' + classVariableNames:'' + poolDictionaries:'' + category:'Monitors-ST/X' +! + + +!SystemStatusMonitorV2 methodsFor:'initialization & release'! + +release + updateBlock notNil ifTrue:[ + Processor removeTimedBlock:updateBlock. + updateBlock := nil. + ]. + listUpdateBlock notNil ifTrue:[ + Processor removeTimedBlock:listUpdateBlock. + listUpdateBlock := nil. + ]. + updateProcess notNil ifTrue:[ + updateProcess terminate. + updateProcess := nil. + ]. + super release +! ! + +!SystemStatusMonitorV2 class methodsFor:'documentation'! + +version + ^ '$Header: /cvs/stx/stx/libtool/Attic/SystemStatusMonitorV2.st,v 1.1 2003-01-21 15:17:38 penk Exp $' +! !