<<>> <> <> <> <> <<>> DIRECTORY Buttons USING [Button, Create, ReLabel, SetDisplayStyle], Commander USING [CommandProc, Register], <> IO, Process USING [Detach, Pause, SecondsToTicks], UserProfile USING [CallWhenProfileChanges, Number, ProfileChangedProc], PFS, Rope, UnixSysCallExtensions, UXStrings, UnixTypes, ViewerClasses USING [ClickProc]; PageSpaceMon: CEDAR MONITOR IMPORTS Buttons, Commander, --Debugger,-- IO, PFS, Process, UnixSysCallExtensions, UserProfile, UXStrings, Rope ~ BEGIN ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; defaultCheckFreqInSeconds: INTEGER = 60; defaultWarningLevel: INTEGER = 100; -- in kBytes outputFile: ROPE = "/tmp/pstat.out"; commandName: ROPE = "/etc/pstat -s"; devNull: UnixTypes.CHARPtr ¬ UXStrings.Create["/dev/null"]; buttonLabel: ROPE ¬ "Page Space: "; checkFreq: INTEGER; warningLevel: INTEGER; highlighted: BOOLEAN ¬ FALSE; uxcommandname: UnixTypes.CHARPtr ¬ UXStrings.Create[commandName]; uxoutputfile: UnixTypes.CHARPtr ¬ UXStrings.Create[outputFile]; theButton: Buttons.Button ¬ NIL; PageSpaceButton: ENTRY Commander.CommandProc = { IF theButton # NIL THEN { IO.PutRope[cmd.out, "Page Space Monitor Button already created.\n"]; RETURN; }; theButton ¬ Buttons.Create[ info: [name: buttonLabel], proc: DisplayPSLeft, fork: TRUE, documentation: "create page space monitor button"]; NoteProfileChange[firstTime]; -- get initial values from profile UserProfile.CallWhenProfileChanges[NoteProfileChange]; TRUSTED {Process.Detach[FORK PageSpaceWatcher[]]}; }; PageSpaceWatcher: PROC ~ { DO ENABLE ABORTED => LOOP; DisplayPSLeft[theButton]; Process.Pause[Process.SecondsToTicks[checkFreq]]; ENDLOOP; }; DisplayPSLeft: ENTRY ViewerClasses.ClickProc ~ { swapLeftInK: INTEGER; newName: ROPE; XRConsoleMsgInner: PROC [m: UXStrings.CString] ~ TRUSTED MACHINE CODE { "XR_ConsoleMsg" }; DebugMsg: PROC [r: Rope.ROPE] ~ TRUSTED { text: REF TEXT; text ¬ Rope.ToRefText[r]; XRConsoleMsgInner[UXStrings.ViewRefText[text]]; }; <> <> <<};>> GetSwapSpaceLeft: PROC [] RETURNS [spaceLeft: INTEGER] ~ { -- returns -1 on error res: INTEGER; [res] ¬ UnixSysCallExtensions.Spawn[uxcommandname, devNull, uxoutputfile, devNull]; IF res = -1 THEN { DebugMsg["PageSpaceMonButton: Spawn failed\n"]; spaceLeft ¬ -1; } ELSE { -- read pstat output (highly sunos dependent) ENABLE IO.EndOfStream, PFS.Error => { DebugMsg["PageSpaceMonButton: end of output seen unexpectedly"]; spaceLeft ¬ -1; CONTINUE; }; s : STREAM ¬ PFS.StreamOpen[PFS.PathFromRope[outputFile]]; WHILE IO.GetChar[s] ~= ', DO -- advance to comma after used NULL; ENDLOOP; [] ¬ IO.GetChar[s]; -- get space char spaceLeft ¬ IO.GetInt[s]; -- get space left }; }; swapLeftInK ¬ GetSwapSpaceLeft[]; IF swapLeftInK = -1 THEN { newName ¬ "Page Space: Error"; } ELSE { IF swapLeftInK >= 1000 THEN [newName] ¬ IO.PutFR1["Page Space: %gMb", IO.int[swapLeftInK / 1000]] ELSE [newName] ¬ IO.PutFR1["Page Space: %gKb", IO.int[swapLeftInK]]; }; Buttons.ReLabel[button: theButton, newName: newName, paint: TRUE]; IF swapLeftInK < warningLevel THEN { IF ~highlighted THEN { Buttons.SetDisplayStyle[theButton, $WhiteOnBlack]; highlighted ¬ TRUE; } } ELSE { IF highlighted THEN { Buttons.SetDisplayStyle[theButton, $BlackOnWhite]; highlighted ¬ FALSE; } }; }; NoteProfileChange: UserProfile.ProfileChangedProc ~ { checkFreq ¬ MAX[UserProfile.Number["PageSpaceMonitor.CheckFrequency", defaultCheckFreqInSeconds], 0]; warningLevel ¬ MAX[UserProfile.Number["PageSpaceMonitor.WarningLevel", defaultWarningLevel], 0]; }; Commander.Register["PageSpaceMonButton", PageSpaceButton, "create page space monitor button"]; END.