DIRECTORY BasicTime, Commander, Icons, Imager, ImagerBackdoor, ImagerColor, IO, MessageWindow, PrincOps, PrincOpsUtils, Process, ProcessWatch, ProcessWatchPrinting, Real, RealFns, Rope, TIPUser, ViewerClasses, ViewerOps; ProcessWatchInstantaneously: CEDAR MONITOR IMPORTS BasicTime, Commander, Icons, Imager, ImagerBackdoor, ImagerColor, IO, MessageWindow, PrincOpsUtils, Process, ProcessWatch, ProcessWatchPrinting, Real, RealFns, TIPUser, ViewerOps = { ROPE: TYPE = Rope.ROPE; PsbIndex: TYPE = PrincOps.PsbIndex; UsefulPsbIndex: TYPE = ProcessWatch.UsefulPsbIndex; nUsefulPsbs: CARDINAL = ProcessWatch.nUsefulPsbs; Viewer: TYPE = ViewerClasses.Viewer; ReadyVector: TYPE = ProcessWatch.ReadyVector; ProcessWatcher: TYPE = REF ProcessWatcherPrivate; ProcessWatcherPrivate: TYPE = RECORD [ ch, cw, rows, cols, lastFullColumn, width, height, dx, dy, ox, oy: INT _ 0, pds: ARRAY UsefulPsbIndex OF ProcessData _ ALL[[]] ]; ProcessData: TYPE = RECORD [ color: MyColor _ dormant, lastTill: BasicTime.Pulses _ 0]; MyColor: TYPE = {active, recent, past, old, dormant}; colorCode: ARRAY MyColor OF Imager.ConstantColor _ [ active: Imager.white, recent: ImagerColor.ColorFromRGB[[1.0, 1.0, 0]], past: ImagerColor.ColorFromRGB[[1.0, 0, 0]], old: ImagerColor.ColorFromRGB[[0.25, 0, 0.25]], dormant: Imager.black ]; xor: Imager.Color = ImagerBackdoor.invert; Million: LONG CARDINAL = 1000000; DecayingColor: TYPE = MyColor[recent .. old]; colorPersistance: ARRAY DecayingColor OF BasicTime.Pulses _ [ recent: BasicTime.MicrosecondsToPulses[666*Million/10], past: BasicTime.MicrosecondsToPulses[66*Million], old: BasicTime.MicrosecondsToPulses[60*Million] ]; CreateCmd: PROC [cmd: Commander.Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] --Commander.CommandProc-- = { [] _ CreateProcessWatcher[[name: "Instantaneous Process Watcher"]]; }; CreateProcessWatcher: PROC [viewerData: ViewerClasses.ViewerRec _ [], paint: BOOL _ TRUE] RETURNS [pwv: Viewer] = { pwv _ ViewerOps.CreateViewer[pwFlavor, viewerData, paint]; SetPWV[pwv]; }; pwFlavor: ATOM = $InstantaneousProcessWatcher; pwClass: ViewerClasses.ViewerClass _ NEW [ViewerClasses.ViewerClassRec _ [ flavor: pwFlavor, paint: PaintProcessWatcher, init: InitProcessWatcher, destroy: DestroyProcessWatcher, tipTable: TIPUser.InstantiateNewTIPTable["ProcessWatcher.TIP"], notify: NotifyProcessWatcher, icon: Icons.NewIconFromFile["ProcessWatcher.icons", 0] ]]; gray: Imager.Color _ Imager.MakeGray[0.5]; paintTime: BasicTime.Pulses _ BasicTime.MicrosecondsToPulses[300000]; doGray: BOOL _ TRUE; InitProcessWatcher: PROC [self: Viewer] --ViewerClasses.InitProc-- = { pw: ProcessWatcher = NEW [ProcessWatcherPrivate _ []]; self.data _ pw; }; DestroyProcessWatcher: PROC [self: Viewer] --ViewerClasses.DestroyProc-- = { SetPWV[NIL]; }; counts: REF Counts _ NEW [Counts _ ALL[0]]; Counts: TYPE = ARRAY MyColor OF INT; debug: BOOL _ FALSE; CARD: TYPE = LONG CARDINAL; PaintProcessWatcher: PROC [self: Viewer, context: Imager.Context, whatChanged: REF, clear: BOOL] RETURNS [quit: BOOL _ FALSE] --ViewerClasses.PaintProc-- = { ENABLE UNWIND => painting _ FALSE; pw: ProcessWatcher = NARROW[self.data]; now: BasicTime.Pulses = BasicTime.GetClockPulses[]; paintAllowance: BasicTime.Pulses = now + paintTime; laters: ARRAY DecayingColor OF BasicTime.Pulses; latest: BasicTime.Pulses; reset: BOOL = lastPaint >= paintAllowance; FOR dc: DecayingColor IN DecayingColor DO laters[dc] _ now + colorPersistance[dc]; ENDLOOP; latest _ laters[FIRST[DecayingColor]]; IF painting THEN RETURN; painting _ TRUE; IF whatChanged # $Sample OR pw.ch # self.ch OR pw.cw # self.cw OR reset THEN { lastPaint _ now; pw.ch _ self.ch; pw.cw _ self.cw; FOR side: INT _ Real.Fix[RealFns.SqRt[REAL[pw.ch]*REAL[pw.cw]]], side - 1 DO IF side = 0 THEN {pw.rows _ pw.cols _ 16; EXIT}; pw.rows _ pw.ch/side; pw.cols _ pw.cw/side; WHILE (pw.rows-1) * pw.cols >= nUsefulPsbs DO pw.rows _ pw.rows - 1; ENDLOOP; WHILE (pw.cols-1) * pw.rows >= nUsefulPsbs DO pw.cols _ pw.cols - 1; ENDLOOP; IF pw.rows * pw.cols >= nUsefulPsbs THEN EXIT; ENDLOOP; pw.lastFullColumn _ nUsefulPsbs - (pw.rows-1)*pw.cols; pw.dx _ pw.cw / pw.cols; pw.dy _ pw.ch / pw.rows; pw.width _ pw.dx * pw.cols; pw.height _ pw.dy * pw.rows; pw.ox _ (pw.cw - pw.width)/2; pw.oy _ (pw.ch - pw.height)/2; Imager.SetColor[context, colorCode[dormant]]; Imager.MaskRectangle[context, [0, 0, pw.cw, pw.ch]]; Imager.TranslateT[context, [pw.ox, pw.oy]]; Imager.SetColor[context, colorCode[active]]; FOR row: INT IN [0 .. pw.rows] DO y: INT = row * pw.dy; w: INT = IF row = pw.rows THEN pw.lastFullColumn*pw.dx ELSE pw.width; Imager.MaskVector[context, [0, y], [w, y]]; ENDLOOP; FOR col: INT IN [0 .. pw.cols] DO x: INT = col * pw.dx; h: INT = IF col > pw.lastFullColumn THEN pw.height-pw.dy ELSE pw.height; Imager.MaskVector[context, [x, 0], [x, h]]; ENDLOOP; FOR psbi: UsefulPsbIndex IN UsefulPsbIndex DO IF reset THEN pw.pds[psbi].lastTill _ 0; pw.pds[psbi].color _ dormant; ENDLOOP; } ELSE Imager.TranslateT[context, [pw.ox, pw.oy]]; --now paint incrementally:--{ row, col: NAT _ 0; lastPaint _ now; FOR psbi: UsefulPsbIndex IN UsefulPsbIndex DO ready: BOOL = displayedVectors[psbi]; pd: ProcessData = pw.pds[psbi]; PaintIt: PROC [mc: MyColor] = INLINE { x: INT = col*pw.dx+1; y: INT = row*pw.dy+1; pw.pds[psbi].color _ mc; IF debug THEN { counts[mc] _ counts[mc] + 1; Imager.SetColor[context, ImagerBackdoor.invert]; Imager.MaskRectangle[context, [x, y, pw.dx-1, pw.dy-1]]; }; Imager.SetColor[context, colorCode[mc]]; Imager.MaskRectangle[context, [x, y, pw.dx-1, pw.dy-1]]; }; IF ready THEN { IF pd.color # active THEN PaintIt[active]; pw.pds[psbi].lastTill _ latest; } ELSE { rightColor: MyColor _ dormant; IF pd.lastTill > now THEN FOR dc: DecayingColor DECREASING IN DecayingColor DO IF pd.lastTill <= laters[dc] THEN { rightColor _ dc; EXIT; }; ENDLOOP; IF pd.color # rightColor THEN PaintIt[rightColor]; }; IF (col _ col + 1) = pw.cols THEN {col _ 0; row _ row + 1}; ENDLOOP; }; painting _ FALSE; }; lastPaint: BasicTime.Pulses _ 0; painting: BOOL _ FALSE; ReadPI: PROC RETURNS [pi: PsbIndex] = TRUSTED INLINE { pi _ PrincOpsUtils.PsbHandleToIndex[PrincOpsUtils.ReadPSB[]]}; NotifyProcessWatcher: PROC [self: Viewer, input: LIST OF REF ANY] --ViewerClasses.NotifyProc-- = { pw: ProcessWatcher = NARROW[self.data]; notifier: PsbIndex = ReadPI[]; who: UsefulPsbIndex _ 0; valid: BOOL _ FALSE; WHILE input # NIL DO first: REF ANY = input.first; input _ input.rest; WITH first SELECT FROM mc: TIPUser.TIPScreenCoords => { y: INT = mc.mouseY - pw.oy; x: INT = mc.mouseX - pw.ox; row: INT = y / pw.dy; col: INT = x / pw.dx; index: INT = row * pw.cols + col; valid _ y IN [0 .. pw.height) AND x IN [0 .. pw.width) AND (NOT (y >= pw.height - pw.dy AND x >= pw.lastFullColumn*pw.dx)); IF valid THEN who _ index; }; a: ATOM => SELECT a FROM $Select => { MessageWindow.Append[ message: IF valid THEN IO.PutFR["Process %g (%bB, %xH)%g", [cardinal[who]], [cardinal[who]], [cardinal[who]], [rope[IF notifier = who THEN " --- the notifier!" ELSE NIL]]] ELSE "Out of range", clearFirst: TRUE]; }; $ShowTop => { IF valid THEN TRUSTED {Process.Detach[FORK ProcessWatchPrinting.ShowTop[who]]}; }; $ShowStack => { IF valid THEN TRUSTED {Process.Detach[FORK ProcessWatchPrinting.ShowStack[who]]}; }; $Unselect => NULL; ENDCASE => ERROR; ENDCASE => ERROR; ENDLOOP; }; me: ProcessWatch.Consumer = [ConsumeReadyList]; pwv: Viewer _ NIL; sample: CONDITION; notedVectors, displayedVectors: ProcessWatch.ReadyVector; SetPWV: ENTRY PROC [v: Viewer] = { diff: BOOL = (pwv = NIL) # (v = NIL); pwv _ v; IF diff THEN { IF pwv = NIL THEN ProcessWatch.RemoveConsumer[me] ELSE ProcessWatch.AddConsumer[me]; }; }; ConsumeReadyList: ENTRY PROC [REF ANY] = { notedVectors _ ProcessWatch.readyVector; BROADCAST sample; }; PaintIt: PROC = { Wait: ENTRY PROC RETURNS [v: Viewer] = { DO WAIT sample; displayedVectors _ notedVectors; IF pwv # NIL THEN RETURN [pwv]; ENDLOOP; }; DO ViewerOps.PaintViewer[Wait[], client, FALSE, $Sample]; ENDLOOP; }; Start: PROC = TRUSTED { ViewerOps.RegisterViewerClass[pwFlavor, pwClass]; Process.InitializeCondition[@sample, 0]; Process.DisableTimeout[@sample]; Process.Detach[FORK PaintIt[]]; Commander.Register["InstantaneousProcessWatcher", CreateCmd, "Create an Instantaneous Process Watcher"]; }; Start[]; }. –ProcessWatchInstantaneously.Mesa Spreitzer, April 22, 1986 6:12:06 pm PST lifetime: BasicTime.Pulses _ BasicTime.MicrosecondsToPulses[1000000]; Κ π– "cedar" style˜code™ K™(—K˜KšΟk œCœŽ˜άK˜šΠbxœœ˜*KšœCœn˜Ί—K˜Kšœ˜K˜Kšœœœ˜Kšœ œ˜#Kšœœ˜3Kšœ œ˜1Kšœœ˜$Kšœ œ˜-K˜Kšœœœ˜1šœœœ˜&KšœCœ˜KKšœœœœ˜2K˜—K˜šœ œœ˜Kšœ˜Kšœ ˜ —K˜Kšœ œ(˜5šœ œ œ˜4Kšœ˜Kšœ0˜0Kšœ,˜,Kšœ/˜/Kšœ˜K˜—K˜K˜*K˜KšΟnœœœ ˜!K˜Kšœœ˜-šœœœ˜=Kšœ7˜7Kšœ1˜1Kšœ/˜/K˜—K˜šŸ œœœ œœœœΟcœ˜rKšœC˜CK˜—K˜š Ÿœœ3œœœ˜sKšœ:˜:K˜ K˜—K˜Kšœ œ ˜.K˜šœ%œ"˜JKšœ˜K˜K˜K˜K˜?K˜Kšœ6˜6K˜—K˜K˜*KšœE™EKšœE˜EKšœœœ˜K˜šŸœœ œ˜FKšœœ˜6K˜K˜—K˜šŸœœ œ˜LKšœœ˜ K˜—K˜Kšœœ œ œ˜+Kš œœœ œœ˜$Kšœœœ˜K˜Kšœœœœ˜K˜šŸœœ6œ œœœœ œ˜Kšœœœ˜"Kšœœ ˜'Kšœ3˜3Kšœ3˜3Kšœœœ˜0Kšœ˜Kšœœ˜*šœœ˜)Kšœ(˜(Kšœ˜—Kšœœ˜&Kšœ œœ˜Kšœ œ˜š œœœœœ˜NK˜K˜K˜š œœœœ˜LKšœ œœ˜0K˜K˜šœ&˜-K˜Kšœ˜—šœ&˜-K˜Kšœ˜—Kšœ"œœ˜.Kšœ˜—K˜6K˜K˜K˜K˜K˜K˜K˜-K˜4Kšœ+˜+K˜,šœœœ˜!Kšœœ˜Kš œœœœœ ˜EK˜+Kšœ˜—šœœœ˜!Kšœœ˜Kš œœœœœ ˜HK˜+Kšœ˜—šœœ˜-Kšœœ˜(Kšœ˜Kšœ˜—K˜—Kšœ,˜0š œ˜Kšœ œ˜K˜šœœ˜-Kšœœ˜%K˜šŸœœœ˜&Kšœœ˜Kšœœ˜K˜šœœ˜K˜K˜0K˜8K˜—Kšœ(˜(K˜8K˜—šœœ˜Kšœœ˜*Kšœ˜K˜—šœ˜K˜š œœœ œœ˜Nšœœ˜#Kšœœ˜K˜—Kšœ˜—Kšœœ˜2K˜—Kšœœ˜;Kšœ˜—K˜—Kšœ œ˜K˜Kšœ ˜ Kšœ œœ˜—K˜š Ÿœœœœœ˜6Kšœ>˜>—K˜šŸœœœœœœ œ˜bKšœœ ˜'Kšœ˜Kšœ˜Kšœœœ˜šœ œ˜Kšœœœ˜K˜šœœ˜šœ ˜ Kšœœ˜Kšœœ˜Kšœœ ˜Kšœœ ˜Kšœœ˜!Kš œ œœœœœœ ˜{Kšœœ ˜K˜—šœœœ˜˜ šœ˜šœ œ˜Kš œœ[œœœœ˜™Kšœ˜—Kšœ œ˜—K˜—šœ ˜ Kšœœœœ%˜OKšœ˜—šœ˜Kšœœœœ'˜QKšœ˜—Kšœ œ˜Kšœœ˜—Kšœœ˜—Kšœ˜—K˜—K˜Kšœ/˜/Kšœœ˜Kšœ œ˜Kšœ9˜9K˜šŸœœœ˜"Kšœœ œ œ˜%Kšœ˜šœœ˜Kšœœœ!œ˜TK˜—K˜—K˜š Ÿœœœœœ˜*Kšœ(˜(Kš œ˜K˜—K˜šŸœœ˜šŸœœœœ˜(š˜Kšœ˜ Kšœ ˜ Kšœœœœ˜Kšœ˜—K˜—š˜Kšœ&œ ˜6Kšœ˜—K˜—K˜šŸœœœ˜Kšœ1˜1K˜(Kšœ ˜ Kšœœ ˜K˜hK˜—K˜K˜K˜K˜—…— l*ς