FilePageMgrIOImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Last edited by
Kolling on January 27, 1984 2:30:52 pm PST
MBrown on January 31, 1984 9:02:38 pm PST
DIRECTORY
BasicTime
USING[GetClockPulses, Pulses, PulsesToMicroseconds],
File
USING[Error, Handle, RC, Read, Reason, Write],
FilePageMgrIO
USING[IORequest, IOType, Who],
FilePageMgrPrivateFile
USING[LeaderFilePageNumber],
IO,
Process
USING[Detach],
Rope,
ViewRec
USING[ViewRef];
FilePageMgrIOImpl: CEDAR MONITOR
IMPORTS BasicTime, File, IO, Process, ViewRec
EXPORTS FilePageMgrIO =
BEGIN OPEN FpmIO: FilePageMgrIO, FpmPF: FilePageMgrPrivateFile;
requests: LIST OF IOMasterRequests ← NIL;
nRequests: NAT ← 0;
maxRequests: NAT ← 1; -- 1 is best if File isn't scheduling, otherwise > 1.
IOMasterRequests: TYPE = RECORD[controllingProcess: PROCESS, idlerAssigned: BOOLEAN,
error: File.RC, errorIORequest: FpmIO.IORequest, nIOsInProgress: NAT, io: FpmIO.IOType,
file: File.Handle, list: LIST OF FpmIO.IORequest];
IOControllerAvail: CONDITION;
IdlerFinished: CONDITION;
IdlerNeeded: CONDITION;
nDebugEntries: CARDINAL = 200;
DebugLog: TYPE = RECORD [
debugging: BOOLEANTRUE,
entryNum: [0..nDebugEntries) ← 0,
entries: ARRAY [0..nDebugEntries) OF DebugEntries
];
ROPE: TYPE = Rope.ROPE;
Procedure: TYPE = {RegReq, RegIdler, GetNext, FinishUp, IO};
ProcedureNames: ARRAY Procedure OF ROPE = ["RegReq ", "RegIdler", "GetNext", "FinishUp", "IO "];
WhoNames: ARRAY FpmIO.Who OF ROPE = ["Idler ", "Controller"];
ActionNames: ARRAY FpmIO.IOType OF ROPE = ["read", "write"];
DebugEntries: TYPE = RECORD[proc: Procedure, action: FpmIO.IOType, process: PROCESS, who: FpmIO.Who, number: INT, timeOrDeltaTime1, timeOrDeltaTime2, timeOrDeltaTime3: LONG CARDINAL];
debugLog: REF DebugLog ← NIL;
DebugControl: PROC[] ~ {
IF debugLog = NIL THEN debugLog ← NEW[DebugLog];
[] ← ViewRec.ViewRef[debugLog];
};
PrintLog: PROCEDURE [ out: IO.STREAM ] ~ {
IF debugLog # NIL THEN {
startTime: INTLOOPHOLE[debugLog.entries[debugLog.entryNum].timeOrDeltaTime1];
FOR i: [ 0..nDebugEntries ) ← debugLog.entryNum, (i+1) MOD nDebugEntries WHILE i # (debugLog.entryNum - 1) MOD nDebugEntries DO
OPEN debugLog.entries[i];
t1: INT = timeOrDeltaTime1;
t2: INT = timeOrDeltaTime2;
t3: INT = timeOrDeltaTime3;
IO.PutF[ out, "%g %g %g %g %g ", IO.rope[ProcedureNames[proc]], IO.card[LOOPHOLE[process, CARDINAL]], IO.rope[WhoNames[who]], IO.card[LOOPHOLE[number]], IO.int[t1 - startTime] ];
IO.PutF[ out, "%g %g %g \n", IO.int[IF t2#0 THEN t2 - startTime ELSE 0], IO.int[t3], IO.rope[IF proc=IO THEN ActionNames[action] ELSE ""] ];
ENDLOOP;
};
};
RegisterRequest: PUBLIC ENTRY PROCEDURE[controllingProcess: PROCESS, io: FpmIO.IOType,
file: File.Handle, list: LIST OF FpmIO.IORequest] RETURNS[iORequest: FpmIO.IORequest] =
BEGIN -- non system fatal errors: none.
DO
IF nRequests < maxRequests THEN EXIT;
WAIT IOControllerAvail;
ENDLOOP;
nRequests ← nRequests + 1;
requests ← CONS[[controllingProcess: controllingProcess, idlerAssigned: FALSE,
error: ok, errorIORequest: , nIOsInProgress: 1, io: io, file: file, list: list.rest], requests];
IF list.rest # NIL THEN NOTIFY IdlerNeeded;
IF debugLog # NIL THEN AddToDebugLog[proc: RegReq, process: controllingProcess, who: controller,
number: list.first.filePageNumber, timeOrDeltaTime1: BasicTime.GetClockPulses[], timeOrDeltaTime2: 0, timeOrDeltaTime3: 0];
RETURN[list.first];
END;
AddToDebugLog: PROCEDURE[proc: {RegReq, RegIdler, GetNext, FinishUp, IO}, action: FpmIO.IOType ← read, process: PROCESS, who: FpmIO.Who, number: INT, timeOrDeltaTime1, timeOrDeltaTime2, timeOrDeltaTime3: BasicTime.Pulses] =
BEGIN
IF debugLog.debugging THEN {
debugLog.entries[debugLog.entryNum] ← [proc: proc, action: action, process: process, who: who,
number: number, timeOrDeltaTime1: BasicTime.PulsesToMicroseconds[timeOrDeltaTime1]/1000, timeOrDeltaTime2: BasicTime.PulsesToMicroseconds[timeOrDeltaTime2]/1000, timeOrDeltaTime3: BasicTime.PulsesToMicroseconds[timeOrDeltaTime3]/1000];
debugLog.entryNum ← (debugLog.entryNum + 1) MOD nDebugEntries;
};
END;
RegisterIdler: ENTRY PROCEDURE RETURNS[workToDo: BOOLEAN, controllingProcess:
PROCESS, io: FpmIO.IOType, file: File.Handle, iORequest: FpmIO.IORequest] =
BEGIN -- non system fatal errors: none.
FOR req: LIST OF IOMasterRequests ← requests, req.rest UNTIL req = NIL DO
IF ((NOT req.first.idlerAssigned) AND (req.first.list # NIL)) THEN BEGIN
workToDo ← TRUE;
controllingProcess ← req.first.controllingProcess;
io ← req.first.io;
file ← req.first.file;
iORequest ← req.first.list.first;
req.first.list ← req.first.list.rest;
req.first.idlerAssigned ← TRUE;
IF (req.first.nIOsInProgress ← req.first.nIOsInProgress + 1) # 2 THEN ERROR;
IF debugLog # NIL THEN AddToDebugLog[proc: RegIdler, process: controllingProcess, who: idler, number: iORequest.filePageNumber, timeOrDeltaTime1: BasicTime.GetClockPulses[], timeOrDeltaTime2: 0, timeOrDeltaTime3: 0];
RETURN;
END;
ENDLOOP;
workToDo ← FALSE;
END;
GetNext: PUBLIC ENTRY PROCEDURE[controllingProcess: PROCESS, who: FpmIO.Who]
RETURNS[error: File.RC, errorIORequest: FpmIO.IORequest, workToDo: BOOLEAN, iORequest:
FpmIO.IORequest] =
BEGIN -- non system fatal errors: none.
prevReq, req: LIST OF IOMasterRequests;
[prevReq, req] ← FindReqAndPrev[controllingProcess];
IF (((error ← req.first.error) # ok) OR ((workToDo ← (req.first.list # NIL)) = FALSE))
THEN BEGIN
workToDo ← FALSE;
IF debugLog # NIL THEN AddToDebugLog[proc: GetNext, process: controllingProcess, who: who,
number: 0, timeOrDeltaTime1: BasicTime.GetClockPulses[], timeOrDeltaTime2: 0, timeOrDeltaTime3: 0];
[error, errorIORequest] ← FinishUp[controllingProcess, prevReq, req, who];
END
ELSE BEGIN
iORequest ← req.first.list.first;
IF debugLog # NIL THEN AddToDebugLog[proc: GetNext, process: controllingProcess, who: who,
number: iORequest.filePageNumber, timeOrDeltaTime1: BasicTime.GetClockPulses[], timeOrDeltaTime2: 0, timeOrDeltaTime3: 0];
req.first.list ← req.first.list.rest;
END;
END;
LogError: PUBLIC ENTRY PROCEDURE[controllingProcess: PROCESS, who: FpmIO.Who, why:
File.Reason, errorIORequest: FpmIO.IORequest] =
BEGIN -- non system fatal errors: none.
prevReq, req: LIST OF IOMasterRequests;
[prevReq, req] ← FindReqAndPrev[controllingProcess];
req.first.error ← why;
req.first.errorIORequest ← errorIORequest;
[] ← FinishUp[controllingProcess, prevReq, req, who];
END;
FindReqAndPrev: INTERNAL PROCEDURE[controllingProcess: PROCESS] RETURNS[prevReq,
req: LIST OF IOMasterRequests] =
BEGIN -- non system fatal errors: none.
prevReq ← NIL;
req ← requests;
DO IF req.first.controllingProcess = controllingProcess THEN RETURN;
prevReq ← req;
IF (req ← req.rest) = NIL THEN ERROR;
ENDLOOP;
END;
FinishUp: INTERNAL PROCEDURE[controllingProcess: PROCESS, prevReq, req: LIST OF
IOMasterRequests, who: FpmIO.Who] RETURNS[error: File.RC, errorIORequest: FpmIO.IORequest] =
BEGIN -- non system fatal errors: none.
req.first.nIOsInProgress ← req.first.nIOsInProgress - 1;
IF debugLog # NIL THEN AddToDebugLog[proc: FinishUp, process: controllingProcess, who: who, number: 0, timeOrDeltaTime1: BasicTime.GetClockPulses[], timeOrDeltaTime2: 0, timeOrDeltaTime3: 0];
IF who = idler
THEN BEGIN IF req.first.nIOsInProgress = 0 THEN BROADCAST IdlerFinished; END
ELSE BEGIN
IF req.first.nIOsInProgress # 0 THEN BEGIN
DO
WAIT IdlerFinished;
IF req.first.nIOsInProgress = 0 THEN EXIT;
ENDLOOP;
[prevReq, req] ← FindReqAndPrev[controllingProcess];
END;
IF prevReq = NIL
THEN requests ← req.rest
ELSE prevReq.rest ← req.rest;
nRequests ← nRequests - 1;
NOTIFY IOControllerAvail;
END;
error ← req.first.error;
errorIORequest ← req.first.errorIORequest;
IF debugLog # NIL THEN AddToDebugLog[proc: FinishUp, process: controllingProcess, who: who, number: 0, timeOrDeltaTime1: BasicTime.GetClockPulses[], timeOrDeltaTime2: 0, timeOrDeltaTime3: 0];
END;
Idler: PROCEDURE =
BEGIN -- non system fatal errors:
MonitoredIdler: ENTRY PROCEDURE =
BEGIN -- non system fatal errors: none.
WAIT IdlerNeeded;
END;
DoWork: PROCEDURE =
BEGIN -- non system fatal errors: none.
workToDo: BOOLEAN;
controllingProcess: PROCESS;
io: FpmIO.IOType;
file: File.Handle;
iORequest: FpmIO.IORequest;
[workToDo, controllingProcess, io, file, iORequest] ← RegisterIdler[];
DO
IF (NOT workToDo) THEN RETURN;
DoIO[io, file, iORequest !
File.Error => BEGIN LogError[controllingProcess, idler, why, iORequest];
GOTO errorSeen;
END];
[, , workToDo, iORequest] ← GetNext[controllingProcess: controllingProcess, who: idler];
REPEAT errorSeen => NULL;
ENDLOOP;
END;
DO
MonitoredIdler[];
DoWork[];
ENDLOOP;
END;
DoIO: PUBLIC PROCEDURE[io: FpmIO.IOType, file: File.Handle, iORequest: FpmIO.IORequest] =
BEGIN -- non system fatal errors: none.
deltaTime1: LONG CARDINAL ← BasicTime.GetClockPulses[];
deltaTime2: LONG CARDINAL;
tiny: INT ← iORequest.filePageNumber;
SELECT io FROM
write => BEGIN
IF iORequest.filePageNumber = FpmPF.LeaderFilePageNumber
THEN BEGIN
We aren't supposed to see any leader pages here.
ERROR;
END
ELSE file.Write[[iORequest.filePageNumber], iORequest.nPages, iORequest.vM];
END;
read => BEGIN
IF iORequest.filePageNumber = FpmPF.LeaderFilePageNumber
THEN ERROR -- don't expect this.
ELSE TRUSTED BEGIN file.Read[[iORequest.filePageNumber], iORequest.nPages,
iORequest.vM]; END;
END;
ENDCASE => ERROR;
deltaTime2 ← BasicTime.GetClockPulses[];
IF debugLog # NIL THEN AddToDebugLog[proc: IO, action: io, process: LOOPHOLE[0], who: idler, number: LOOPHOLE[tiny], timeOrDeltaTime1: deltaTime1, timeOrDeltaTime2: deltaTime2, timeOrDeltaTime3: deltaTime2 - deltaTime1];
END;
GenerateIdler: PROCEDURE =
BEGIN -- non system fatal errors: none.
TRUSTED BEGIN Process.Detach[FORK Idler[]]; END;
END;
main line code:
THROUGH [0..maxRequests) DO
GenerateIdler[];
ENDLOOP;
END.
Edit Log
Initial: Kolling: August 25, 1983 3:12 pm: impl module for FilePageManager io.
Nodified: Hauser: February 20, 1985 3:05:56 pm PST
Hauser, March 7, 1985 3:00:51 pm PST
Added copyright.