-- LoaderSupportImpl.mesa
-- last edit by Schmidt, January 6, 1983 1:59 pm
-- last edit by Satterthwaite, February 9, 1983 12:55 pm
DIRECTORY
BcdDefs: TYPE USING [Base, EXPIndex, FTIndex, FTNull, FTSelf,
GFTIndex, Link, MTIndex, NameRecord, NullVersion, NullLink],
BcdOps: TYPE USING [BcdBase, EXPHandle, FTHandle, MTHandle, NameString,
ProcessExports, ProcessModules],
CompilerOps: TYPE USING [Start],
CWF: TYPE USING [FWF0, FWF1, WF0, WF1, WF2, WF4],
Directory: TYPE USING [Handle, Lookup],
File: TYPE USING [Capability, PageCount],
IO: TYPE USING[GetChar, Handle, PutChar, PutF, PutRope, Signal],
LowLoader: TYPE USING [AllocateInterfaceSeq, ConvertLink, CopyNStoLS, EqualStringAndName,
FindVariableLink, FreeInterfaceSeq, InterfaceSeq],
LongString: TYPE USING [EqualString, EquivalentString],
PilotLoadStateFormat: TYPE USING [ConfigIndex],
PilotLoadStateOps: TYPE USING [AcquireBcd, ConfigIndex, InputLoadState, MapConfigToReal,
ReleaseLoadState],
PrincOps: TYPE USING [ControlLink, GFTIndex, GFTNull,
GlobalFrameHandle, NullLink, UnboundLink],
PrincOpsRuntime: TYPE USING [GetFrame, GFT],
Rope: TYPE USING[Lower, ROPE, Text],
RopeInline: TYPE USING[InlineFlatten],
Runtime: TYPE USING [IsBound, RunConfig],
Subr: TYPE USING [AbortMyself, LongZone, MakeTTYProcs, TTYProcs, SubrStop],
System: TYPE USING [GetClockPulses, PulsesToMicroseconds],
TimeStamp: TYPE USING [Null, Stamp],
UECP: TYPE USING[Argv, Parse],
UserExec: TYPE USING[CommandProc, GetStreams, RegisterCommand, UserAbort];
LoaderSupportImpl: MONITOR
IMPORTS BcdOps, CompilerOps, CWF, Directory, IO, LowLoader, LongString, PilotLoadStateOps,
PrincOpsRuntime, RopeInline, Runtime, Subr, System, UECP, UserExec
EXPORTS LowLoader
SHARES File = {
NEXPRECORDS: CARDINAL = 1500; -- # of export records in load state
LoadStateSeqRecord: TYPE = RECORD[
nbcds: CARDINAL ← 0, -- nBcds in loadstate when last examined
size: CARDINAL ← 0,
body: SEQUENCE maxsize: CARDINAL OF LowLoader.InterfaceSeq
];
-- MDS Usage!
loadstateseq: LONG POINTER TO LoadStateSeqRecord ← NIL;
-- end of MDS usage
-- procedures having to do with the load state
-- must call IncorporateLoadStateChanges before calling this
GetIntFromLoadState: PUBLIC PROC[intname: LONG STRING, vers: TimeStamp.Stamp]
RETURNS[interfaceseq: LowLoader.InterfaceSeq] = {
IF loadstateseq = NIL THEN ERROR;
FOR i: CARDINAL DECREASING IN [0.. loadstateseq.size) DO
interfaceseq ← loadstateseq[i];
IF (vers = TimeStamp.Null OR interfaceseq.versstamp = vers)
AND LongString.EqualString[interfaceseq.intname, intname] THEN
RETURN[interfaceseq];
ENDLOOP;
RETURN[NIL];
};
AddToLoadState: PUBLIC PROC[interfaceseq: LowLoader.InterfaceSeq] = {
IF loadstateseq = NIL THEN ERROR;
IF loadstateseq.size >= loadstateseq.maxsize THEN ERROR;
loadstateseq[loadstateseq.size] ← interfaceseq;
loadstateseq.size ← loadstateseq.size + 1;
interfaceseq.isfromloadstate ← TRUE;
};
IncorporateLoadStateChanges: PUBLIC PROC[window: Subr.TTYProcs, askCompiler: BOOL] = {
ENABLE UNWIND => PilotLoadStateOps.ReleaseLoadState[];
nbcds: CARDINAL;
bcdbase: BcdOps.BcdBase;
namestring: BcdOps.NameString;
longzone: UNCOUNTED ZONE ← Subr.LongZone[];
config: CARDINAL;
p: LONG CARDINAL;
ForEachExport: PROC[eth: BcdOps.EXPHandle, eti: BcdDefs.EXPIndex]
RETURNS[stop: BOOL] = {
fth: BcdOps.FTHandle;
blink: BcdDefs.Link;
rgfi: CARDINAL;
newclink: PrincOps.ControlLink;
interfaceseq: LowLoader.InterfaceSeq;
stop ← FALSE;
fth ← @LOOPHOLE[bcdbase + bcdbase.ftOffset, BcdDefs.Base][eth.file];
interfaceseq ← ProcessInterface[namestring, eth.name, fth.version,
bcdbase, eth.size];
IF eth.size > interfaceseq.maxsize THEN {
PilotLoadStateOps.ReleaseLoadState[];
ERROR;
};
-- now fill in the exports
FOR i: CARDINAL IN [0 .. eth.size) DO
blink ← eth.links[i];
rgfi ← PilotLoadStateOps.MapConfigToReal[blink.gfi, config];
IF rgfi = PrincOps.GFTNull THEN LOOP;
SELECT blink.vtag FROM
var => {
frame: PrincOps.GlobalFrameHandle;
frame ← PrincOpsRuntime.GetFrame[PrincOpsRuntime.GFT[rgfi]];
IF frame = NIL THEN
newclink ← PrincOps.UnboundLink -- NIL due to Runtime.SelfDestruct[]
ELSE
newclink ← LowLoader.FindVariableLink[blink, NIL, frame, bcdbase];
};
proc0, proc1=> {
newclink ← LowLoader.ConvertLink[blink];
newclink.gfi ← rgfi;
};
type => newclink ← PrincOps.NullLink; -- error
ENDCASE => ERROR;
interfaceseq[i] ← [clink: newclink, blink: BcdDefs.NullLink];
ENDLOOP;
interfaceseq.size ← eth.size;
};
-- this fills in the frame pointers
ForEachModule: PROC[mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex]
RETURNS[stop: BOOL] = {
fth: BcdOps.FTHandle;
rgfi: CARDINAL;
interfaceseq: LowLoader.InterfaceSeq;
frame: PrincOps.GlobalFrameHandle;
stop ← FALSE;
IF mth.file = BcdDefs.FTSelf OR mth.file = BcdDefs.FTNull THEN RETURN;
fth ← @LOOPHOLE[bcdbase + bcdbase.ftOffset, BcdDefs.Base][mth.file];
interfaceseq ← ProcessInterface[namestring, mth.name, fth.version,
bcdbase, 1];
IF interfaceseq.maxsize = 0 THEN {
PilotLoadStateOps.ReleaseLoadState[];
ERROR;
};
-- now fill in module pointer
rgfi ← PilotLoadStateOps.MapConfigToReal[mth.gfi, config];
frame ← PrincOpsRuntime.GetFrame[PrincOpsRuntime.GFT[rgfi]];
interfaceseq[0] ← [clink: LOOPHOLE[frame], blink: BcdDefs.NullLink];
interfaceseq.size ← 1;
};
wp: PROC[ch: CHAR] = {
window.out.PutChar[ch];
};
{
oldNBcds: CARDINAL ← 0;
p ← System.PulsesToMicroseconds[System.GetClockPulses[]];
IF loadstateseq = NIL THEN
loadstateseq ← longzone.NEW[LoadStateSeqRecord[NEXPRECORDS]]
ELSE oldNBcds ← loadstateseq.nbcds;
IF askCompiler AND NOT Runtime.IsBound[CompilerOps.Start] THEN {
IF window.Confirm[
window.in, window.out, window.data,
"Do you want to have Compiler.bcd loaded right now ", 'y] = 'y
THEN {
cap: File.Capability;
CWF.FWF0[wp, "Yes.\nLoading ... "L];
{
ENABLE ANY => { CWF.FWF0[wp, "failed.\n"L]; GOTO out};
cap ← Directory.Lookup["compiler.bcd"L];
Runtime.RunConfig[file: cap, offset: 1, codeLinks: TRUE];
CWF.FWF0[wp, "done.\n"L];
EXITS
out => NULL;
}}
ELSE CWF.FWF0[wp, "No.\n"L];
};
nbcds ← PilotLoadStateOps.InputLoadState[];
IF oldNBcds = nbcds THEN {
PilotLoadStateOps.ReleaseLoadState[];
RETURN; -- ok, no changes
};
CWF.FWF0[wp, "Filling in from Pilot load state... "L];
FOR config IN [oldNBcds .. nbcds) DO
bcdbase ← PilotLoadStateOps.AcquireBcd[config];
-- this will be true only if this is a fake config
-- that I generate
IF bcdbase.version = BcdDefs.NullVersion THEN LOOP;
namestring ← LOOPHOLE[bcdbase + bcdbase.ssOffset];
[] ← BcdOps.ProcessExports[bcdbase, ForEachExport];
[] ← BcdOps.ProcessModules[bcdbase, ForEachModule];
ENDLOOP;
PilotLoadStateOps.ReleaseLoadState[];
p ← (System.PulsesToMicroseconds[System.GetClockPulses[]] - p)/1000;
loadstateseq.nbcds ← nbcds;
CWF.FWF1[wp, "done (%lu millisec).\n"L, @p];
}};
ProcessInterface: PROC[namestring: BcdOps.NameString, name: BcdDefs.NameRecord,
version: TimeStamp.Stamp, bcdbase: BcdOps.BcdBase, size: CARDINAL]
RETURNS[interfaceseq: LowLoader.InterfaceSeq] = {
oldinterfaceseq: LowLoader.InterfaceSeq;
interfaceseq ← NIL;
FOR i: CARDINAL IN [0 .. loadstateseq.size) DO
oldinterfaceseq ← loadstateseq[i];
IF LowLoader.EqualStringAndName[oldinterfaceseq.intname, namestring, name]
AND oldinterfaceseq.versstamp = version THEN {
interfaceseq ← oldinterfaceseq;
EXIT;
};
ENDLOOP;
IF interfaceseq = NIL THEN {
intname: STRING ← [100];
LowLoader.CopyNStoLS[intname, bcdbase, name];
interfaceseq ← LowLoader.AllocateInterfaceSeq[intname, size];
interfaceseq.isfromloadstate ← TRUE;
loadstateseq[loadstateseq.size] ← interfaceseq;
loadstateseq.size ← loadstateseq.size + 1;
IF loadstateseq.size >= loadstateseq.maxsize THEN {
PilotLoadStateOps.ReleaseLoadState[];
ERROR;
};
interfaceseq.versstamp ← version;
};
};
PrintCLink: PROC[j: CARDINAL, link: PrincOps.ControlLink] = {
IF link = PrincOps.NullLink THEN
CWF.WF1["#%u: NullLink\n"L, @j]
ELSE IF link = PrincOps.UnboundLink THEN
CWF.WF1["#%u: UnboundLink\n"L, @j]
ELSE {
gfi, ep: CARDINAL;
gfi ← link.gfi;
ep ← link.ep;
CWF.WF4["#%u: gfi %bB ep %u, address %bB\n"L, @j, @gfi, @ep, @link];
};
};
PrintInt: PROC[interfaceseq: LowLoader.InterfaceSeq] = {
j: CARDINAL;
CWF.WF2["%s of %lt:\n"L, interfaceseq.intname,
@interfaceseq.versstamp.time];
FOR j IN [0 .. interfaceseq.size) DO
PrintCLink[j, interfaceseq[j].clink];
ENDLOOP;
};
PrintInterfacesFromLoadState: UserExec.CommandProc = TRUSTED {
ENABLE Subr.AbortMyself => {
CWF.WF0["LSPrint aborted.\n"L];
GOTO out;
};
argv: UECP.Argv ← UECP.Parse[event.commandLine];
ttyprocs: Subr.TTYProcs ← Subr.MakeTTYProcs[
exec.GetStreams[].in, exec.GetStreams[].out, exec, MyConfirm];
IncorporateLoadStateChanges[ttyprocs, FALSE];
CWF.WF1["Pilot Loadstate, total %u interface records.\n"L, @loadstateseq.size];
FOR parm: CARDINAL IN [1 .. argv.argc) DO
flat: Rope.Text ← LOOPHOLE[RopeInline.InlineFlatten[argv[parm]]];
intname: LONG STRING ← LOOPHOLE[flat];
IF LongString.EquivalentString[intname, "All"L] THEN {
-- print them all out
FOR i: CARDINAL IN [0 .. loadstateseq.size) DO
IF UserExec.UserAbort[exec] THEN SIGNAL Subr.AbortMyself;
PrintInt[loadstateseq[i]];
ENDLOOP;
}
ELSE {
FOR j: CARDINAL IN [0 .. loadstateseq.size) DO
IF LongString.EquivalentString[intname, loadstateseq[j].intname] THEN {
PrintInt[loadstateseq[j]];
EXIT;
};
REPEAT
FINISHED =>
CWF.WF1["Interface %s not found in load state.\n"L, intname];
ENDLOOP;
};
ENDLOOP;
EXITS
out => NULL;
};
MyConfirm: PROC[in, out: IO.Handle, data: REF ANY, msg: Rope.ROPE, dch: CHAR] RETURNS[CHAR] = {
ch: CHAR;
bs: IO.Handle;
out.PutRope[msg];
DO
ENABLE IO.Signal => TRUSTED{IF ec = Rubout THEN LOOP};
out.PutF["? "];
bs ← IF in.backingStream = NIL THEN in ELSE in.backingStream;
ch ← bs.GetChar[];
IF ch = '\n THEN ch ← dch;
ch ← Rope.Lower[ch];
RETURN[ch];
ENDLOOP;
};
-- call only once
ShutDown: PUBLIC PROC = {
IF loadstateseq ~= NIL THEN
FOR i: CARDINAL IN [0 .. loadstateseq.size) DO
LowLoader.FreeInterfaceSeq[loadstateseq[i]];
ENDLOOP;
Subr.SubrStop[];
};
OnceInit: PROC = {
UserExec.RegisterCommand["XLSPrint.~", PrintInterfacesFromLoadState];
};
OnceInit[];
}.