-- FilePageMgrIOImpl.mesa
-- 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, WriteProperties],
FilePageMgrIO
USING[IORequest, IOType, Who],
FilePageMgrPrivateFile
USING[LeaderFilePageNumber],
Process
USING
[Detach];


FilePageMgrIOImpl: CEDAR MONITOR
IMPORTS BasicTime, File, Process
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;
--debugLog: LIST OF DebugEntries ← NIL;
--restDebugLog: LIST OF DebugEntries ← NIL;
--DebugEntries: TYPE = RECORD[proc: {RegReq, RegIdler, GetNext, FinishUp, IO}, process: PROCESS, who: FpmIO.Who, number: INT, timeOrDeltaTime1, timeOrDeltaTime2, timeOrDeltaTime3: BasicTime.Pulses];

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;
--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}, process:
--PROCESS, who: FpmIO.Who, number: INT, timeOrDeltaTime1, timeOrDeltaTime2, timeOrDeltaTime3: BasicTime.Pulses] = INLINE
--BEGIN
--debugLog ← CONS[[proc: proc, process: process, who: who,
--number: number, timeOrDeltaTime1: BasicTime.PulsesToMicroseconds[timeOrDeltaTime1], timeOrDeltaTime2: BasicTime.PulsesToMicroseconds[timeOrDeltaTime2], timeOrDeltaTime3: BasicTime.PulsesToMicroseconds[timeOrDeltaTime3]],
--debugLog];
--IF
restDebugLog = NIL
--THEN BEGIN
restDebugLogdebugLog;
--END
--ELSE BEGIN
saveDebugLog: LIST OF DebugEntries ← debugLog.rest;
--restDebugLog.rest ← debugLog;
--debugLog.rest ← NIL;
--debugLog ← saveDebugLog;
--restDebugLog ← restDebugLog.rest;
--END;
--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;
--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;
--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;
--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;
--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;
--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 file.WriteProperties[]
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;
deltaTime2BasicTime.GetClockPulses[];
--AddToDebugLog[proc: 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.