-- 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.