-- PilotLoadStateImpl.mesa
-- last edited by Sandman on February 4, 1981 9:00 AM
-- Last Modified On October 13, 1982 10:32 am By Paul Rovner

DIRECTORY
BcdOps USING [BcdBase],
Environment USING [PageNumber, PageCount, wordsPerPage],
Heap USING [MakeMDSNode, FreeMDSNode, systemMDSZone],
Inline USING [LongCOPY],
PilotLoadStateFormat USING [
PilotVersionID, ConfigIndex, LoadState, ModuleInfo, ModuleTable, NullConfig,
NullModule, LoadStateObject, BcdInfo],
PilotLoadStateOps USING [EnumerationDirection, Map],
PilotLoadStatePrivate USING [],
PrincOps USING [GFTIndex],
RuntimeInternal USING [loadStatePage],
RuntimePrograms USING [],
Space USING [
Create, Handle, LongPointer, LongPointerFromPage,
Map, virtualMemory, VMPageNumber];

PilotLoadStateImpl: MONITOR
IMPORTS Heap, Inline, RuntimeInternal, Space
EXPORTS PilotLoadStateOps, PilotLoadStatePrivate, RuntimePrograms =

BEGIN OPEN Environment, PilotLoadStateOps, PilotLoadStateFormat, PrincOps;

loadstate: LoadState; -- the working copy of the load state.
queue: CONDITION;
inuse: BOOLEANTRUE;

LoadStateFull: PUBLIC ERROR = CODE;
LoadStateInvalid: PUBLIC ERROR = CODE;

InitializePilotLoadState: PUBLIC PROCEDURE [
pageInitialLoadState: PageNumber,
countInitialLoadState: PageCount] = -- Module initialization:
BEGIN OPEN Space;
workingLoadState: Space.Handle ← Space.Create[
(SIZE[LoadStateObject]+SIZE[BcdInfo]*LAST[ConfigIndex]+wordsPerPage-1)/wordsPerPage,
Space.virtualMemory];
Space.Map[workingLoadState];
Inline.LongCOPY[
from: LongPointerFromPage[pageInitialLoadState],
to: loadstate ← Space.LongPointer[workingLoadState],
nwords: countInitialLoadState*wordsPerPage];
RuntimeInternal.loadStatePage ← Space.VMPageNumber[workingLoadState];
-- linkage to copilot
-- the working load state is now available.
ReleaseLoadState[];
END;

InstallLoadState: PUBLIC PROC[newState: PilotLoadStateFormat.LoadState]
RETURNS[oldState: PilotLoadStateFormat.LoadState] =
{oldState ← loadstate; loadstate ← newState};

InputLoadState: PUBLIC ENTRY PROCEDURE RETURNS [ConfigIndex] =
{ENABLE UNWIND => NULL;
WHILE inuse DO WAIT queue ENDLOOP;
IF loadstate.versionident # PilotVersionID THEN ERROR LoadStateInvalid;
inuse ← TRUE;
RETURN[loadstate.nBcds]};

ReleaseLoadState: PUBLIC ENTRY PROCEDURE =
{ENABLE UNWIND => NULL; inuse ← FALSE; NOTIFY queue};

UpdateLoadState: PUBLIC PROCEDURE [config: ConfigIndex, bcd: BcdOps.BcdBase] =
{IF bcd = NIL THEN ERROR LoadStateInvalid;
IF config >= LAST[ConfigIndex] THEN ERROR LoadStateFull;

loadstate.bcds[config] ← [ptr[origin: bcd]];
loadstate.bcds[config].exports ← bcd.nExports # 0;
loadstate.bcds[config].typeExported ← bcd.typeExported;

IF config >= loadstate.nBcds THEN loadstate.nBcds ← loadstate.nBcds + 1};

RemoveConfig: PUBLIC PROCEDURE [map: Map, config: ConfigIndex] =
{FOR i: CARDINAL IN [1..LAST[PrincOps.GFTIndex]) DO
IF loadstate.gft[i].config > config AND loadstate.gft[i].config # NullConfig THEN
loadstate.gft[i].config ← loadstate.gft[i].config - 1;
ENDLOOP;
FOR i: CARDINAL IN [1..LENGTH[map]) DO loadstate.gft[map[i]] ← NullModule; ENDLOOP;
FOR i: CARDINAL IN [config..loadstate.nBcds)
DO loadstate.bcds[i] ← loadstate.bcds[i + 1]; ENDLOOP;
loadstate.nBcds ← loadstate.nBcds - 1};

