RTGetSymbolsImpl.mesa
Last Modified By Paul Rovner On March 31, 1983 1:34 pm
Last Modified By Russ Atkinson On June 28, 1983 6:18 pm
altering VersionToReadableFile to spec
DIRECTORY
AMTypes USING[Error],
BcdDefs USING[VersionStamp, NameRecord, MTIndex, SGIndex, SGNull, FTNull,
FTSelf, VersionID, FTIndex, NullVersion],
BcdOps USING[BcdBase, NameString, MTHandle, SGHandle, ProcessModules,
FTHandle, ProcessFiles],
BrandXSymbolDefs USING[rootBodyIndex, nullSymbolIndex, SymbolTableBase,
SymbolModuleIndex],
BrandYSymbolDefs USING[rootBodyIndex, nullSymbolIndex, SymbolTableBase,
SymbolModuleIndex],
CIFS USING[GetFC, Open, read, dontCheck, OpenFile],
ConvertUnsafe USING[AppendRope, ToRope],
File USING[Capability, nullCapability],
FileSegment USING[Pages],
LongString USING[AppendString],
PilotLoadStateFormat USING[ModuleInfo, ConfigIndex],
PilotLoadStateOps USING[InputLoadState, GetModule, AcquireBcd, ReleaseBcd,
ReleaseLoadState, EnumerateBcds],
PrincOps USING[GlobalFrameHandle],
NewRCMapOps USING[EstablishOuter],
Rope USING[ROPE, Flatten, Length, Fetch, Concat],
RTFiles USING [SameFile], -- EXPORTS
RTFilesExtra USING [], -- EXPORTS only
RTFlags USING[checking],
RTOS USING[EnumerateGlobalFrames, SameCode, UnRavelUSUs],
RTSymbolDefs USING[SymbolTableBase, SymbolTableHandle, nullHandle, nullBase,
SymbolModuleIndex],
RTSymbolOps USING[STBToModuleName, STBVersion, SubStringForHash, NullModuleIndex,
NullSth],
RTSymbols USING[], -- EXPORTS only
RTSymbolsPrivate USING[], -- EXPORTS only
RTTypesBasicPrivate USING[SymbolTableIndex, MapStiStd, FindSTI, STDesc],
Runtime USING[CallDebugger, ValidateGlobalFrame],
Space USING[Map, LongPointer, Unmap, GetAttributes, GetWindow, GetHandle,
PageFromLongPointer, Handle, Create, virtualMemory, Delete],
Strings USING[SubStringDescriptor, AppendSubString, AppendString,
EqualSubStrings],
SymbolTable USING[SetCacheSize, Release, Acquire, Forget, anySpan],
Table USING[Base],
VersionMap USING[MapList],
VersionMapDefaults USING[FileNameFromVersion, GetMapList];
RTGetSymbolsImpl: MONITOR
IMPORTS AMTypes, BcdOps, CIFS, ConvertUnsafe, LongString,
PilotLoadStateOps, NewRCMapOps, Rope, RTFiles, RTOS, RTSymbolOps, RTTypesBasicPrivate,
Runtime, Space, Strings, SymbolTable, VersionMapDefaults
EXPORTS RTFiles, RTFilesExtra, RTSymbols, RTSymbolsPrivate
SHARES File
= BEGIN OPEN bx: BrandXSymbolDefs, by: BrandYSymbolDefs,
XSymbolTable: SymbolTable, YSymbolTable: SymbolTable,
XRCMapOps: NewRCMapOps, YRCMapOps: NewRCMapOps,
RTSymbolDefs, RTSymbolOps;
Variables protected by the monitor
onePageSpace: Space.Handle = Space.Create[size: 1, parent: Space.virtualMemory];
standardBCDSpaces: LIST OF Space.Handle ← NIL;
standardBCDSpacePages: NAT = 20;
standardBCDSpacesInUse: NAT ← 0;
standardBCDSpacesHeld: NAT ← 0;
biggerBCDSpacesInUse: NAT ← 0;
OZ: BOOLFALSE;
ROPE: TYPE = Rope.ROPE;
-- PUBLIC PROCS --
Outer: PUBLIC PROC[stb: SymbolTableBase,
mdi: SymbolModuleIndex,
inner: PROC[base: SymbolTableBase],
mesaSymbolsOK: BOOLFALSE] =
{stb1: SymbolTableBase = AcquireSTBFromMDI[stb, mdi, mesaSymbolsOK];
inner[stb1 ! UNWIND => ReleaseSTB[stb1]];
ReleaseSTB[stb1]};
AcquireSTBForDefs: PUBLIC PROC[fileName: ROPE--ends with .bcd--]
RETURNS[stb: SymbolTableBase] =
{ mn: STRING = [100];
dotFound: BOOLFALSE;
FOR i: NAT IN [0..Rope.Length[fileName])
DO IF Rope.Fetch[fileName, i] = '. THEN {dotFound ← TRUE; EXIT};
ENDLOOP;
IF NOT dotFound THEN fileName ← Rope.Concat[fileName, ".bcd"];
mn.length ← 0;
ConvertUnsafe.AppendRope[from: fileName, to: LONG[mn]];
IF mn.length<=4 THEN ERROR AMTypes.Error[reason: noSymbols, msg: fileName];
mn.length ← mn.length-4;
stb ← AcquireSTB[GetSTHForModule[stamp: BcdDefs.NullVersion,
fileName: fileName,
moduleName: ConvertUnsafe.ToRope[LONG[mn]]]];
IF NOT (WITH stb SELECT FROM
t: SymbolTableBase.x => t.e.stHandle.definitionsFile,
t: SymbolTableBase.y => t.e.stHandle.definitionsFile,
ENDCASE => ERROR)
THEN {ReleaseSTB[stb];
ERROR AMTypes.Error[reason: noSymbols,
msg: Rope.Concat[fileName, " not a defs module"]]};
};
AcquireSTB: PUBLIC PROC[sth: SymbolTableHandle, mesaSymbolsOK: BOOLFALSE]
RETURNS[stb: SymbolTableBase] =
{stb ← WITH sth SELECT FROM
t: SymbolTableHandle.x => [x[XSymbolTable.Acquire[t.e]]],
t: SymbolTableHandle.y => [y[YSymbolTable.Acquire[t.e]]]
ENDCASE => ERROR;
IF mesaSymbolsOK THEN RETURN[stb];
groan. backward compatibility for limited usage
(for RTSymbols clients only, NOT for AMTypes)
IF NOT (WITH stb SELECT FROM
t: SymbolTableBase.x => t.e.stHandle.extended,
t: SymbolTableBase.y => t.e.stHandle.extended,
ENDCASE => ERROR) -- symbol table made by an old version of the compiler
OR (WITH stb SELECT FROM
t: SymbolTableBase.x => t.e.bb[bx.rootBodyIndex].type = bx.nullSymbolIndex,
t: SymbolTableBase.y => t.e.bb[by.rootBodyIndex].type = by.nullSymbolIndex,
ENDCASE => ERROR)
THEN {modName: ROPE = STBToModuleName[stb ! UNWIND => ReleaseSTB[stb]];
ReleaseSTB[stb];
ERROR AMTypes.Error[reason: noSymbols, msg: modName]}
ELSE RETURN[stb]};
ReleaseSTB: PUBLIC PROC[stb: SymbolTableBase] =
{WITH stb SELECT FROM
t: SymbolTableBase.x => XSymbolTable.Release[t.e];
t: SymbolTableBase.y => YSymbolTable.Release[t.e]
ENDCASE => ERROR};
STPages: PUBLIC PROC[sth: SymbolTableHandle] RETURNS[CARDINAL] =
{RETURN[WITH sth SELECT FROM
t: SymbolTableHandle.x => t.e.span.pages,
t: SymbolTableHandle.y => t.e.span.pages,
ENDCASE => ERROR]};
this may return nullHandle but will not raise any signals
AcquireSTHFromSTX: PUBLIC PROC[stx: RTTypesBasicPrivate.SymbolTableIndex]
RETURNS[sth: SymbolTableHandle ← nullHandle, moduleName: ROPENIL] =
{[sth, moduleName] ← DoAcquireSTHFromSTX[stx, TRUE]};
DoAcquireSTHFromSTX: PROC[stx: RTTypesBasicPrivate.SymbolTableIndex,
invokeGetSTHForModule: BOOLFALSE]
RETURNS[sth: SymbolTableHandle ← nullHandle, moduleName: ROPENIL] =
{ symbolsStamp: BcdDefs.VersionStamp;
bcd: BcdOps.BcdBase;
IF NOT NullSth[RTTypesBasicPrivate.MapStiStd[stx].sth]
THEN RETURN[sth: RTTypesBasicPrivate.MapStiStd[stx].sth];
symbolsStamp ← RTTypesBasicPrivate.MapStiStd[stx].symbolsStamp;
bcd ← RTTypesBasicPrivate.MapStiStd[stx].bcd;
IF bcd = NIL
THEN {IF invokeGetSTHForModule
THEN sth ← GetSTHForModule[stamp: symbolsStamp,
fileName: NIL,
moduleName: NIL
! ANY => CONTINUE]
ELSE RETURN}
ELSE
{sgb: Table.Base = LOOPHOLE[bcd + bcd.sgOffset];
ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset];
ssb: BcdOps.NameString = LOOPHOLE[bcd + bcd.ssOffset];
fti: BcdDefs.FTIndex;
sgi: BcdDefs.SGIndex = RTTypesBasicPrivate.MapStiStd[stx].sgi; -- maybe SGNull
(=> search the BCD's file table)
IF sgi = BcdDefs.SGNull -- search the BCD's file table (find a DEFs)
THEN { findSymbolFTI: PROC[ffth: BcdOps.FTHandle, ffti: BcdDefs.FTIndex]
RETURNS[stop: BOOL] =
{ IF NOT EQStamps[ffth.version, symbolsStamp] THEN RETURN[FALSE];
moduleName ← GetModuleName[ssb, ffth.name];
sth ← GetSTHForModule[stamp: symbolsStamp,
fileName: Rope.Concat[moduleName, ".bcd"],
moduleName: moduleName
! AMTypes.Error => CONTINUE];
RETURN[TRUE]};
IF NOT invokeGetSTHForModule THEN RETURN;
[] ← BcdOps.ProcessFiles[bcd, findSymbolFTI];
IF NullSth[sth]
THEN sth ← GetSTHForModule[stamp: symbolsStamp,
fileName: NIL,
moduleName: NIL
! ANY => CONTINUE];
RTTypesBasicPrivate.MapStiStd[stx].sth ← sth;
RETURN}
ELSE fti ← sgb[sgi].file;
IF fti = BcdDefs.FTSelf
THEN {OPEN Space;
file: File.Capability = FileFromBcdBase[bcd];
IF file # File.nullCapability
THEN
{p: FileSegment.Pages =
[file: file,
span: [base: sgb[sgi].base, pages: sgb[sgi].pages + sgb[sgi].extraPages]];
sth ← IF IsXBCD[bcd] THEN [x[p]] ELSE [y[p]]};
}
ELSE { -- look for the specified file
fileName: ROPE = GetFileName[ssb, ftb[fti].name];
moduleName ← GetModuleName[ssb, ftb[fti].name];
sth ← NewSymbolHandle[fileName: fileName,
version: ftb[sgb[sgi].file].version,
of indicated bcd. Should match bcd.version
base: sgb[sgi].base,
pages: sgb[sgi].pages + sgb[sgi].extraPages
! AMTypes.Error => CONTINUE]
};
}; -- end ELSE (i.e. bcd # NIL)
RTTypesBasicPrivate.MapStiStd[stx].sth ← sth;
}; -- end DoAcquireSTHFromSTX
version must match bcd.version
NewSymbolHandle: PUBLIC PROC[fileName: ROPE,
base: CARDINAL,
pages: CARDINAL,
version: BcdDefs.VersionStamp ← BcdDefs.NullVersion]
RETURNS[sth: SymbolTableHandle ← nullHandle] =
{ file: File.Capability ← File.nullCapability;
stb: SymbolTableBase;
symbolsStamp: BcdDefs.VersionStamp;
isXBCD: BOOL = TRUE; -- NOTE XXX
IF EQStamps[version, BcdDefs.NullVersion]
THEN file ← GetReadCapability[fileName ! ANY => CONTINUE]
ELSE file ← AcquireFCFromVersion[version, fileName];
IF file = File.nullCapability THEN ERROR AMTypes.Error[reason: noSymbols, msg: fileName];
here if file is found and version matches
sth ← IF isXBCD THEN [x[[file: file, span: [base: base, pages: pages]]]]
ELSE [y[[file: file, span: [base: base, pages: pages]]]];
stb ← AcquireSTB[sth];
symbolsStamp ← STBVersion[stb];
ReleaseSTB[stb];
[] ← RTTypesBasicPrivate.FindSTI[[symbolsStamp: symbolsStamp, sth: sth]];
}; -- end NewSymbolHandle
IsFileInUse: PUBLIC PROC[file: File.Capability] RETURNS[found: BOOLFALSE] =
{ loadStateHeld: BOOL;
p: PROC[c: PilotLoadStateFormat.ConfigIndex] RETURNS[stop: BOOL] =
{OPEN Space;
ptr: LONG POINTER = LOOPHOLE[PilotLoadStateOps.AcquireBcd[c]];
space: Handle ← RTOS.UnRavelUSUs[GetHandle[PageFromLongPointer[ptr]]];
PilotLoadStateOps.ReleaseBcd[LOOPHOLE[ptr]];
IF file.fID = GetWindow[space].file.fID
THEN {found ← TRUE; RETURN[TRUE]}
ELSE RETURN[FALSE];
};
try for the local lockbox first
IF IsFileUsed[file] THEN RETURN [TRUE];
flush the SymbolCache
XSymbolTable.Forget[[file: file, span: XSymbolTable.anySpan]
! ANY => {found ← TRUE; CONTINUE}];
IF found THEN RETURN;
YSymbolTable.Forget[[file: file, span: YSymbolTable.anySpan]
! ANY => {found ← TRUE; CONTINUE}];
IF found THEN RETURN;
enumerate the loadstate
[] ← PilotLoadStateOps.InputLoadState[];
loadStateHeld ← TRUE;
[] ← PilotLoadStateOps.EnumerateBcds[recentfirst, p
! ANY => {loadStateHeld ← FALSE;
PilotLoadStateOps.ReleaseLoadState[]}];
IF loadStateHeld THEN PilotLoadStateOps.ReleaseLoadState[];
IF found THEN RETURN;
enumerate MapStiStd
FOR x: NAT IN [1..RTTypesBasicPrivate.MapStiStd.length)
DO sth: SymbolTableHandle;
f: File.Capability;
b: BOOL;
IF RTTypesBasicPrivate.MapStiStd[x] = NIL THEN EXIT;
sth ← RTTypesBasicPrivate.MapStiStd[x].sth;
IF NullSth[sth] THEN LOOP;
SELECT sth FROM
t: SymbolTableHandle.x => b ← TRUE;
t: SymbolTableHandle.y => b ← FALSE;
ENDCASE => ERROR;
IF sth.brand = x
THEN f ← NARROW[sth, SymbolTableHandle.x].e.file
ELSE f ← NARROW[sth, SymbolTableHandle.y].e.file;
IF f.fID = file.fID THEN RETURN[TRUE];
ENDLOOP;
};
RCMapOuterX: PROC[stb: bx.SymbolTableBase,
mdi: bx.SymbolModuleIndex,
inner: PROC[base: bx.SymbolTableBase]] =
{stb1: SymbolTableBase = AcquireSTBFromMDI[[x[stb]], [x[mdi]]];
inner[NARROW[stb1, SymbolTableBase.x].e ! UNWIND => ReleaseSTB[stb1]];
ReleaseSTB[stb1]};
RCMapOuterY: PROC[stb: by.SymbolTableBase,
mdi: by.SymbolModuleIndex,
inner: PROC[base: by.SymbolTableBase]] =
{stb1: SymbolTableBase = AcquireSTBFromMDI[[y[stb]], [y[mdi]]];
inner[NARROW[stb1, SymbolTableBase.y].e ! UNWIND => ReleaseSTB[stb1]];
ReleaseSTB[stb1]};
AcquireSTBFromMDI: PUBLIC PROC[stb: SymbolTableBase,
mdi: SymbolModuleIndex,
mesaSymbolsOK: BOOLFALSE]
RETURNS[SymbolTableBase] =
{ fileNameDesc, modNameDesc: Strings.SubStringDescriptor;
fileName: STRING = [100];
modName: STRING = [100];
IF NullModuleIndex[mdi] THEN ERROR;
fileName.length ← 0;
modName.length ← 0;
SubStringForHash[stb,
@modNameDesc,
WITH stb SELECT FROM
t: SymbolTableBase.x =>
[x[t.e.mdb[NARROW[mdi, SymbolModuleIndex.x].e].moduleId]],
t: SymbolTableBase.y =>
[y[t.e.mdb[NARROW[mdi, SymbolModuleIndex.y].e].moduleId]],
ENDCASE => ERROR];
Strings.AppendSubString[modName, @modNameDesc];
SubStringForHash[stb,
@fileNameDesc,
WITH stb SELECT FROM
t: SymbolTableBase.x =>
[x[t.e.mdb[NARROW[mdi, SymbolModuleIndex.x].e].fileId]],
t: SymbolTableBase.y =>
[y[t.e.mdb[NARROW[mdi, SymbolModuleIndex.y].e].fileId]],
ENDCASE => ERROR];
Strings.AppendSubString[fileName, @fileNameDesc];
RETURN[AcquireSTB[GetSTHForModule
[(WITH stb SELECT FROM
t: SymbolTableBase.x =>
t.e.mdb[NARROW[mdi, SymbolModuleIndex.x].e].stamp,
t: SymbolTableBase.y =>
t.e.mdb[NARROW[mdi, SymbolModuleIndex.y].e].stamp,
ENDCASE => ERROR),
ConvertUnsafe.ToRope[LONG[fileName]],
ConvertUnsafe.ToRope[LONG[modName]]],
mesaSymbolsOK]]};
stamp on the MODULE, maybe different than bcd.version
GetSTHForModule: PUBLIC PROC[stamp: BcdDefs.VersionStamp,
fileName: ROPE, -- maybe NIL
moduleName: ROPE -- maybe NIL
]
RETURNS[sth: SymbolTableHandle ← nullHandle] =
{ bcd: BcdOps.BcdBase;
newFile: File.Capability ← File.nullCapability;
sgb: Table.Base;
ftb: Table.Base;
ntb: BcdOps.NameString;
versionMapTried: BOOLFALSE;
mth: BcdOps.MTHandle;
sSeg: BcdDefs.SGIndex;
modNameDesc: Strings.SubStringDescriptor
← [base: LOOPHOLE[Rope.Flatten[moduleName]],
offset: 0,
length: Rope.Length[moduleName]];
someNameMatched: BOOLFALSE;
FindVersionStampedModule: PROC[mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex]
RETURNS[stop: BOOL] =
{ umid: BcdDefs.VersionStamp = IF mth.file = BcdDefs.FTSelf
THEN bcd.version
ELSE ftb[mth.file].version;
nextModNameDesc: Strings.SubStringDescriptor;
namesMatch: BOOLTRUE;
IF moduleName # NIL
THEN {nextModNameDesc ← [base: @ntb.string,
offset: mth.name,
length: ntb.size[mth.name]];
namesMatch ← Strings.EqualSubStrings[@modNameDesc, @nextModNameDesc];
someNameMatched ← someNameMatched OR namesMatch};
RETURN[namesMatch AND (EQStamps[stamp, BcdDefs.NullVersion]
OR EQStamps[stamp, umid])]
}; -- end FindVersionStampedModule
START GetSTHForModule body here
IF NOT EQStamps[stamp, BcdDefs.NullVersion]
THEN {found: BOOL;
stx: RTTypesBasicPrivate.SymbolTableIndex;
[stx, found] ← FindSTX[stamp];
IF found THEN sth ← DoAcquireSTHFromSTX[stx].sth;
IF NOT NullSth[sth] THEN RETURN[sth]};
IF fileName # NIL THEN newFile ← GetReadCapability[fileName ! ANY => CONTINUE];
DO
IF newFile = File.nullCapability -- no local file with that name
THEN {IF EQStamps[stamp, BcdDefs.NullVersion]
THEN GOTO noFile
ELSE { -- look for the module's original file
shortName: ROPE = IF moduleName = NIL
THEN NIL
ELSE Rope.Concat[moduleName, ".bcd"];
cifsFile: CIFS.OpenFile =
VersionToReadableFile[versionStamp: stamp,
shortNameHint: shortName];
versionMapTried ← TRUE;
IF cifsFile = NIL THEN GOTO noFile;
newFile ← CIFS.GetFC[cifsFile
! ANY => {IF OZ THEN Runtime.CallDebugger
["CIFS.GetFC failed"];
CONTINUE}];
IF newFile = File.nullCapability THEN GOTO noFile}};
here with a valid FC
bcd ← AcquireBCDFromCap[newFile];
sgb ← LOOPHOLE[bcd + bcd.sgOffset];
ftb ← LOOPHOLE[bcd + bcd.ftOffset];
ntb ← LOOPHOLE[bcd + bcd.ssOffset];
IF bcd.versionIdent # BcdDefs.VersionID
THEN {IF versionMapTried
THEN GOTO oldSymbols
ELSE {newFile ← File.nullCapability; LOOP}};
someNameMatched ← FALSE;
mth ← BcdOps.ProcessModules[bcd, FindVersionStampedModule].mth;
IF mth = NIL
THEN {IF NOT versionMapTried THEN {newFile ← File.nullCapability; LOOP};
IF someNameMatched
THEN GOTO wrongVersion
ELSE GOTO noSymbols};
sSeg ← mth.sseg;
IF sSeg = BcdDefs.SGNull
OR sgb[sSeg].pages = 0
OR ((NOT bcd.definitions) AND (sgb[sSeg].extraPages = 0)) -- compressed symbols
OR sgb[sSeg].file # BcdDefs.FTSelf
THEN {IF versionMapTried
THEN GOTO noSymbols
ELSE {newFile ← File.nullCapability; LOOP}};
{p: FileSegment.Pages =
[file: newFile, span: [base: sgb[sSeg].base,
pages: sgb[sSeg].pages + sgb[sSeg].extraPages]];
sth ← IF IsXBCD[bcd] THEN [x[p]] ELSE [y[p]]};
IF EQStamps[stamp, BcdDefs.NullVersion]
THEN {stb: SymbolTableBase = AcquireSTB[sth];
stamp ← STBVersion[stb];
ReleaseSTB[stb]};
[] ← RTTypesBasicPrivate.FindSTI[[symbolsStamp: stamp, sth: sth]];
ReleaseBCD[bcd];
RETURN[sth];
ENDLOOP;
EXITS
noFile => ERROR AMTypes.Error[reason: noSymbols, msg: fileName];
oldSymbols => ERROR AMTypes.Error[reason: noSymbols, msg: moduleName];
noSymbols => ERROR AMTypes.Error[reason: noSymbols,
msg: IF moduleName = NIL
THEN fileName
ELSE moduleName];
wrongVersion => ERROR AMTypes.Error[reason: noSymbols, msg: moduleName];
}; -- end GetSTHForModule
raises Error if there are no symbols for the specified module
AcquireSTBFromGFH: PUBLIC PROC[gfh: PrincOps.GlobalFrameHandle,
mesaSymbolsOK: BOOLFALSE]
RETURNS[stb: SymbolTableBase ← nullBase] =
BEGIN
bcd: BcdOps.BcdBase;
bcdns: BcdOps.NameString;
moduleName: ROPE;
module: PilotLoadStateFormat.ModuleInfo; -- a loadstate.gft entry
mth: BcdOps.MTHandle;
umid: BcdDefs.VersionStamp; -- functional version stamp of the module
ftb: Table.Base;
sth: SymbolTableHandle ← nullHandle;
FindOriginal: PROCEDURE [f: PrincOps.GlobalFrameHandle] RETURNS [BOOL] =
{RETURN[(f # gfh) AND (RTOS.SameCode[gfh, f] = identical) AND (~f.copied)]};
FindModule: PROC [mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOL] =
{RETURN[(mth.gfi <= module.gfi) AND (module.gfi < (mth.gfi + mth.ngfi))]};
IF RTFlags.checking THEN Runtime.ValidateGlobalFrame[gfh];
IF gfh.copied THEN gfh ← RTOS.EnumerateGlobalFrames[FindOriginal];
[] ← PilotLoadStateOps.InputLoadState[];
module ← PilotLoadStateOps.GetModule[gfh.gfi];
bcd ← PilotLoadStateOps.AcquireBcd[module.config];
PilotLoadStateOps.ReleaseLoadState[];
bcdns ← LOOPHOLE[bcd + bcd.ssOffset];
ftb ← LOOPHOLE[bcd + bcd.ftOffset];
[mth,] ← BcdOps.ProcessModules[bcd, FindModule];
IF mth = NIL THEN ERROR;
umid ← (IF mth.file = BcdDefs.FTSelf THEN bcd.version ELSE ftb[mth.file].version);
First look in the umid -> sth map
{found: BOOL;
stx: RTTypesBasicPrivate.SymbolTableIndex;
[stx, found] ← FindSTX[umid];
IF found THEN sth ← AcquireSTHFromSTX[stx].sth};
IF NullSth[sth] -- then try for the one referenced in the bcd
THEN sth ← AcquireSTHFromSGI[bcd, mth.sseg];
IF NullSth[sth] -- then try for the named module's file (locally)
THEN sth ← GetSTHForModule[stamp: umid,
fileName: GetFileName[ssb: bcdns, n: ftb[mth.file].name],
moduleName: GetModuleName[ssb: bcdns, n: mth.name]
! ANY => CONTINUE];
IF NullSth[sth] -- then try for the original one
THEN [sth: sth, moduleName: moduleName]
← AcquireSTHFromSTX[RTTypesBasicPrivate.FindSTI[[symbolsStamp: umid,
bcd: bcd]]];
IF NullSth[sth] -- then give up.
THEN {sgb: Table.Base = LOOPHOLE[bcd + bcd.sgOffset];
msg: ROPE ← moduleName;
IF msg = NIL THEN msg ← GetFileName[ssb: bcdns, n: ftb[sgb[mth.sseg].file].name];
ERROR AMTypes.Error[reason: noSymbols, msg: msg]};
stb ← AcquireSTB[sth, mesaSymbolsOK];
RETURN[stb];
END; -- AcquireSTBFromGFH
AcquireSTBFromSGI: PUBLIC PROC[bcd: BcdOps.BcdBase,
sgi: BcdDefs.SGIndex, -- of the symbol segment
mesaSymbolsOK: BOOLFALSE]
RETURNS[stb: SymbolTableBase ← nullBase] =
{ ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset];
sgh: BcdOps.SGHandle = @LOOPHOLE[bcd + bcd.sgOffset, Table.Base][sgi];
sth: SymbolTableHandle ← AcquireSTHFromSGI[bcd, sgi]; -- try for the referenced one
IF NullSth[sth]
THEN {ssb: BcdOps.NameString = LOOPHOLE[bcd + bcd.ssOffset];
ERROR AMTypes.Error[reason: noSymbols,
msg: GetFileName[ssb: ssb, n: ftb[sgh.file].name]]};
RETURN[AcquireSTB[sth]]};
-- PRIVATE PROCS --
EQStamps: PROC[s1, s2: BcdDefs.VersionStamp] RETURNS[BOOL] =
INLINE {RETURN[s1.net = s2.net AND s1.host = s2.host AND s1.time = s2.time]};
FindSTX: PROC[stamp: BcdDefs.VersionStamp]
RETURNS[stx: RTTypesBasicPrivate.SymbolTableIndex, found: BOOL] =
{FOR stx IN [1..RTTypesBasicPrivate.MapStiStd.length)
DO IF RTTypesBasicPrivate.MapStiStd[stx] = NIL THEN EXIT;
IF EQStamps[stamp, RTTypesBasicPrivate.MapStiStd[stx].symbolsStamp]
THEN RETURN[stx, TRUE];
ENDLOOP;
RETURN[0, FALSE]};
returns nullHandle if there are no symbols
AcquireSTHFromSGI: PROC [bcd: BcdOps.BcdBase, sgi: BcdDefs.SGIndex]
RETURNS [sth: SymbolTableHandle ← nullHandle] =
{ sgb: Table.Base = LOOPHOLE[bcd + bcd.sgOffset];
ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset];
ssb: BcdOps.NameString = LOOPHOLE[bcd + bcd.ssOffset];
sgh: BcdOps.SGHandle ← @sgb[sgi];
IF sgh.class # symbols THEN ERROR;
IF (sgh.pages = 0) -- empty symbol segment
OR ((NOT bcd.definitions) AND (sgh.extraPages = 0)) -- compressed symbols
OR sgh.file = BcdDefs.FTNull
THEN RETURN;
IF sgh.file = BcdDefs.FTSelf
THEN {stb: SymbolTableBase;
symbolsStamp: BcdDefs.VersionStamp;
file: File.Capability = FileFromBcdBase[bcd];
IF file = File.nullCapability THEN RETURN;
{p: FileSegment.Pages =
[file: file, span: [base: sgh.base, pages: sgh.pages+sgh.extraPages]];
sth ← IF IsXBCD[bcd] THEN [x[p]] ELSE [y[p]]};
stb ← AcquireSTB[sth];
symbolsStamp ← STBVersion[stb];
ReleaseSTB[stb];
[] ← RTTypesBasicPrivate.FindSTI[[symbolsStamp: symbolsStamp, sth: sth]];
}
ELSE
{ fileName: ROPE ← GetFileName[ssb, ftb[sgh.file].name];
sth ← NewSymbolHandle[fileName: fileName,
base: sgh.base,
pages: sgh.pages+sgh.extraPages,
version: ftb[sgh.file].version
version of the specified file, not necessarily of the module
! ANY => CONTINUE]}
}; -- end AcquireSTHFromSGI
GetModuleName: PROC[ssb: BcdOps.NameString, n: BcdDefs.NameRecord] RETURNS[ROPE] =
{nameString: STRING = [100];
ssd: Strings.SubStringDescriptor ← [base: @ssb.string, offset: n, length: MIN[ssb.size[n], 100]];
nameString.length ← 0;
Strings.AppendSubString[nameString, @ssd];
FOR i: CARDINAL IN [0..nameString.length) DO
IF nameString[i] = '. THEN {nameString.length ← i; EXIT};
ENDLOOP;
RETURN[ConvertUnsafe.ToRope[LONG[nameString]]]};
GetFileName: PROC[ssb: BcdOps.NameString, n: BcdDefs.NameRecord] RETURNS[ROPE] =
{nameString: STRING = [100];
ssd: Strings.SubStringDescriptor ← [base: @ssb.string, offset: n, length: MIN[ssb.size[n], 100]];
dot: BOOLFALSE;
nameString.length ← 0;
Strings.AppendSubString[nameString, @ssd];
FOR i: CARDINAL IN [0..nameString.length) DO
IF nameString[i] = '. THEN {dot ← TRUE; EXIT};
ENDLOOP;
IF ~dot THEN Strings.AppendString[nameString, ".bcd"];
RETURN[ConvertUnsafe.ToRope[LONG[nameString]]]};
FileFromBcdBase: PROC[bcd: BcdOps.BcdBase]
RETURNS[fc: File.Capability ← File.nullCapability] =
{ ssb: BcdOps.NameString = LOOPHOLE[bcd + bcd.ssOffset];
fc ← AcquireFCFromVersion[versionStamp: bcd.version,
shortFileNameHint: Rope.Concat[GetModuleName[ssb, bcd.source],
".bcd"]]};
AcquireFCFromVersion: PROC
[versionStamp: BcdDefs.VersionStamp, shortFileNameHint: ROPENIL]
RETURNS[file: File.Capability ← File.nullCapability] = {
may return NIL
cifsFile: CIFS.OpenFile ← VersionToReadableFile[versionStamp, shortFileNameHint];
IF cifsFile # NIL THEN
file ← CIFS.GetFC[
cifsFile
! ANY => {IF OZ THEN Runtime.CallDebugger["CIFS.GetFC failed"]; CONTINUE}];
};
AcquireBCDFromVersion: PUBLIC PROC
[versionStamp: BcdDefs.VersionStamp, shortFileNameHint: ROPENIL]
RETURNS[bcd: BcdOps.BcdBase] = {
may return NIL
file: File.Capability ← AcquireFCFromVersion[versionStamp, shortFileNameHint];
IF file = File.nullCapability
THEN RETURN[NIL]
ELSE RETURN[AcquireBCDFromCap[file]]};
AcquireBCDFromCap: ENTRY PROC[file: File.Capability] RETURNS[bcd: BcdOps.BcdBase] = {
ENABLE UNWIND => NULL;
space: Space.Handle;
size: NAT; -- pages
Space.Map[onePageSpace, [file: file, base: 1]];
bcd ← LOOPHOLE[Space.LongPointer[onePageSpace]];
IF bcd.extended
THEN size ← bcd.nPages - bcd.rtPages.pages
ELSE size ← bcd.nPages;
Space.Unmap[onePageSpace];
IF size <= standardBCDSpacePages
THEN {IF standardBCDSpaces = NIL
THEN space ← Space.Create[size: standardBCDSpacePages, parent: Space.virtualMemory]
ELSE {space ← standardBCDSpaces.first;
standardBCDSpaces ← standardBCDSpaces.rest;
standardBCDSpacesHeld ← standardBCDSpacesHeld - 1};
standardBCDSpacesInUse ← standardBCDSpacesInUse + 1
}
ELSE {space ← Space.Create[size: size, parent: Space.virtualMemory];
biggerBCDSpacesInUse ← biggerBCDSpacesInUse + 1};
Space.Map[space, [file: file, base: 1]];
bcd ← LOOPHOLE[Space.LongPointer[space]];
};
IsXBCD: PROC[bcd: BcdOps.BcdBase--only the first page!!--] RETURNS[BOOL] =
{RETURN[TRUE]}; -- NOTE XXX
ReleaseBCD: PUBLIC ENTRY PROC[bcd: BcdOps.BcdBase] =
{ ENABLE UNWIND => NULL;
space: Space.Handle = RTOS.UnRavelUSUs[Space.GetHandle[Space.PageFromLongPointer[bcd]]];
size: NAT ← Space.GetAttributes[space].size;
Space.Unmap[space];
IF size # standardBCDSpacePages
THEN {Space.Delete[space]; biggerBCDSpacesInUse ← biggerBCDSpacesInUse - 1}
ELSE {standardBCDSpaces ← CONS[space, standardBCDSpaces];
standardBCDSpacesInUse ← standardBCDSpacesInUse - 1;
standardBCDSpacesHeld ← standardBCDSpacesHeld + 1};
};
GetBCDVersionInfo: ENTRY PROC[file: File.Capability]
RETURNS[fileVersionIdent: CARDINAL,
fileVersionStamp: BcdDefs.VersionStamp,
isXBCD: BOOL] =
{ ENABLE UNWIND => NULL;
bcd: BcdOps.BcdBase;
Space.Map[onePageSpace, [file: file, base: 1]];
bcd ← LOOPHOLE[Space.LongPointer[onePageSpace]];
fileVersionIdent ← bcd.versionIdent;
fileVersionStamp ← bcd.version;
isXBCD ← IsXBCD[bcd];
Space.Unmap[onePageSpace];
};
GetReadCapability: PROC[name: ROPE] RETURNS[f: File.Capability ← File.nullCapability] =
{cifsFile: CIFS.OpenFile ← NIL;
cifsFile ← CIFS.Open[Rope.Concat["/local/", name], CIFS.read
! ANY => CONTINUE];
IF cifsFile = NIL THEN RETURN;
f ← CIFS.GetFC[cifsFile
! ANY => {IF OZ THEN Runtime.CallDebugger["CIFS.GetFC failed"];
CONTINUE}]};
VersionToReadableFile: PUBLIC PROC
[versionStamp: BcdDefs.VersionStamp, shortNameHint: ROPENIL]
RETURNS [file: CIFS.OpenFile ← NIL] = {
mn: ROPENIL;
IF shortNameHint # NIL THEN {
file ← CIFS.Open[shortNameHint, CIFS.read + CIFS.dontCheck
! ANY => {IF OZ THEN Runtime.CallDebugger["CIFS.Open failed"]; CONTINUE}
];
IF file # NIL THEN {
fc: File.Capability ← File.nullCapability;
fc ← CIFS.GetFC[
file
! ANY => {IF OZ THEN Runtime.CallDebugger["CIFS.GetFC failed"]; CONTINUE}];
IF fc # File.nullCapability AND GetBCDVersionInfo[fc].fileVersionStamp = versionStamp
THEN RETURN[file];
};
file ← NIL;
};
mn ← VersionMapDefaults.FileNameFromVersion[
which: $Symbols, version: versionStamp
! ANY => {
IF OZ THEN
Runtime.CallDebugger["VersionMapDefaults.FileNameFromVersion failed"];
CONTINUE;
}
];
IF mn = NIL THEN RETURN;
file ← CIFS.Open[
mn, CIFS.read + CIFS.dontCheck
! ANY => {IF OZ THEN Runtime.CallDebugger["CIFS.Open failed"]; CONTINUE}
];
};
GetMapList: PUBLIC PROC RETURNS[VersionMap.MapList] = {RETURN[VersionMapDefaults.GetMapList[$Symbols]]};
The following procedures and data are here to keep track of the files in use
inUseList: InUseList ← NIL; -- protected by the monitor
InUseList: TYPE = LIST OF InUseEntry;
InUseEntry: TYPE = RECORD [file: File.Capability, exclusive: BOOLFALSE, count: INT ← 0];
IncFileUse: PUBLIC ENTRY SAFE PROC
[file: File.Capability, exclusive: BOOLTRUE] RETURNS [ok: BOOL] = TRUSTED {
... increments # of users of a given file. If exclusive, then the increment only takes place if the initial count was 0. If not exclusive, the increment only takes place if the file is not exclusively open.
ENABLE UNWIND => NULL;
entry: InUseList ← NIL;
FOR each: InUseList ← inUseList, each.rest WHILE each # NIL DO
IF RTFiles.SameFile[file, each.first.file] THEN {
entry ← each;
EXIT};
ENDLOOP;
IF entry = NIL THEN {
inUseList ← CONS[[file: file, exclusive: exclusive, count: 1], inUseList];
RETURN [TRUE]};
IF entry.first.exclusive THEN RETURN [FALSE];
IF exclusive THEN {
IF entry.first.count # 0 THEN RETURN [FALSE];
entry.first.exclusive ← TRUE;
};
entry.first.count ← entry.first.count + 1;
RETURN [TRUE];
};
DecFileUseError: PUBLIC ERROR = CODE;
DecFileUse: PUBLIC ENTRY SAFE PROC [file: File.Capability] = TRUSTED {
... decrements # of users of a given file, raising DecFileUseError if the initial count = 0.
ENABLE UNWIND => NULL;
entry: InUseList ← NIL;
FOR each: InUseList ← inUseList, each.rest WHILE each # NIL DO
IF RTFiles.SameFile[file, each.first.file] THEN {
entry ← each;
EXIT};
ENDLOOP;
IF entry = NIL OR entry.first.count <= 0 THEN ERROR DecFileUseError;
entry.first.exclusive ← FALSE;
entry.first.count ← entry.first.count - 1;
};
FileUseCount: PUBLIC ENTRY SAFE PROC
[file: File.Capability] RETURNS [count: INT ← 0, exclusive: BOOLFALSE] = TRUSTED {
... returns # of users of a given file
ENABLE UNWIND => NULL;
FOR each: InUseList ← inUseList, each.rest WHILE each # NIL DO
IF RTFiles.SameFile[file, each.first.file] THEN
RETURN [each.first.count, each.first.exclusive];
ENDLOOP;
};
IsFileUsed: PUBLIC ENTRY SAFE PROC [file: File.Capability] RETURNS [BOOL] = TRUSTED {
... equivalent to FileUseCount[file] > 0
ENABLE UNWIND => NULL;
FOR each: InUseList ← inUseList, each.rest WHILE each # NIL DO
IF RTFiles.SameFile[file, each.first.file] THEN
RETURN [each.first.count # 0];
ENDLOOP;
RETURN [FALSE];
};
MODULE INITIALIZATION
YRCMapOps.EstablishOuter[RCMapOuterY]; -- NOTE this line should precede the next one
XRCMapOps.EstablishOuter[RCMapOuterX];
YSymbolTable.SetCacheSize[pages: 512];
XSymbolTable.SetCacheSize[pages: 512];
END.