-- XDLoadState.mesa -- Edited by: -- Bruce, October 8, 1980 6:53 PM -- Sandman, July 18, 1980 12:07 PM DIRECTORY AltoFileDefs USING [CFA, eofDA, FA, FP, NullSN], BcdOps USING [BcdBase], ControlDefs USING [GFTIndex], DebugOps USING [ShortREAD], DiskDefs USING [UnrecoverableDiskError], Event USING [AddNotifier, Item, Masks, Notifier], LoadStateFormat USING [ AltoVersionID, BcdObject, ConfigIndex, LoadState, ModuleInfo, ModuleTable, NullConfig], DLoadState USING [EnumerationDirection, Map], MiscDefs USING [Zero], SDDefs USING [SD, sGFTLength], SegmentDefs USING [ DefaultMDSBase, DeleteFileSegment, FileHandle, FileHint, FileSegmentAddress, FileSegmentHandle, HardUp, InsertFile, InvalidFP, InvalidSegmentSize, MakeSwappedIn, NewFileSegment, Read, SetFileSegmentDA, SwapOut, SwapUp, Unlock, LongVMtoFileSegment], State USING [GetGS, GSHandle], Storage USING [Free, Node]; XDLoadState: PROGRAM IMPORTS DebugOps, DiskDefs, Event, MiscDefs, SegmentDefs, State, Storage EXPORTS DLoadState = PUBLIC BEGIN OPEN LoadStateFormat, SegmentDefs; GFTIndex: TYPE = ControlDefs.GFTIndex; FileSegmentHandle: TYPE = SegmentDefs.FileSegmentHandle; state: PUBLIC FileSegmentHandle _ NIL; offset: PUBLIC CARDINAL; loadstate: LoadState _ NIL; gft: ModuleTable; dirty: BOOLEAN _ FALSE; Invalid: SIGNAL = CODE; SwapIn: PROC [seg: FileSegmentHandle] = INLINE BEGIN MakeSwappedIn[seg,DefaultMDSBase,HardUp] END; Acquire: PROCEDURE RETURNS [ConfigIndex] = BEGIN OPEN ControlDefs, SDDefs; IF state = NIL THEN SIGNAL Invalid; SwapIn[state]; loadstate _ FileSegmentAddress[state]; IF loadstate.versionident # AltoVersionID THEN ERROR Invalid[ ! UNWIND => Unlock[state]]; gft _ DESCRIPTOR[@loadstate.gft, DebugOps.ShortREAD[SD+sGFTLength]]; RETURN[loadstate.nBcds] END; Release: PROCEDURE = BEGIN 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: DLoadState.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: DLoadState.Map] = BEGIN IF BASE[map] # NIL THEN Storage.Free[BASE[map]]; END; AcquireBcd: PROCEDURE [config: ConfigIndex] RETURNS [bcd: BcdOps.BcdBase] = BEGIN 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 Invalid; fp _ IF b.fp.serial = AltoFileDefs.NullSN THEN state.file.fp ELSE b.fp; seg _ NewFileSegment[InsertFile[@fp, Read], offset + b.base, b.pages, Read]; IF b.da # AltoFileDefs.eofDA THEN WITH s: seg SELECT FROM disk => s.hint _ SegmentDefs.FileHint[b.da, offset + b.base]; ENDCASE; AddSeg[config: config, seg: seg]; END; SwapIn[seg]; RETURN[FileSegmentAddress[seg]]; END; ReleaseBcd: PROCEDURE [bcd: BcdOps.BcdBase] = BEGIN seg: FileSegmentHandle _ LongVMtoFileSegment[bcd]; IF seg = NIL THEN RETURN; Unlock[seg]; seg.inuse _ TRUE; END; DeleteSeg: PROCEDURE [config: ConfigIndex, seg: FileSegmentHandle] = BEGIN [] _ Acquire[]; 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 offset + b.base = seg.base THEN WITH s: seg SELECT FROM disk => BEGIN b.da _ s.hint.da; dirty _ TRUE END; ENDCASE; END; ENDCASE => ERROR Invalid[]; ENDLOOP; Release[]; DeleteFileSegment[seg]; END; Enumerate: PROCEDURE [dir: DLoadState.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; -- 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 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; Init: PUBLIC PROCEDURE = BEGIN data: State.GSHandle _ State.GetGS[]; cfa: POINTER TO AltoFileDefs.CFA _ @data.ESV.loadstateCFA; pages: CARDINAL _ data.ESV.lspages; file: FileHandle; offset _ 0; IF state # NIL THEN { UNTIL state.lock = 0 DO Unlock[state]; ENDLOOP; state.write _ FALSE; DeleteFileSegment[state]}; file _ InsertFile[@cfa.fp, Read]; state _ FindLoadState[file, @cfa.fa, pages ! InvalidFP, InvalidSegmentSize, DiskDefs.UnrecoverableDiskError => { state _ NIL; CONTINUE}]; END; FindLoadState: PROCEDURE [ file: FileHandle, fa: POINTER TO AltoFileDefs.FA, pages: CARDINAL] RETURNS [seg: FileSegmentHandle] = BEGIN seg _ NewFileSegment[file, fa.page, pages, Read]; SetFileSegmentDA[seg, fa.da ! UNWIND => DeleteFileSegment[seg]]; SwapIn[seg ! UNWIND => DeleteFileSegment[seg]]; Unlock[seg]; RETURN END; Event.AddNotifier[@notifyItem]; END.. (1792)\5217f8 9f0 94f8 9f0