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: BOOLEAN _ TRUE, 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: INT _ LOOPHOLE[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 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; 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 6FilePageMgrIOImpl.mesa Copyright c 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 We aren't supposed to see any leader pages here. main line code: Hauser, March 7, 1985 3:00:51 pm PST Added copyright. Κ ˜J˜J˜šœ™Icodešœ Οmœ1™<—šœ™Jšœ*™*Jšœ)™)—J˜JšΟk ˜ ˜˜ Jšžœ/˜4—˜Jšžœžœ˜.—˜ Jšžœ˜—˜Jšžœ˜—J˜˜Jšžœ ˜—J˜šœ˜Jšžœ ˜J˜J˜——šΟnœžœž˜ Jšžœ&˜-Jšžœ˜J˜J˜—Jšžœžœ5˜?J˜J˜Jšœ žœžœžœ˜)Jšœ žœ˜Jšœ žœΟc5˜LJ˜š œžœžœžœžœ˜TJšœ žœ3žœ˜WJšœžœžœ˜2J˜—Jšœž œ˜Jšœž œ˜Jšœ ž œ˜J˜Jšœžœ˜šœ žœžœ˜Jšœ žœžœ˜Jšœ!˜!Jšœ žœžœ ˜1J˜J˜—Jšžœžœžœ˜Jšœ8žœ˜J˜——šžœ˜J˜J˜——š Ÿ œžœž œžœ žœ˜MJšžœD˜Kšžœ "˜(š žœžœžœ&žœž˜Iš žœžœžœžœžœžœ˜IJšœ žœ˜J˜2J˜J˜J˜!J˜%Jšœžœ˜Jšžœ?žœžœ˜LJšžœ žœžœΒ˜ΨJšžœ˜Jšžœ˜——Jšžœ˜Jšœ žœ˜—šžœ˜J˜J˜——š Ÿœžœžœž œžœ˜LJšžœ žœ-žœ ˜VJ˜šžœ "˜(Jšœžœžœ˜'J˜4šžœ#žœ žœžœ˜Všžœžœ˜ Jšœ žœ˜šžœ žœžœD˜ZJšœc˜c—J˜JJšž˜—šžœžœ˜ Jšœ!˜!šžœ žœžœD˜ZJšœz˜z—J˜%Jšžœ˜———šžœ˜J˜J˜——š Ÿœžœžœž œžœ˜RJ˜/šžœ "˜(Jšœžœžœ˜'J˜4J˜J˜*J˜5—šžœ˜J˜J˜——š Ÿœžœž œžœžœ ˜PJšœžœžœ˜ šžœ "˜(Jšœ žœ˜J˜Jšžœžœ3žœžœ˜DJ˜Jšžœžœžœžœ˜%Jšžœ˜—šžœ˜J˜J˜——š Ÿœžœž œžœžœž˜OJšœ"žœ žœ$˜\šžœ "˜(J˜8Jšžœ žœžœ©˜Ώšžœ ˜Jš žœžœžœžœž œž˜Lšžœž˜ šžœžœž˜+šžœ˜Jšžœ˜Jšžœžœžœ˜*—Jšžœ˜J˜4Jšžœ˜—šžœ ž˜Jšžœ˜Jšžœ˜—J˜Jšžœ˜Jšžœ˜——J˜J˜*Jšžœ žœžœ©˜Ώ—šžœ˜˜J˜———šŸœž œ˜šžœ ˜#šŸœžœž œ˜!šžœ "˜(Jšžœ ˜—Jšžœ˜—šŸœž œ˜šžœ !˜'Jšœ žœ˜Jšœžœ˜J˜J˜J˜J˜Fšž˜Jšžœžœ žœžœ˜˜šœžœ5˜HJšžœ ˜Jšžœ˜——J˜XJšžœžœ˜—Jšžœ˜—Jšžœ˜—šž˜J˜J˜ —Jšžœ˜—Jšžœ˜J˜J˜—šŸœžœž œC˜Yšžœ !˜'Jšœ žœžœ˜7Jšœ žœžœ˜Jšœžœ˜%šžœž˜šœ ž˜šžœ6˜8šžœž˜ J™0Jšž˜Jšž˜—JšžœH˜L—Jšžœ˜—šœ ž˜šžœ6˜8Jšžœžœ ˜!šžœžœžœ8˜JJšœžœ˜——Jšžœ˜——Jšžœžœ˜J˜(Jšžœ žœžœžœžœ žœžœo˜ά—Jšžœ˜J˜J˜J˜—šŸ œž œ˜šžœ !˜'Jšžœžœžœ žœ˜0—Jšžœ˜J˜J˜J˜—Jšœ™J˜šžœž˜J˜—šžœ˜J˜J˜J˜—Jšžœ˜˜J˜J˜—J˜NJ˜2J˜J˜™$K™—K™—…—%Ό2