-- file: LaurelSegments.mesa
-- edited by Levin, January 27, 1981 11:57 AM
-- edited by Brotz, November 13, 1981 12:21 PM

DIRECTORY
AltoDefs USING [BytesPerPage, PageCount, PageNumber],
AltoFileDefs USING [FP, NullFP],
Core USING [LookupInFileCache],
exD: FROM "ExceptionDefs" USING [SysBug],
lsD: FROM "LaurelStateDefs" USING [AllocateStateNode, PageCount, PageNumber,
StateHeader, StateSegment, StateSegmentObject],
SegmentDefs USING [DefaultAccess, DefaultBase, DeleteFileSegment, FileHandle,
FileSegmentAddress, FileSegmentHandle, GetEndOfFile, GetFileSegmentDA, HardDown,
InsertFile, LockFile, MakeSwappedIn, NewFileSegment, PageNumber, Read,
ReadWriteAppend, SetEndOfFile, SetFileAccess, SetFileSegmentDA, SwapIn, SwapUp,
Unlock, Write];

LaurelSegments: PROGRAM
IMPORTS Core, exD, lsD, SegmentDefs
EXPORTS lsD
SHARES lsD =

BEGIN
OPEN lsD;

-- Exported procedures for clients --

DefineStateSegment: PUBLIC PROC [nPages: PageCount] RETURNS [seg: StateSegment] =
BEGIN
OPEN SegmentDefs;
IF ~beforeInstallation THEN exD.SysBug[];
seg ← AllocateStateNode[SIZE[StateSegmentObject]];
seg↑ ←
[pages: nPages,
link: NIL,
body: inCore[fsh: NewFileSegment[stateFile, stateFF, nPages, Read+Write]]];
IF segmentListHead = NIL THEN segmentListHead ← seg
ELSE segmentListTail.link ← seg;
segmentListTail ← seg;
stateFF ← stateFF + nPages;
SetEndOfFile[stateFile, stateFF-1, AltoDefs.BytesPerPage];
END; -- of DefineStateSegment --


SwapInStateSegment: PUBLIC PROCEDURE [segment: StateSegment] RETURNS [POINTER] =
BEGIN
OPEN SegmentDefs;
MakeSwappedIn[segment.fsh, DefaultBase, HardDown];
RETURN[FileSegmentAddress[segment.fsh]]
END; -- of SwapInStateSegment --


StateSegmentAddress: PUBLIC PROCEDURE [segment: StateSegment] RETURNS [POINTER] =
BEGIN
IF segment.fsh.lock = 0 THEN exD.SysBug[];
RETURN[SegmentDefs.FileSegmentAddress[segment.fsh]]
END; -- of StateSegmentAddress --


WriteStateSegment: PUBLIC PROCEDURE [segment: StateSegment] =
BEGIN
segment.fsh.write ← TRUE;
SegmentDefs.SwapUp[segment.fsh];
END; -- of WriteStateSegment --


ReleaseStateSegment: PUBLIC PROCEDURE [segment: StateSegment] =
BEGIN
SegmentDefs.Unlock[segment.fsh];
END; -- of ReleaseStateSegment --


-- Exported procedures private to the implementation --

segmentListHead, segmentListTail: StateSegment ← NIL;


InstallSegments: PUBLIC PROCEDURE [header: POINTER TO StateHeader] =
BEGIN
-- this uses an n↑2 algorithm to discover the disk hints, but we don’t care
-- how long installation takes.
seg: StateSegment;
fsh: SegmentDefs.FileSegmentHandle;
IF (header.segmentList ← segmentListHead) = NIL THEN RETURN;
header.firstSegmentPage ← segmentListHead.fsh.base;
FOR seg ← segmentListHead, seg.link UNTIL seg = NIL DO
OPEN SegmentDefs;
fsh ← seg.fsh;
SwapIn[fsh];
seg.hint ← GetFileSegmentDA[fsh];
Unlock[fsh];
DeleteFileSegment[fsh];
ENDLOOP;
END; -- of InstallSegments --


InitializeSegments: PUBLIC PROCEDURE [header: POINTER TO StateHeader] =
BEGIN
OPEN SegmentDefs;
seg: StateSegment;
fsh: FileSegmentHandle;
base: PageNumber ← header.firstSegmentPage;
IF beforeInstallation THEN beforeInstallation ← FALSE
ELSE exD.SysBug[];
FOR seg ← header.segmentList, seg.link UNTIL seg = NIL DO
fsh ← NewFileSegment[stateFile, base, seg.pages, Read];
SetFileSegmentDA[fsh, seg.hint];
seg.fsh ← fsh;
base ← base + seg.pages;
ENDLOOP;
END; -- of InitializeSegments --


-- Main program (executed by start trap) --

stateFF: PageNumber;
stateFile: PUBLIC SegmentDefs.FileHandle;
beforeInstallation: BOOLEAN ← TRUE;


Initialize: PROCEDURE =
BEGIN
byte: CARDINAL;
stateFP: AltoFileDefs.FP ← Core.LookupInFileCache["Laurel.state"L];
IF stateFP = AltoFileDefs.NullFP THEN exD.SysBug[];
stateFile ← SegmentDefs.InsertFile[@stateFP, SegmentDefs.DefaultAccess];
SegmentDefs.LockFile[stateFile];
SegmentDefs.SetFileAccess[stateFile, SegmentDefs.ReadWriteAppend];
[stateFF, byte] ← SegmentDefs.GetEndOfFile[stateFile];
IF byte ~= AltoDefs.BytesPerPage THEN exD.SysBug[]
ELSE stateFF ← stateFF + 1;
END; -- of Initialize --


Initialize[];

END.