<> <> <> 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 <> <> <> table: HashTable.Table; <> <> 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]]]}; <> Flush: PUBLIC ENTRY PROC ~ { ENABLE UNWIND => {NULL}; table.Erase[]; table _ NIL}; Reset: PUBLIC ENTRY PROC ~ { ENABLE UNWIND => {NULL}; ResetProj: PROC[proj: Proj] RETURNS[stop: BOOL_FALSE] ~ { 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: BOOL_FALSE] ~ { 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]}; }; <> LoadUpBcd: PROC[file: FS.OpenFile] RETURNS[pages: VM.Interval, base: BcdDefs.BcdBase] ~ TRUSTED { nPages: INT _ MIN[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}; <> 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; <> <> proj.file _ parms.objectFile; proj.symbolPages _ [parms.symbolPages.base-1, parms.symbolPages.pages]; proj.cantOpen _ FALSE; proj.state _ $opened}; <> table _ HashTable.Create[ops~[GetKey, HashFromKey, CompareKeys]]; }.