SMProjImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
last edit by Satterthwaite, May 14, 1986 4:06:04 pm PDT
DIRECTORY
Basics: TYPE USING [BITXOR],
BcdDefs: TYPE USING [Base, BcdBase, FTNull, MTIndex],
CompilerOps: TYPE USING [Transaction],
CS: TYPE USING [EndsIn, PartialName, z],
FS: TYPE USING [Close, Error, GetInfo, Open, OpenFile, nullOpenFile, Read],
HashTable: TYPE USING [Table, Create, Erase, ForEach, Fetch, Store],
Rope: TYPE USING [Concat, --Equal,-- ROPE],
SMProj: TYPE USING [Proj, ProjInfo],
TimeStamp: TYPE USING [Stamp],
VM: TYPE USING [AddressForPageNumber, Allocate, Free, Interval, nullInterval];
SMProjImpl: CEDAR MONITOR
IMPORTS Basics, CS, FS, HashTable, Rope, VM
EXPORTS SMProj ~ {
Proj: TYPE ~ SMProj.Proj; -- can't be opaque with current RedBlackTree impl
all code in this module updates the projection table
therefore all PUBLIC procedures acquire the monitor lock
MDS usage (protected by the monitor lock)
table: HashTable.Table;
end of MDS
operations for cache management
GetKey: PROC[n: Proj] RETURNS[TimeStamp.Stamp] ~ {RETURN[n.stamp]};
CompareKeys: PROC[k1, k2: TimeStamp.Stamp] RETURNS[BOOL] ~ {RETURN[k1 = k2]};
HashFromKey: PROC[k: TimeStamp.Stamp] RETURNS[CARDINAL] ~ {
words: ARRAY [0..3) OF WORD ~ LOOPHOLE[k];
RETURN[Basics.BITXOR[Basics.BITXOR[words[0], words[1]], words[2]]]};
code to manipulate the projection (derived file) cache
Flush: PUBLIC ENTRY PROC ~ {
ENABLE UNWIND => {NULL};
table.Erase[]; table ← NIL};
Reset: PUBLIC ENTRY PROC ~ {
ENABLE UNWIND => {NULL};
ResetProj: PROC[proj: Proj] RETURNS[stop: BOOLFALSE] ~ {
IF proj.state > $analyzed THEN {
proj.file.Close; proj.file ← FS.nullOpenFile;
proj.state ← $analyzed};
proj.cantOpen ← FALSE};
[] ← table.ForEach[ResetProj]};
Erase: PUBLIC ENTRY PROC[proj: Proj] ~ {
ENABLE UNWIND => {NULL};
oldFile: FS.OpenFile ~ proj.file;
IF oldFile ~= FS.nullOpenFile THEN {
EraseProj: PROC[proj: Proj] RETURNS[stop: BOOLFALSE] ~ {
IF oldFile = proj.file THEN {
proj.state ← MIN[proj.state, $analyzed];
proj.file.Close; proj.file ← FS.nullOpenFile;
proj.cantOpen ← TRUE;
proj.localName ← NIL}
};
[] ← table.ForEach[EraseProj]};
};
Analyzed: PUBLIC ENTRY PROC[proj: Proj] RETURNS[BOOL] ~ {
ENABLE UNWIND => {NULL};
RETURN[proj # NIL AND proj.state >= $analyzed]};
Available: PUBLIC ENTRY PROC[proj: Proj] RETURNS[BOOL] ~ {
ENABLE UNWIND => {NULL};
RETURN[proj # NIL AND proj.state = $opened]};
Fill: PUBLIC ENTRY PROC[proj: Proj, localName, wDir: Rope.ROPE, new: BOOL] ~ {
ENABLE UNWIND => {NULL};
IF proj.state < $opened THEN {
proj.localName ←
(IF CS.EndsIn[localName, ".bcd"] THEN localName ELSE localName.Concat[".bcd"]);
proj.wDir ← (IF CS.PartialName[localName] THEN wDir ELSE NIL);
IF ~new AND ~proj.cantOpen THEN OpenProj[proj]};
};
Find: PUBLIC ENTRY PROC[stamp: TimeStamp.Stamp] RETURNS[proj: Proj] ~ {
ENABLE UNWIND => {NULL};
proj ← table.Fetch[stamp].value;
IF proj = NIL THEN {
proj ← (CS.z).NEW[SMProj.ProjInfo ← [stamp~stamp, state~$empty]];
[] ← table.Store[stamp, proj]};
RETURN};
Read: PUBLIC ENTRY PROC[proj: Proj]
RETURNS[pages: VM.Interval, base: BcdDefs.BcdBase] ~ {
ENABLE UNWIND => {NULL};
RETURN (IF proj = NIL OR proj.file = FS.nullOpenFile
THEN [VM.nullInterval, NIL] ELSE LoadUpBcd[proj.file])
};
FindFile: PROC[proj: Proj] RETURNS[file: FS.OpenFile] ~ {
file ← FS.Open[name~proj.localName, wDir~proj.wDir
! FS.Error => {file ← FS.nullOpenFile; CONTINUE}];
RETURN};
OpenProj: PROC[proj: Proj] ~ {
file: FS.OpenFile ~ FindFile[proj];
IF file = FS.nullOpenFile THEN proj.cantOpen ← TRUE
ELSE IF proj.state = $analyzed THEN {
proj.file ← file; proj.state ← $opened}
ELSE TRUSTED {
bcdBase: BcdDefs.BcdBase;
interval: VM.Interval;
[interval, bcdBase] ← LoadUpBcd[file];
IF bcdBase.version ~= proj.stamp THEN proj.cantOpen ← TRUE
ELSE { -- should reject configs, etc.
firstMti: BcdDefs.MTIndex ~ BcdDefs.MTIndex.FIRST;
mtb: BcdDefs.Base ~ LOOPHOLE[bcdBase + bcdBase.mtOffset];
sgb: BcdDefs.Base ~ LOOPHOLE[bcdBase + bcdBase.sgOffset];
proj.interface ← bcdBase.definitions;
proj.symbolPages ← (IF sgb[mtb[firstMti].sseg].file = BcdDefs.FTNull
THEN [base~0, pages~0]
ELSE [base~sgb[mtb[firstMti].sseg].base-1, pages~sgb[mtb[firstMti].sseg].pages]);
proj.file ← file;
proj.state ← $opened};
VM.Free[interval]};
};
NB: a procedure identical to the following appears in SMFIImpl. Refactor?
LoadUpBcd: PROC[file: FS.OpenFile]
RETURNS[pages: VM.Interval, base: BcdDefs.BcdBase] ~ TRUSTED {
nPages: INTMIN[10, file.GetInfo[].pages];
pages ← VM.nullInterval; base ← NIL;
IF file = FS.nullOpenFile THEN ERROR;
DO
pages ← VM.Allocate[count~nPages];
base ← VM.AddressForPageNumber[pages.page];
FS.Read[file~file, from~0, nPages~nPages, to~base];
IF base.nPages <= nPages THEN EXIT;
nPages ← base.nPages;
VM.Free[pages]; pages ← VM.nullInterval
ENDLOOP;
RETURN};
for proj info provided by the compiler
Update: PUBLIC ENTRY PROC[
proj: Proj, parms: REF READONLY CompilerOps.Transaction] ~ {
ENABLE UNWIND => {NULL};
IF proj.stamp # parms.objectVersion THEN ERROR;
proj.interface ← parms.interface;
IF ~(proj.localName).Equal[parms.objectName, FALSE] THEN
proj.localName ← parms.objectName;
proj.file ← parms.objectFile;
proj.symbolPages ← [parms.symbolPages.base-1, parms.symbolPages.pages];
proj.cantOpen ← FALSE; proj.state ← $opened};
start code
table ← HashTable.Create[ops~[GetKey, HashFromKey, CompareKeys]];
}.