-- ExternalLoadState.mesa -- Edited by: -- Bruce, July 2, 1980 4:56 PM -- Sandman, January 22, 1979 1:48 PM -- Barbara, November 7, 1978 11:18 AM DIRECTORY AltoFileDefs USING [eofDA, FP, NullSN], BcdOps USING [BcdBase], ControlDefs USING [GFTIndex], DebugOps USING [ShortREAD], Event USING [AddNotifier, Item, Masks, Notifier], LoadStateFormat USING [AltoVersionID, BcdObject, ConfigIndex, LoadState, ModuleInfo, ModuleTable, NullConfig], LoadStateOps USING [EnumerationDirection, Map], MiscDefs USING [Zero], SDDefs USING [SD, sGFTLength], SegmentDefs USING [DefaultMDSBase, DeleteFileSegment, FileHint, FileSegmentAddress, FileSegmentHandle, HardUp, InsertFile, MakeSwappedIn, NewFileSegment, Read, SwapOut, SwapUp, Unlock, VMtoFileSegment], Storage USING [Free, Node]; ExternalLoadState: PROGRAM IMPORTS DebugOps, Event, MiscDefs, SegmentDefs, Storage EXPORTS LoadStateOps = PUBLIC BEGIN OPEN LoadStateFormat; GFTIndex: TYPE = ControlDefs.GFTIndex; FileSegmentHandle: TYPE = SegmentDefs.FileSegmentHandle; state: PUBLIC FileSegmentHandle _ NIL; loadstate: LoadState _ NIL; gft: ModuleTable; dirty: BOOLEAN _ FALSE; LoadStateInvalid: SIGNAL = CODE; SwapIn: PROC [seg: SegmentDefs.FileSegmentHandle] = INLINE BEGIN OPEN SegmentDefs; MakeSwappedIn[seg,DefaultMDSBase,HardUp] END; InputLoadState: PROCEDURE RETURNS [ConfigIndex] = BEGIN OPEN ControlDefs, SDDefs, SegmentDefs; IF state = NIL THEN SIGNAL LoadStateInvalid; SwapIn[state]; loadstate _ FileSegmentAddress[state]; IF loadstate.versionident # AltoVersionID THEN ERROR LoadStateInvalid[ ! UNWIND => Unlock[state]]; gft _ DESCRIPTOR[@loadstate.gft, DebugOps.ShortREAD[SD+sGFTLength]]; RETURN[loadstate.nBcds] END; ReleaseLoadState: PROCEDURE = BEGIN OPEN SegmentDefs; IF ~state.swappedin THEN RETURN; Unlock[state]; IF state.lock = 0 THEN BEGIN IF dirty THEN BEGIN state.write _ TRUE; SegmentDefs.SwapUp[state]; dirty _ state.write _ FALSE; END; loadstate _ NIL; END; state.inuse _ TRUE; END; MapConfigToReal: PROCEDURE [cgfi: GFTIndex, config: ConfigIndex] RETURNS [rgfi: GFTIndex] = BEGIN IF cgfi = 0 THEN RETURN[0]; FOR rgfi IN [0..LENGTH[gft]) DO IF gft[rgfi].config = config AND gft[rgfi].gfi = cgfi THEN RETURN [rgfi]; ENDLOOP; RETURN[0]; END; MapRealToConfig: PROCEDURE [rgfi: GFTIndex] RETURNS [GFTIndex, ConfigIndex] = BEGIN RETURN[gft[rgfi].gfi, gft[rgfi].config]; END; GetMap: PROCEDURE [config: ConfigIndex] RETURNS [map: LoadStateOps.Map] = BEGIN max: CARDINAL _ 0; i: GFTIndex; FOR i IN [0..LENGTH[gft]) DO IF gft[i].config = config THEN max _ MAX[max, gft[i].gfi]; ENDLOOP; max _ max+1; map _ DESCRIPTOR[Storage.Node[max], max]; MiscDefs.Zero[BASE[map], max]; FOR i IN [0..LENGTH[gft]) DO IF gft[i].config = config THEN map[gft[i].gfi] _ i; ENDLOOP; END; ReleaseMap: PROCEDURE [map: LoadStateOps.Map] = BEGIN IF BASE[map] # NIL THEN Storage.Free[BASE[map]]; END; AcquireBcd: PROCEDURE [config: ConfigIndex] RETURNS [bcd: BcdOps.BcdBase] = BEGIN OPEN SegmentDefs; b: POINTER TO alto BcdObject; fp: AltoFileDefs.FP; seg: FileSegmentHandle; seg _ GetSeg[config]; IF seg = NIL THEN BEGIN WITH object: loadstate.bcds[config] SELECT FROM alto => b _ @object; ENDCASE => ERROR LoadStateInvalid; fp _ IF b.fp.serial = AltoFileDefs.NullSN THEN state.file.fp ELSE b.fp; seg _ NewFileSegment[InsertFile[@fp, Read], b.base, b.pages, Read]; IF b.da # AltoFileDefs.eofDA THEN WITH s: seg SELECT FROM disk => s.hint _ SegmentDefs.FileHint[b.da, b.base]; ENDCASE; AddSeg[config: config, seg: seg]; END; SwapIn[seg]; RETURN[FileSegmentAddress[seg]]; END; ReleaseBcd: PROCEDURE [bcd: BcdOps.BcdBase] = BEGIN OPEN SegmentDefs; seg: FileSegmentHandle _ VMtoFileSegment[bcd]; IF seg = NIL THEN RETURN; Unlock[seg]; seg.inuse _ TRUE; END; DeleteSeg: PROCEDURE [config: ConfigIndex, seg: FileSegmentHandle] = BEGIN OPEN SegmentDefs; [] _ InputLoadState[]; FOR config IN [0..loadstate.nBcds) DO WITH b: loadstate.bcds[config] SELECT FROM alto => BEGIN IF b.fp # seg.file.fp THEN LOOP; IF b.da = AltoFileDefs.eofDA AND b.base = seg.base THEN WITH s: seg SELECT FROM disk => BEGIN b.da _ s.hint.da; dirty _ TRUE END; ENDCASE; END; ENDCASE => ERROR LoadStateInvalid[]; ENDLOOP; ReleaseLoadState[]; DeleteFileSegment[seg]; END; EnumerateModules: PROCEDURE [ proc: PROCEDURE [GFTIndex, ModuleInfo] RETURNS [BOOLEAN]] RETURNS [GFTIndex] = BEGIN i: GFTIndex; FOR i IN [0..LENGTH[gft]) DO IF proc[i, gft[i]] THEN RETURN[i]; ENDLOOP; RETURN[0] END; EnumerateBcds: PROCEDURE [dir: LoadStateOps.EnumerationDirection, proc: PROCEDURE [ConfigIndex] RETURNS [BOOLEAN]] RETURNS [config: ConfigIndex] = BEGIN 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] END; SetAltoLoadState: PROCEDURE [stateseg: FileSegmentHandle] = BEGIN state _ stateseg; END; GetAltoLoadState: PROCEDURE RETURNS [FileSegmentHandle] = BEGIN RETURN[state]; END; -- Bcd Cache notifyItem: Event.Item _ [ link:, eventMask: Event.Masks[newSession] + Event.Masks[resumeSession] + Event.Masks[abortSession], eventProc: LoadStateNotifier]; LoadStateNotifier: Event.Notifier = BEGIN SELECT why FROM resumeSession, abortSession => IF state # NIL THEN SegmentDefs.SwapOut[state]; newSession => FlushBcdCache[]; ENDCASE; RETURN END; CacheItem: TYPE = RECORD [ config: ConfigIndex, seg: FileSegmentHandle]; CacheSize: CARDINAL = 8; CacheIndex: TYPE = CARDINAL[0..CacheSize); cache: ARRAY CacheIndex OF CacheItem; entries: [0..CacheSize] _ 0; FlushBcdCache: PROCEDURE = BEGIN i: CacheIndex; FOR i IN [0..entries) DO DeleteSeg[config: cache[i].config, seg: cache[i].seg]; ENDLOOP; entries _ 0; RETURN END; GetSeg: PROCEDURE [config: ConfigIndex] RETURNS [seg: FileSegmentHandle] = BEGIN i, j: CacheIndex; item: CacheItem; FOR i IN [0..entries) DO IF cache[i].config = config THEN BEGIN item _ cache[i]; FOR j DECREASING IN [1..i] DO cache[j] _ cache[j-1]; ENDLOOP; cache[0] _ item; RETURN[item.seg]; END; ENDLOOP; RETURN[NIL]; END; AddSeg: PROCEDURE [config: ConfigIndex, seg: FileSegmentHandle] = BEGIN i: CacheIndex; IF entries < CacheSize THEN BEGIN FOR i DECREASING IN [1..entries] DO cache[i] _ cache[i-1]; ENDLOOP; cache[0] _ [config: config, seg: seg]; entries _ entries + 1; RETURN END; DeleteSeg[ config: cache[LAST[CacheIndex]].config, seg: cache[LAST[CacheIndex]].seg]; FOR i DECREASING IN [1..CacheSize) DO cache[i] _ cache[i-1]; ENDLOOP; cache[0] _ [config: config, seg: seg]; END; Event.AddNotifier[@notifyItem]; END.. (1792)\5685f8 9f0 94f8 9f0