-- Copyright (C) 1980, 1981, 1983, 1984, 1985 by Xerox Corporation. All rights reserved.
-- File: MDSWatcher.mesa
-- HGM, 14-Sep-85 22:16:20
-- Ted Wobber 8-Aug-83 11:11:17
-- Randy Gobbel 7-Aug-81 16:11:44
-- Roy Levin 10-Sep-80 18:46:53
-- Andrew Birrell 16-Oct-80 18:30:01
-- Hankins 23-Aug-84 10:38:03
DIRECTORY
Ascii USING [NUL],
BufferOps USING [GetStatistics, Statistics],
EnquiryDefs USING [DisplayStats, Histograms, RemoteServers, PolicyControls],
GlassDefs USING [Handle, HandleObject, StringType],
LogDefs USING [DisplayNumber],
LogPrivateDefs USING [tty],
Process USING [
Detach, InvalidProcess, Pause, Priority, SecondsToTicks, SetPriority, Ticks,
ValidateProcess],
ProcessPriorities USING [priorityFrameFault],
ProcessOperations USING [
DisableInterrupts, EnableInterrupts, Notify, ReEnter, Wait],
PSB USING [
Condition, FaultIndex, PDABase, PDA, PsbIndex, PsbNull, qPageFault, StartPsb],
SpecialSpace USING [MakeProcedureResident],
RestartDefs,
TTY USING [GetChar, PutChar, PutDecimal, PutLongDecimal, PutString];
MDSWatcher: PROGRAM
IMPORTS
BufferOps, EnquiryDefs, LogDefs, LogPrivateDefs, Process, ProcessOperations,
SpecialSpace, TTY
EXPORTS RestartDefs =
BEGIN
screen: GlassDefs.Handle = @screenObject;
screenObject: GlassDefs.HandleObject ← [
ReadChar: ReadCharNull, ReadString: ReadStringNull, WriteChar: MyWriteChar,
WriteString: MyWriteString, WriteDecimal: MyWriteDecimal,
WriteLongDecimal: MyWriteLongDecimal, SendNow: NullProc,
CharsLeft: CardNullProc, LinesLeft: CardNullProc, SetWidth: SetWidthNull,
SetHeight: SetHeightNull, DelTyped: BoolNullProc, Synch: NullProc,
Flush: NullProc];
availablePages, availablePSBs, availablePups: CARDINAL ← 0;
savedStorageFaults, storageFaults: CARDINAL ← 0;
oneMinute: Process.Ticks = Process.SecondsToTicks[60];
tenSeconds: Process.Ticks = Process.SecondsToTicks[10];
StartKeyWatcher: PUBLIC PROCEDURE =
BEGIN
Process.Detach[FORK KeyboardWatcher[]];
END;
Init: PROCEDURE =
BEGIN
-- LogDefs.DisplayNumber["Free MDS"L, [short[@availablePages]]];
LogDefs.DisplayNumber["Free PSBs"L, [short[@availablePSBs]]];
LogDefs.DisplayNumber["Free Pup Buffers"L, [short[@availablePups]]];
LogDefs.DisplayNumber["Page faults/min"L, [short[@savedStorageFaults]]];
END;
WatchMDS: PROCEDURE =
BEGIN
<< this is looking at MDS and seeing how much has been carved up for new, smaller, spaces.
this is no longer possible to do in any clean way (could import global from of some Pilot impl and look at a variable therein (SpecialSpaceImpl?) so we'll just not calculate it any longer.
firstPage: Space.PageNumber = Space.PageFromLongPointer[Space.MDS[].pointer];
lastPage: Space.PageNumber = firstPage + Environment.maxPagesInMDS;
should also be equivalent to firstPage+Space.MDS[].count? >>
DO
available: CARDINAL ← 0;
<< FOR page: Space.PageNumber ← firstPage, SUCC[page] UNTIL page > lastPage DO
IF Space.GetHandle[page] = Space.mds THEN available ← available + 1;
ENDLOOP;
availablePages ← available;
available ← 0;
>>
FOR i: CARDINAL IN [PSB.StartPsb..PSB.StartPsb + PSB.PDA.count) DO
Process.ValidateProcess[
LOOPHOLE[i, PROCESS] !
Process.InvalidProcess => {available ← available + 1; CONTINUE}];
ENDLOOP;
availablePSBs ← available;
savedStorageFaults ← storageFaults;
storageFaults ← 0;
Process.Pause[oneMinute];
ENDLOOP;
END;
WatchPupBuffers: PROCEDURE =
BEGIN
stats: ARRAY BufferOps.Statistics OF CARDINAL;
DO
stats ← BufferOps.GetStatistics[];
availablePups ← stats[available];
Process.Pause[tenSeconds];
ENDLOOP
END;
KeyboardWatcher: PROCEDURE =
BEGIN
DO
c: CHAR ← TTY.GetChar[LogPrivateDefs.tty];
SELECT c FROM
'h, 'H => EnquiryDefs.Histograms[screen];
'o, 'O => EnquiryDefs.RemoteServers[screen];
'p, 'P => EnquiryDefs.PolicyControls[screen];
ENDCASE => EnquiryDefs.DisplayStats[screen];
ENDLOOP;
END;
-- Stuff stolen from BLyon's UsageMonitor tool
priorityStorageFaultRecorders: Process.Priority ←
ProcessPriorities.priorityFrameFault - 1;
-- should be higher than Pilot's page and write fault handlers' priorities.
pda: PSB.PDABase = PSB.PDA;
qPageFault: PSB.FaultIndex = PSB.qPageFault;
pPageFaultCondition: LONG POINTER TO PSB.Condition = @pda.fault[
qPageFault].condition;
pPageFaultCONDITION: LONG POINTER TO CONDITION = LOOPHOLE[pPageFaultCondition];
PageFaultRecorder: --EXTERNAL-- PROCEDURE [] =
BEGIN
pageFaultLock: MONITORLOCK;
shouldNotifyPilot: BOOLEAN ← FALSE;
Process.SetPriority[priorityStorageFaultRecorders];
-- NO PAGE FAULTS or calls to swappable code from this point on! (else the state vector goblin will get ya)
--FOREVER--
DO
-- wait for a page fault..
ProcessOperations.Wait[@pageFaultLock, pPageFaultCONDITION, --timeout:-- 1];
UNTIL ProcessOperations.ReEnter[@pageFaultLock, pPageFaultCONDITION] DO
NULL ENDLOOP;
-- either a new page fault came along or we timed out..
IF pda.fault[qPageFault].queue.tail = PSB.PsbNull THEN
-- no page fault, just timed out..
BEGIN
IF shouldNotifyPilot
AND pda.fault[qPageFault].condition.tail ~= PSB.PsbNull THEN {
NakedNotify[pPageFaultCONDITION]; shouldNotifyPilot ← FALSE};
LOOP; -- go back and wait again.
END;
-- wake up the Pilot fault handler:
ProcessOperations.DisableInterrupts[];
IF pPageFaultCondition↑.tail = PSB.PsbNull THEN shouldNotifyPilot ← TRUE -- Pilot not ready for this fault yet..
ELSE NakedNotify[pPageFaultCONDITION];
ProcessOperations.EnableInterrupts[];
-- log the fault:
storageFaults ← SUCC[storageFaults];
ENDLOOP;
-- Note: following code never executed in current implementation.
-- Must get back to ordinary priority before exiting since Process.End is swappable..
-- Process.SetPriority[Process.priorityForeground];
END; -- PageFaultRecorder (process disappears)
NakedNotify: PROCEDURE [pCondition: LONG POINTER TO CONDITION] = INLINE {
-- Used ONLY to notify a condition from a high priority process outside the relevant monitor.
pCond: LONG POINTER TO PSB.Condition = LOOPHOLE[pCondition];
ProcessOperations.DisableInterrupts[];
IF pCond↑.tail = PSB.PsbNull THEN {
pCond↑.wakeup ← TRUE; ProcessOperations.EnableInterrupts[]}
ELSE {
ProcessOperations.EnableInterrupts[];
ProcessOperations.Notify[pCondition]}};
-- GlassDefs.HandleOject implementors
NullProc: PROCEDURE = {};
BoolNullProc: PROCEDURE RETURNS [BOOLEAN] = {RETURN[FALSE]};
CardNullProc: PROCEDURE RETURNS [CARDINAL] = {RETURN[0]};
ReadCharNull: PROCEDURE RETURNS [CHARACTER] = {RETURN[Ascii.NUL]};
ReadStringNull: PROC [prompt, s: LONG STRING, type: GlassDefs.StringType]
RETURNS [CHARACTER] = {RETURN[Ascii.NUL]};
SetWidthNull, SetHeightNull: PROCEDURE [CARDINAL] = {};
MyWriteChar: PROCEDURE [c: CHARACTER] = {TTY.PutChar[LogPrivateDefs.tty, c]};
MyWriteString: PROC [s: LONG STRING] = {TTY.PutString[LogPrivateDefs.tty, s]};
MyWriteDecimal: PROCEDURE [n: CARDINAL] = {
TTY.PutDecimal[LogPrivateDefs.tty, n]};
MyWriteLongDecimal: PROCEDURE [n: LONG CARDINAL] = {
TTY.PutLongDecimal[LogPrivateDefs.tty, n]};
Init[];
SpecialSpace.MakeProcedureResident[PageFaultRecorder];
Process.Detach[FORK WatchMDS[]];
Process.Detach[FORK WatchPupBuffers[]];
END.