-- Cache.Mesa Edited by Sandman on July 10, 1980 7:41 AM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY AllocDefs USING [ AddSwapStrategy, CantSwap, RemoveSwapStrategy, SwappingProcedure, SwapStrategy, TryCodeSwapping], AltoDefs USING [BytesPerPage, PageNumber, PageSize], AltoFileDefs USING [eofDA], CacheOps USING [CoreSegment, CoreSegmentObject, PageItem], BootmesaOps USING [MakeResident], InlineDefs USING [BITAND], SegmentDefs USING [ Append, DefaultVersion, DeleteFileSegment, FileHandle, FileSegmentAddress, FileSegmentHandle, GetFileSegmentDA, LockFile, NewFile, NewFileSegment, Read, ReleaseFile, SegmentFault, SetEndOfFile, SetFileSegmentDA, Unlock, UnlockFile, Write], Storage USING [Words, FreeWords]; Cache: PROGRAM IMPORTS AllocDefs, BootmesaOps, InlineDefs, SegmentDefs, Storage EXPORTS CacheOps = BEGIN OPEN CacheOps; SwapStrategy: TYPE = AllocDefs.SwapStrategy; PageNumber: TYPE = AltoDefs.PageNumber; FileHandle: TYPE = SegmentDefs.FileHandle; FileSegmentHandle: TYPE = SegmentDefs.FileSegmentHandle; PageSize: CARDINAL = AltoDefs.PageSize; DefaultCacheSize: CARDINAL _ 50; -- number of pages to keep in core maxsegments: CARDINAL _ 0; -- number of pages to keep in core CS: DESCRIPTOR FOR ARRAY OF CoreSegmentObject; CoreFile: SegmentDefs.FileHandle; PageList: DESCRIPTOR FOR ARRAY OF PageItem; Fpage: PageNumber; -- last page allocated in file CacheSwap: SwapStrategy _ SwapStrategy[link:, proc: AllocDefs.CantSwap]; CodeSwap: SwapStrategy _ SwapStrategy[link:, proc: AllocDefs.TryCodeSwapping]; first, last: PageNumber; createAllowed: BOOLEAN _ TRUE; Init: PUBLIC PROCEDURE [name: STRING, firstPage, lastPage: PageNumber] = BEGIN OPEN Storage, SegmentDefs; i: CARDINAL; IF maxsegments = 0 THEN SetCacheSize[DefaultCacheSize]; PageList _ DESCRIPTOR[Words[(lastPage + 1)*SIZE[PageItem]], lastPage + 1 --, PageItem--]; FOR i IN [0..lastPage] DO PageList[i].page _ 0 ENDLOOP; CoreFile _ NewFile[name, Read + Write + Append, DefaultVersion]; LockFile[CoreFile]; Fpage _ 0; AllocDefs.AddSwapStrategy[@CacheSwap]; AllocDefs.AddSwapStrategy[@CodeSwap]; first _ firstPage; last _ lastPage; createAllowed _ TRUE; RETURN END; Close: PUBLIC PROCEDURE = BEGIN OPEN SegmentDefs; Storage.FreeWords[BASE[CS]]; Storage.FreeWords[BASE[PageList]]; IF CoreFile.lock # 0 THEN UnlockFile[CoreFile]; IF CoreFile.lock = 0 THEN ReleaseFile[CoreFile]; AllocDefs.RemoveSwapStrategy[@CacheSwap]; AllocDefs.RemoveSwapStrategy[@CodeSwap]; maxsegments _ 0; RETURN END; Flush: PUBLIC AllocDefs.SwappingProcedure = BEGIN did: BOOLEAN _ FALSE; i: CARDINAL; cs: CoreSegment; CacheSwap.proc _ AllocDefs.CantSwap; FOR i IN [0..maxsegments) DO cs _ @CS[i]; IF cs.segment # NIL THEN BEGIN OPEN SegmentDefs; did _ TRUE; Unlock[cs.segment]; DeleteFileSegment[cs.segment]; cs.segment _ NIL; END; ENDLOOP; RETURN[did]; END; NewCoreSegment: PUBLIC PROCEDURE [p: POINTER TO PageItem, cs: CoreSegment] = BEGIN OPEN SegmentDefs; s: FileSegmentHandle _ NewFileSegment[CoreFile, p.page, 1, Read]; SetFileSegmentDA[s, p.da]; BootmesaOps.MakeResident[ s ! SegmentFault => BEGIN SetEndOfFile[CoreFile, p.page, AltoDefs.BytesPerPage]; RETRY; END]; p.da _ GetFileSegmentDA[s]; cs.page _ p.page; cs.segment _ s; RETURN END; CSrover: CARDINAL _ 0; GetCS: PUBLIC PROCEDURE [p: PageItem] RETURNS [FileSegmentHandle] = BEGIN i: CARDINAL; s: FileSegmentHandle; sp: CoreSegment; BEGIN FOR i IN [0..maxsegments) DO sp _ @CS[i]; IF sp.segment = NIL THEN GOTO newseg; IF sp.page = p.page THEN EXIT; REPEAT FINISHED => BEGIN OPEN SegmentDefs; WHILE ~(sp _ @CS[CSrover]).old DO sp.old _ TRUE; CSrover _ (CSrover + 1) MOD maxsegments; ENDLOOP; CSrover _ (CSrover + 1) MOD maxsegments; s _ sp.segment; sp.segment _ NIL; Unlock[s]; DeleteFileSegment[s]; GOTO newseg; END ENDLOOP; EXITS newseg => BEGIN cso: CoreSegmentObject; NewCoreSegment[@p, @cso]; FOR i IN [0..maxsegments) DO sp _ @CS[i]; IF sp.segment = NIL THEN BEGIN sp^ _ cso; EXIT END; REPEAT FINISHED => ERROR ENDLOOP; END; END; sp.old _ FALSE; CacheSwap.proc _ Flush; RETURN[sp.segment] END; BadReadWrite: PUBLIC ERROR = CODE; CheckPage: PROCEDURE [cp: PageNumber] = BEGIN IF PageList[cp].page # 0 THEN RETURN; IF ~createAllowed THEN ERROR BadReadWrite; PageList[cp] _ PageItem[page: Fpage _ Fpage + 1, da: AltoFileDefs.eofDA]; RETURN END; READ: PUBLIC PROCEDURE [a: UNSPECIFIED] RETURNS [UNSPECIFIED] = BEGIN OPEN InlineDefs; cp: PageNumber; cp _ LOOPHOLE[a, CARDINAL]/PageSize; IF cp~ IN [first..last] THEN ERROR BadReadWrite; CheckPage[cp]; RETURN[ (SegmentDefs.FileSegmentAddress[GetCS[PageList[cp]]] + BITAND[ a, PageSize - 1])^]; END; WRITE: PUBLIC PROCEDURE [a: UNSPECIFIED, v: UNSPECIFIED] = BEGIN OPEN InlineDefs; cp: PageNumber; s: SegmentDefs.FileSegmentHandle; cp _ LOOPHOLE[a, CARDINAL]/PageSize; IF cp~ IN [first..last] THEN ERROR BadReadWrite; CheckPage[cp]; (SegmentDefs.FileSegmentAddress[s _ GetCS[PageList[cp]]] + BITAND[ a, PageSize - 1])^ _ v; s.write _ TRUE; RETURN END; CopyWrite: PUBLIC PROCEDURE [from, to: POINTER, size: CARDINAL] = BEGIN i: CARDINAL; FOR i IN [0..size) DO WRITE[to + i, (from + i)^]; ENDLOOP; RETURN END; CopyRead: PUBLIC PROCEDURE [from, to: POINTER, size: CARDINAL] = BEGIN i: CARDINAL; FOR i IN [0..size) DO (to + i)^ _ READ[from + i]; ENDLOOP; RETURN END; GetPageItem: PUBLIC PROCEDURE [page: CARDINAL] RETURNS [p: PageItem] = BEGIN p _ PageList[page]; RETURN END; SetPageItem: PUBLIC PROCEDURE [page: CARDINAL, p: PageItem] = BEGIN PageList[page] _ p; RETURN END; SetCoreFile: PUBLIC PROCEDURE [file: FileHandle] = BEGIN CoreFile _ file; createAllowed _ FALSE; RETURN END; GetCoreFile: PUBLIC PROCEDURE RETURNS [FileHandle] = BEGIN RETURN[CoreFile] END; SetCacheSize: PUBLIC PROCEDURE [size: CARDINAL] = BEGIN OPEN Storage; i: CARDINAL; maxsegments _ size; CS _ DESCRIPTOR[Words[maxsegments*SIZE[CoreSegmentObject]], maxsegments]; FOR i IN [0..maxsegments) DO CS[i].segment _ NIL ENDLOOP; END; END.