EnterModule: PUBLIC PROCEDURE [rgfi: GFTIndex, module: ModuleInfo] =
{loadstate.gft[rgfi] ← module};

GetModule: PUBLIC PROCEDURE [rgfi: GFTIndex] RETURNS [module: ModuleInfo] =
{RETURN[loadstate.gft[rgfi]]};

MapConfigToReal: PUBLIC PROCEDURE [cgfi: GFTIndex, config: ConfigIndex]
RETURNS [rgfi: GFTIndex] =
{IF cgfi = 0 THEN RETURN[0];
FOR rgfi IN PrincOps.GFTIndex DO
IF loadstate.gft[rgfi].config = config AND loadstate.gft[rgfi].gfi = cgfi THEN RETURN[rgfi];
ENDLOOP;
RETURN[0]};

MapRealToConfig: PUBLIC PROCEDURE [rgfi: GFTIndex]
RETURNS [cgfi: GFTIndex, config: ConfigIndex] =
{RETURN[loadstate.gft[rgfi].gfi, loadstate.gft[rgfi].config]};

GetMap: PUBLIC PROCEDURE [config: ConfigIndex] RETURNS [map: Map] =
{max: CARDINAL ← 0;
FOR i: GFTIndex IN PrincOps.GFTIndex DO
IF loadstate.gft[i].config = config THEN max ← MAX[max, loadstate.gft[i].gfi]; ENDLOOP;
map ← DESCRIPTOR[Heap.MakeMDSNode[z: Heap.systemMDSZone, n: max + 1], max + 1];
FOR i: GFTIndex IN [0..LENGTH[map]) DO map[i] ← 0; ENDLOOP;
FOR i: GFTIndex IN PrincOps.GFTIndex DO
IF loadstate.gft[i].config = config THEN map[loadstate.gft[i].gfi] ← i; ENDLOOP};

ReleaseMap: PUBLIC PROCEDURE [map: Map] =
{IF BASE[map] # NIL THEN Heap.FreeMDSNode[z: Heap.systemMDSZone, p: BASE[map]]};

AcquireBcd: PUBLIC PROCEDURE [config: ConfigIndex]
RETURNS [bcd: BcdOps.BcdBase] =
{bcdInfo: BcdInfo ← loadstate.bcds[config];
bcdInfo.exports ← bcdInfo.typeExported ← FALSE;
-- NOTE overlaid hack to save a word per entry
RETURN[LOOPHOLE[bcdInfo.origin]]};

ReleaseBcd: PUBLIC PROCEDURE [bcd: BcdOps.BcdBase] = {};

EnumerateModules: PUBLIC PROCEDURE [
proc: PROCEDURE [GFTIndex, ModuleInfo] RETURNS [BOOLEAN]]
RETURNS [gfti: GFTIndex ← 0] =
{FOR i: GFTIndex IN PrincOps.GFTIndex
DO IF proc[i, loadstate.gft[i]] THEN RETURN[i]; ENDLOOP};

EnumerateBcds: PUBLIC PROCEDURE [
dir: EnumerationDirection, proc: PROCEDURE [ConfigIndex] RETURNS [BOOLEAN]]
RETURNS [config: ConfigIndex] =
{SELECT dir FROM
recentfirst =>
FOR config DECREASING IN [0..loadstate.nBcds)
DO IF proc[config] THEN RETURN[config]; ENDLOOP;
recentlast =>
FOR config IN [0..loadstate.nBcds)
DO IF proc[config] THEN RETURN[config]; ENDLOOP;
ENDCASE;
RETURN[NullConfig]};

BcdUnresolved: PUBLIC PROCEDURE[bcd: ConfigIndex] RETURNS[BOOLEAN] =
{FOR i: GFTIndex IN PrincOps.GFTIndex DO
IF bcd = loadstate.gft[i].config AND ~loadstate.gft[i].resolved THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE]};

BcdExports: PUBLIC PROCEDURE [bcd: ConfigIndex] RETURNS [BOOLEAN] =
{RETURN[loadstate.bcds[bcd].exports]};

BcdExportsTypes: PUBLIC PROCEDURE [bcd: ConfigIndex] RETURNS [BOOLEAN] =
{RETURN[loadstate.bcds[bcd].typeExported]};

END.