-- CheckPoint.Mesa Edited by Sandman on September 24, 1980 10:44 AM
-- Copyright Xerox Corporation 1979, 1980
DIRECTORY
AllocDefs USING [
AddSwapStrategy, RemoveSwapStrategy, SwappingProcedure, SwapStrategy],
AltoDefs USING [BytesPerPage, PageCount, PageNumber, PageSize],
AltoFileDefs USING [CFA, FA, fillinDA, FP, NullFP, vDA],
BcdDefs USING [VersionStamp],
BFSDefs USING [ActOnPages, GetNextDA],
ControlDefs USING [
AllocationVector, AllocationVectorSize, AV, ControlLink, EntryVectorItem,
FrameHandle, FrameVec, GFT, GFTIndex, GlobalFrameHandle, LargeReturnSlot,
LastAVSlot, PrefixHandle, ProcDesc, SpecialReturnSlot, StateVector,
SVPointer],
CoreSwapDefs USING [PuntInfo, level],
DiskDefs USING [DA, DiskRequest, RealDA],
DiskKDDefs USING [CloseDiskKD],
FrameDefs USING [GlobalFrame, MakeCodeResident, SwapInCode],
FrameOps USING [CodeHandle, Free, FlushLargeFrames, MyLocalFrame],
ImageDefs USING [ImageVersion, PuntMesa, UserCleanupProc],
ImageFormat USING [
FirstImageDataPage, HeaderPages, ImageHeader, ImagePrefix, MapItem,
VersionID],
InlineDefs USING [BITAND, COPY],
LoadStateFormat USING [LoadState],
LoadStateOps USING [initstate, InputLoadState, ReleaseLoadState, state],
MiscDefs USING [CurrentTime, GetNetworkNumber, SetBlock, Zero],
NucleusOps USING [
BFS, Directory, DiskKD, Faults, Files, FSP, HyperRegion, LoadState, MesaInit,
Miscellaneous, Modules, NonResident, OurProcess, SegmentsA, SegmentsB,
StreamsA, StreamsB, StreamsC, StringsA, StringsB],
OsStaticDefs USING [OsStatics],
ProcessDefs USING [
CV, DisableInterrupts, DIW, EnableInterrupts, Priority, SetPriority],
ProcessOps USING [
ActiveWord, CurrentPSB, CurrentState, FirstProcess, LastProcess,
NullQueueHandle, Queue, ReadWDC, ReadyList, Requeue, WakeupsWaiting,
WriteWDC],
PSBDefs USING [ProcessHandle, PSB],
Region USING [Node, NodeObject],
SDDefs USING [sAllocTrap, SD, sSwapTrap, sXferTrap],
SegmentDefs USING [
AddressFromPage, Append, CloseFile, DataSegmentAddress, DataSegmentHandle,
DefaultBase, DefaultVersion, DeleteDataSegment, EnumerateDataSegments,
EnumerateFiles, EnumerateFileSegments, FileError, FileHandle,
FileSegmentAddress, FileSegmentHandle, GetFileSegmentDA, JumpToPage,
MapFileSegment, NewDataSegment, NewFile, Object, ObjectHandle, Read, SetEndOfFile,
SwapIn, SwapOut, Unlock, Write],
Storage USING [Pages, FreePages, Prune],
SwapperOps USING [
AllocateObject, LiberateObject, mdsNodes, MoveCode, DisableHyperspace,
EnableHyperspace, InitMemoryConfig],
TrapOps USING [ReadATP, ReadOTP, ReadXTS, WriteXTS];
CheckPoint: PROGRAM
IMPORTS
BFSDefs, CoreSwapDefs, AllocDefs, SwapperOps, DiskDefs, DiskKDDefs, FrameDefs,
FrameOps, ImageDefs, InlineDefs, LoadStateOps, MiscDefs, NucleusOps,
ProcessDefs, ProcessOps, SegmentDefs, Storage, TrapOps
EXPORTS ImageDefs
SHARES DiskDefs, SegmentDefs =
BEGIN OPEN ImageFormat, ControlDefs;
CFA: TYPE = AltoFileDefs.CFA;
DataSegmentHandle: TYPE = SegmentDefs.DataSegmentHandle;
FP: TYPE = AltoFileDefs.FP;
FileHandle: TYPE = SegmentDefs.FileHandle;
FileSegmentHandle: TYPE = SegmentDefs.FileSegmentHandle;
PageSize: CARDINAL = AltoDefs.PageSize;
PageCount: TYPE = AltoDefs.PageCount;
PageNumber: TYPE = AltoDefs.PageNumber;
vDA: TYPE = AltoFileDefs.vDA;
SwapTrapDuringMakeCheck: PUBLIC SIGNAL = CODE;
SwapErrorDuringMakeCheck: PUBLIC SIGNAL = CODE;
SwapOutDuringMakeCheck: PUBLIC SIGNAL = CODE;
NoRoomInCheckMap: PUBLIC SIGNAL = CODE;
SwapTrapError: PROCEDURE =
BEGIN
dest: ControlLink;
s: StateVector;
ProcessDefs.DisableInterrupts[];
s ← STATE;
dest ← TrapOps.ReadOTP[];
ProcessDefs.EnableInterrupts[];
SIGNAL SwapTrapDuringMakeCheck;
RETURN WITH s;
END;
SwapOutError: AllocDefs.SwappingProcedure =
BEGIN SIGNAL SwapOutDuringMakeCheck; RETURN[TRUE]; END;
-- File Segment Transfer Routines
LockCodeSegment: PROCEDURE [frame: GlobalFrameHandle] =
BEGIN
FrameDefs.MakeCodeResident[frame];
FrameDefs.SwapInCode[frame];
SegmentDefs.Unlock[FrameOps.CodeHandle[frame]];
END;
UnlockCodeSegment: PROCEDURE [frame: GlobalFrameHandle] =
BEGIN SegmentDefs.Unlock[FrameOps.CodeHandle[frame]]; END;
DAofPage: PROCEDURE [file: FileHandle, page: PageNumber] RETURNS [next: vDA] =
BEGIN
cfa: CFA;
buf: POINTER = Storage.Pages[1];
cfa.fp ← file.fp;
cfa.fa ← AltoFileDefs.FA[file.fp.leaderDA, 0, 0];
next ← SegmentDefs.JumpToPage[@cfa, page - 1, buf].next;
Storage.FreePages[buf];
RETURN
END;
FillInCAs: PROCEDURE [
Image: POINTER TO ImageHeader, mapindex: CARDINAL, ca: POINTER] =
BEGIN
i: CARDINAL;
map: POINTER TO ARRAY [0..0) OF normal MapItem = LOOPHOLE[@Image.map];
addr: POINTER;
FOR i IN [0..mapindex) DO
addr ← SegmentDefs.AddressFromPage[map[i].page];
THROUGH [0..map[i].count) DO
ca↑ ← addr; ca ← ca + 1; addr ← addr + AltoDefs.PageSize; ENDLOOP;
ENDLOOP;
END;
EnumerateNeededModules: PROCEDURE [proc: PROCEDURE [GlobalFrameHandle]] =
BEGIN
proc[FrameDefs.GlobalFrame[EnumerateNeededModules]];
proc[LOOPHOLE[NucleusOps.BFS]];
proc[LOOPHOLE[NucleusOps.SegmentsA]];
proc[LOOPHOLE[NucleusOps.SegmentsB]];
proc[LOOPHOLE[NucleusOps.Files]];
proc[LOOPHOLE[NucleusOps.Faults]];
proc[LOOPHOLE[NucleusOps.DiskKD]];
proc[LOOPHOLE[NucleusOps.Miscellaneous]];
proc[LOOPHOLE[NucleusOps.Directory]];
proc[LOOPHOLE[NucleusOps.StreamsA]];
proc[LOOPHOLE[NucleusOps.StreamsB]];
proc[LOOPHOLE[NucleusOps.StreamsC]];
proc[LOOPHOLE[NucleusOps.FSP]];
proc[LOOPHOLE[NucleusOps.StringsA]];
proc[LOOPHOLE[NucleusOps.StringsB]];
proc[LOOPHOLE[NucleusOps.LoadState]];
proc[LOOPHOLE[NucleusOps.MesaInit]];
proc[LOOPHOLE[NucleusOps.NonResident]];
proc[LOOPHOLE[NucleusOps.OurProcess]];
proc[LOOPHOLE[NucleusOps.HyperRegion]];
proc[LOOPHOLE[NucleusOps.Modules]];
END;
AdjustLoadState: PROCEDURE [state: FileSegmentHandle] =
BEGIN OPEN SegmentDefs;
imageFile: FileHandle = FrameOps.CodeHandle[
LOOPHOLE[NucleusOps.MesaInit]].file;
loadstate: LoadStateFormat.LoadState = FileSegmentAddress[state];
i: CARDINAL;
FOR i IN [0..loadstate.nBcds) DO
WITH b: loadstate.bcds[i] SELECT FROM
alto => IF b.fp = AltoFileDefs.NullFP THEN b.fp ← imageFile.fp;
ENDCASE;
ENDLOOP;
RETURN
END;
AssureObjects: PROCEDURE = {
OPEN SwapperOps, SegmentDefs;
a: FileHandle;
b: DataSegmentHandle;
c: FileSegmentHandle;
a ← LOOPHOLE[SwapperOps.AllocateObject[SIZE[file Object]]];
a↑ ← [,file[,,,,,,,,,,,]];
b ← LOOPHOLE[SwapperOps.AllocateObject[SIZE[data segment Object]]];
b↑ ← [,segment[,data[,]]];
c ← LOOPHOLE[SwapperOps.AllocateObject[SIZE[file segment Object]]];
c↑ ← [,segment[,file[,,,,,,,,]]];
SwapperOps.LiberateObject[a];
SwapperOps.LiberateObject[b];
SwapperOps.LiberateObject[c]};
MakeCheckPoint: PUBLIC PROCEDURE [name: STRING] RETURNS [restart: BOOLEAN] =
BEGIN OPEN SegmentDefs, DiskDefs, AltoFileDefs;
wdc: CARDINAL;
diskrequest: DiskRequest;
savealloctrap, saveswaptrap: ControlLink;
auxtrapFrame: FrameHandle;
saveAllocationVector: AllocationVector;
saveXferTrap, saveXferTrapStatus: UNSPECIFIED;
savePuntData: POINTER;
datapages: PageCount ← 0;
SwapOutErrorStrategy: AllocDefs.SwapStrategy ← AllocDefs.SwapStrategy[
link:, proc: SwapOutError];
mapindex: CARDINAL ← 0;
maxFileSegPages: CARDINAL ← 0;
endofdatamapindex: CARDINAL;
HeaderSeg, daMapSeg: DataSegmentHandle;
Image: POINTER TO ImageHeader;
HeaderDA: vDA;
checkFile: FileHandle;
saveDIW: WORD;
savePV: ARRAY [0..15] OF UNSPECIFIED;
saveReadyList: ProcessOps.Queue;
savePriority: ProcessDefs.Priority;
saveCurrentPSB: PSBDefs.ProcessHandle;
saveCurrentState: SVPointer;
initstateseg: FileSegmentHandle ← LoadStateOps.initstate;
stateseg: FileSegmentHandle ← LoadStateOps.state;
net: CARDINAL ← MiscDefs.GetNetworkNumber[];
segs: DESCRIPTOR FOR ARRAY OF FileSegmentHandle;
maxnumbersegments: CARDINAL ← 0;
nextpage: PageNumber;
level: CARDINAL ← 0;
wordsForDAMap: CARDINAL ← 0;
mdsFreeList: DESCRIPTOR FOR ARRAY OF Region.NodeObject;
SaveMDSFreeList: PROCEDURE =
BEGIN OPEN SwapperOps;
nNodes, i: CARDINAL;
node: Region.Node;
nNodes ← 0;
FOR node ← mdsNodes.fwd, node.fwd UNTIL node = @mdsNodes DO
nNodes ← nNodes + 1; ENDLOOP;
IF nNodes = 0 THEN BEGIN mdsFreeList ← DESCRIPTOR[NIL, 0]; RETURN END;
mdsFreeList ← DESCRIPTOR[auxalloc[nNodes*SIZE[Region.NodeObject]], nNodes];
i ← 0;
FOR node ← mdsNodes.fwd, node.fwd UNTIL node = @mdsNodes DO
mdsFreeList[i] ← node↑; i ← i + 1; ENDLOOP;
END;
RestoreMDSFreeList: PROCEDURE =
BEGIN OPEN SwapperOps;
i: CARDINAL ← 0;
node: Region.Node;
IF LENGTH[mdsFreeList] = 0 THEN RETURN;
FOR i IN [0..LENGTH[mdsFreeList]) DO
node ← AddressFromPage[mdsFreeList[i].base];
node↑ ← mdsFreeList[i];
ENDLOOP;
END;
SaveProcesses: PROCEDURE =
BEGIN OPEN ProcessOps;
saveDIW ← ProcessDefs.DIW↑;
savePV ← ProcessDefs.CV↑;
ProcessDefs.DIW↑ ← 0;
WakeupsWaiting↑ ← 0;
saveReadyList ← ReadyList↑;
saveCurrentPSB ← CurrentPSB↑;
savePriority ← CurrentPSB.priority;
saveCurrentState ← CurrentState↑;
END;
RestoreProcesses: PROCEDURE =
BEGIN OPEN ProcessDefs, ProcessOps;
p: PSBDefs.ProcessHandle;
ActiveWord↑ ← 77777B;
ProcessDefs.DIW↑ ← saveDIW;
ProcessDefs.CV↑ ← savePV;
ReadyList↑ ← saveReadyList;
CurrentPSB↑ ← saveCurrentPSB;
CurrentPSB.priority ← LAST[Priority];
CurrentState↑ ← saveCurrentState;
FOR p ← FirstProcess↑, p + SIZE[PSBDefs.PSB] UNTIL p = LastProcess↑ DO
IF p.state = alive AND p.timeout # 0 AND p.waitingOnCV THEN
BEGIN
p.waitingOnCV ← FALSE;
Requeue[from: NullQueueHandle, to: ReadyList, p: p];
END;
ENDLOOP;
SetPriority[savePriority];
RETURN
END;
EnterNormalMapItem: PROCEDURE [vmpage: PageNumber, pages: PageCount] =
BEGIN
map: POINTER TO normal MapItem = LOOPHOLE[@Image.map];
IF pages > 127 THEN SIGNAL SwapErrorDuringMakeCheck;
IF mapindex >=
PageSize*HeaderPages - SIZE[ImagePrefix] - SIZE[normal MapItem] THEN
SIGNAL NoRoomInCheckMap;
(map + mapindex)↑ ← MapItem[vmpage, pages, normal[]];
mapindex ← mapindex + SIZE[normal MapItem];
END;
CountDataSegments: PROCEDURE [s: DataSegmentHandle] RETURNS [BOOLEAN] =
BEGIN
IF s # HeaderSeg AND s # daMapSeg THEN datapages ← datapages + s.pages;
RETURN[FALSE];
END;
MapDataSegments: PROCEDURE [s: DataSegmentHandle] RETURNS [BOOLEAN] =
BEGIN
IF s # HeaderSeg AND s # daMapSeg THEN
BEGIN
EnterNormalMapItem[s.VMpage, s.pages];
nextpage ← nextpage + s.pages;
END;
RETURN[FALSE];
END;
CountMaxSegmentsPerFile: PROCEDURE [f: FileHandle] RETURNS [BOOLEAN] =
BEGIN
maxnumbersegments ← MAX[maxnumbersegments, f.swapcount];
RETURN[FALSE];
END;
EnterSwappedInPerFile: PROCEDURE [f: FileHandle] RETURNS [BOOLEAN] =
BEGIN
nsegs: CARDINAL ← 0;
next: PageNumber ← DefaultBase;
i: CARDINAL;
OrganizeSegments: PROCEDURE [s: FileSegmentHandle] RETURNS [BOOLEAN] =
BEGIN
i, j: CARDINAL;
IF ~s.swappedin OR s.file # f THEN RETURN[FALSE];
FOR i IN [0..nsegs) DO
IF segs[i].base > s.base THEN GOTO insert;
REPEAT
insert =>
BEGIN
FOR j DECREASING IN [i..nsegs) DO segs[j + 1] ← segs[j]; ENDLOOP;
segs[i] ← s;
END;
FINISHED => segs[nsegs] ← s;
ENDLOOP;
RETURN[(nsegs ← nsegs + 1) = f.swapcount];
END;
IF f = checkFile OR f.swapcount = 0 THEN RETURN[FALSE];
[] ← EnumerateFileSegments[OrganizeSegments];
FOR i IN [0..nsegs) DO
IF segs[i].base # next THEN EnterChangeMapItem[segs[i]]
ELSE EnterNormalMapItem[segs[i].VMpage, segs[i].pages];
next ← segs[i].base + segs[i].pages;
ENDLOOP;
RETURN[FALSE];
END;
EnterChangeMapItem: PROCEDURE [s: FileSegmentHandle] =
BEGIN
map: POINTER TO change MapItem = LOOPHOLE[@Image.map];
da: DiskDefs.DA ← DiskDefs.RealDA[GetFileSegmentDA[s]];
IF s.pages > 127 THEN SIGNAL SwapErrorDuringMakeCheck;
IF mapindex >=
PageSize*HeaderPages - SIZE[ImagePrefix] - SIZE[change MapItem] THEN
SIGNAL NoRoomInCheckMap;
(map + mapindex)↑ ← MapItem[s.VMpage, s.pages, change[da, s.base]];
mapindex ← mapindex + SIZE[change MapItem];
END;
checkFile ← NewFile[name, Read + Write + Append, DefaultVersion];
ProcessDefs.DisableInterrupts[];
wdc ← ProcessOps.ReadWDC[];
level ← CoreSwapDefs.level;
CoreSwapDefs.level ← -1;
SaveProcesses[];
ImageDefs.UserCleanupProc[Checkpoint];
SwapperOps.MoveCode[direction: intoMDS];
SwapperOps.DisableHyperspace[];
SwapIn[initstateseg];
[] ← LoadStateOps.InputLoadState[]; -- bring it in for first time
AdjustLoadState[stateseg];
[] ← Storage.Prune[];
SetupAuxStorage[];
EnumerateNeededModules[LockCodeSegment];
HeaderDA ← DAofPage[checkFile, 1]; -- set up private frame allocation trap
FrameOps.FlushLargeFrames[];
savealloctrap ← SDDefs.SD[SDDefs.sAllocTrap];
SDDefs.SD[SDDefs.sAllocTrap] ← auxtrapFrame ← auxtrap[];
saveAllocationVector ← AV↑;
AV↑ ← LOOPHOLE[DataSegmentAddress[AuxSeg], POINTER TO AllocationVector]↑;
HeaderSeg ← NewDataSegment[DefaultBase, 1];
daMapSeg ← NewDataSegment[DefaultBase, 3];
AssureObjects[];
[] ← EnumerateDataSegments[CountDataSegments];
SetEndOfFile[
checkFile, datapages + stateseg.pages*2 + FirstImageDataPage - 1,
AltoDefs.BytesPerPage];
[] ← DiskKDDefs.CloseDiskKD[];
Image ← DataSegmentAddress[HeaderSeg];
MiscDefs.Zero[Image, AltoDefs.PageSize*HeaderPages];
Image.prefix.versionident ← ImageFormat.VersionID; --Image.prefix.options ← 0;
--Image.prefix.state.stk[0] ← Image.prefix.state.stk[1] ← 0;
Image.prefix.state.stkptr ← 2;
Image.prefix.state.dest ← FrameOps.MyLocalFrame[];
Image.prefix.type ← checkfile;
Image.prefix.leaderDA ← checkFile.fp.leaderDA;
Image.prefix.diskAddresses ← DataSegmentAddress[daMapSeg];
Image.prefix.version ← BcdDefs.VersionStamp[
time: MiscDefs.CurrentTime[], net: net,
host: OsStaticDefs.OsStatics.SerialNumber];
Image.prefix.creator ← ImageDefs.ImageVersion[];
-- version stamp of currently running image
nextpage ← FirstImageDataPage;
[] ← EnumerateDataSegments[MapDataSegments];
IF nextpage # FirstImageDataPage + datapages THEN ERROR;
endofdatamapindex ← mapindex; -- Move LoadStates
InlineDefs.COPY[
from: FileSegmentAddress[stateseg], to: FileSegmentAddress[initstateseg],
nwords: initstateseg.pages*PageSize];
MapFileSegment[stateseg, checkFile, datapages + FirstImageDataPage];
EnterNormalMapItem[stateseg.VMpage, stateseg.pages];
MapFileSegment[
initstateseg, checkFile, datapages + FirstImageDataPage + stateseg.pages];
EnterNormalMapItem[initstateseg.VMpage, stateseg.pages];
Image.prefix.loadStateBase ← stateseg.base;
Image.prefix.initialLoadStateBase ← initstateseg.base;
Image.prefix.loadStatePages ← initstateseg.pages; -- now disable swapping
savePuntData ← CoreSwapDefs.PuntInfo↑;
saveswaptrap ← SDDefs.SD[SDDefs.sSwapTrap];
SDDefs.SD[SDDefs.sSwapTrap] ← SwapTrapError;
AllocDefs.AddSwapStrategy[@SwapOutErrorStrategy];
[] ← EnumerateFiles[CountMaxSegmentsPerFile];
segs ← DESCRIPTOR[auxalloc[maxnumbersegments], maxnumbersegments];
[] ← EnumerateFiles[EnterSwappedInPerFile];
SegmentDefs.CloseFile[checkFile ! SegmentDefs.FileError => RESUME ];
checkFile.write ← checkFile.append ← FALSE;
diskrequest ← DiskRequest[
ca: auxalloc[datapages + 3], da: auxalloc[datapages + 3], fixedCA: FALSE,
fp: auxalloc[SIZE[FP]], firstPage: FirstImageDataPage - 1,
lastPage: FirstImageDataPage + datapages - 1, action: WriteD,
lastAction: WriteD, signalCheckError: FALSE,
option: update[BFSDefs.GetNextDA]];
diskrequest.fp↑ ← checkFile.fp;
(diskrequest.ca + 1)↑ ← Image;
FillInCAs[Image, endofdatamapindex, diskrequest.ca + 2];
MiscDefs.SetBlock[diskrequest.da, fillinDA, datapages + 3];
(diskrequest.da + 1)↑ ← HeaderDA;
SaveMDSFreeList[];
saveXferTrap ← SDDefs.SD[SDDefs.sXferTrap];
SDDefs.SD[SDDefs.sXferTrap] ← FrameOps.MyLocalFrame[];
saveXferTrapStatus ← TrapOps.ReadXTS[];
restart ← BFSDefs.ActOnPages[LOOPHOLE[@diskrequest]].page = 0;
ProcessOps.WriteWDC[wdc];
AV↑ ← saveAllocationVector;
SDDefs.SD[SDDefs.sAllocTrap] ← savealloctrap;
SDDefs.SD[SDDefs.sXferTrap] ← saveXferTrap;
TrapOps.WriteXTS[saveXferTrapStatus];
FrameOps.Free[auxtrapFrame];
RestoreMDSFreeList[];
SwapperOps.InitMemoryConfig[];
DeleteDataSegment[daMapSeg];
DeleteDataSegment[HeaderSeg]; -- turn swapping back on
AllocDefs.RemoveSwapStrategy[@SwapOutErrorStrategy];
SDDefs.SD[SDDefs.sSwapTrap] ← saveswaptrap;
SwapperOps.EnableHyperspace[];
RestoreProcesses[];
CoreSwapDefs.PuntInfo↑ ← savePuntData;
ProcessDefs.EnableInterrupts[];
InlineDefs.COPY[
to: FileSegmentAddress[stateseg], from: FileSegmentAddress[initstateseg],
nwords: initstateseg.pages*PageSize];
LoadStateOps.ReleaseLoadState[];
Unlock[initstateseg];
SwapOut[initstateseg];
DeleteDataSegment[AuxSeg];
EnumerateNeededModules[UnlockCodeSegment];
SwapperOps.MoveCode[direction: outofMDS];
ImageDefs.UserCleanupProc[IF restart THEN Restart ELSE Continue];
RETURN
END;
-- auxillary storage for frames and non-saved items
AuxSeg: DataSegmentHandle;
freepointer: POINTER;
wordsleft: CARDINAL;
SetupAuxStorage: PROCEDURE =
BEGIN OPEN SegmentDefs;
av: POINTER;
i: CARDINAL;
AuxSeg ← NewDataSegment[DefaultBase, 5];
av ← freepointer ← DataSegmentAddress[AuxSeg];
wordsleft ← 10*PageSize;
[] ← auxalloc[AllocationVectorSize];
freepointer ← freepointer + 3;
wordsleft ← wordsleft - 3;
FOR i IN [0..LastAVSlot] DO (av + i)↑ ← (i + 1)*4 + 2; ENDLOOP;
(av + 6)↑ ← (av + LargeReturnSlot)↑ ← (av + SpecialReturnSlot + 1)↑ ← 1;
END;
auxalloc: PROCEDURE [n: CARDINAL] RETURNS [p: POINTER] =
BEGIN -- allocate in multiples of 4 words
p ← freepointer;
n ← InlineDefs.BITAND[n + 3, 177774B];
freepointer ← freepointer + n;
IF wordsleft < n THEN ImageDefs.PuntMesa[];
wordsleft ← wordsleft - n;
RETURN
END;
auxtrap: PROCEDURE RETURNS [myframe: FrameHandle] =
BEGIN
state: StateVector;
newframe: FrameHandle;
eventry: POINTER TO EntryVectorItem;
fsize, findex: CARDINAL;
newG: GlobalFrameHandle;
dest, tempdest: ControlLink;
alloc: BOOLEAN;
gfi: GFTIndex;
ep: CARDINAL;
myframe ← LOOPHOLE[FrameOps.MyLocalFrame[]];
state.dest ← myframe.returnlink;
state.source ← 0;
state.instbyte ← 0;
state.stk[0] ← myframe;
state.stkptr ← 1;
ProcessDefs.DisableInterrupts[];
DO
ProcessDefs.EnableInterrupts[];
TRANSFER WITH state;
ProcessDefs.DisableInterrupts[];
state ← STATE;
dest ← TrapOps.ReadATP[];
myframe.returnlink ← state.source;
tempdest ← dest;
DO
SELECT tempdest.tag FROM
frame =>
BEGIN alloc ← TRUE; findex ← LOOPHOLE[tempdest, CARDINAL]/4; EXIT END;
procedure =>
BEGIN OPEN proc: LOOPHOLE[tempdest, ProcDesc];
gfi ← proc.gfi;
ep ← proc.ep;
[frame: newG, epbase: findex] ← GFT[gfi];
eventry ← @LOOPHOLE[newG.code.shortbase, PrefixHandle].entry[
findex + ep];
findex ← eventry.info.framesize;
alloc ← FALSE;
EXIT
END;
indirect => tempdest ← tempdest.link↑;
ENDCASE => ImageDefs.PuntMesa[];
ENDLOOP;
IF findex > LastAVSlot THEN ImageDefs.PuntMesa[];
fsize ← FrameVec[findex];
IF fsize MOD 4 # 0 THEN fsize ← fsize + 1;
newframe ← LOOPHOLE[freepointer + 1];
freepointer↑ ← findex;
freepointer ← freepointer + fsize;
IF wordsleft < fsize THEN ImageDefs.PuntMesa[]
ELSE wordsleft ← wordsleft - fsize;
IF alloc THEN
BEGIN
state.dest ← myframe.returnlink;
state.stk[state.stkptr] ← newframe;
state.stkptr ← state.stkptr + 1;
END
ELSE
BEGIN
state.dest ← dest;
newframe.accesslink ← LOOPHOLE[AV[findex].frame];
AV[findex].frame ← newframe;
state.source ← myframe.returnlink;
END;
ENDLOOP;
END;
END.