-- RTProcessPrivateImpl.Mesa -- last edited February 22, 1983 1:27 pm by Paul Rovner DIRECTORY AMProcessBasic USING[LocalLink], Environment USING[Long, wordsPerPage], Inline USING[LongCOPY], PrincOps USING [FrameHandle, GlobalFrameHandle, Frame, LargeReturnSlot, FrameVec, NullFrame, stackDepth, ControlLink], Process USING[Priority, SetPriority, GetPriority, ValidateProcess, InvalidProcess], ProcessInternal USING[DisableInterrupts], ProcessOperations USING[IndexToHandle, HandleToIndex, ReadPSB, EnableAndRequeue], PSB USING[PsbHandle, PsbIndex, PDA, StateVectorHandle], RTBasic USING [Address], RTProcessPrivate USING [NewCedarProcessRegistered, InvalidateCedarProcess], RTCommon USING [ShortenLongCardinal], RTOS USING[GetCurrent, MyLocalFrame, End], RTSD USING[SD, sFreezer], RTSponge USING[spongePriority, StartSponge, StopSponge], Runtime USING[GlobalFrame], Space USING[nullHandle, PageNumber, Create, virtualMemory, Handle, Delete, Map, LongPointer, Kill], SpecialSpace USING[MakeResident, MakeSwappable, MakeCodeResident, MakeCodeSwappable, MakeGlobalFrameResident--, MakeGlobalFrameSwappable--]; RTProcessPrivateImpl: MONITOR -- Protects the Cedar process registry IMPORTS AMProcessBasic, Inline, Process, ProcessInternal, ProcessOperations, RTCommon, RTOS, RTProcessPrivate, RTSponge, Runtime, Space, SpecialSpace EXPORTS RTOS = BEGIN PageSize: CARDINAL = Environment.wordsPerPage; --Public signals FrameCopySpaceTooSmall: PUBLIC SIGNAL = CODE; TooManyCedarProcesses: PUBLIC SIGNAL = CODE; -- Variables -- pinned frame body buffer for the stack scan fbpNext: LONG POINTER _ NIL; fbp: LONG POINTER _ NIL; -- init by a call on AllocateFrameBodyBuffer from RTRefCountsImpl fbpMaxNext: LONG POINTER; codeLockCount: CARDINAL _ 0; rtProcessStarted: BOOL _ FALSE; frameBodyMasterPages: CARDINAL _ 60; frameBodyMasterSpace: Space.Handle _ Space.nullHandle; frameBodyBufferSpace: Space.Handle _ Space.nullHandle; thisModule: PROGRAM = Runtime.GlobalFrame[RegisterCedarProcess]; -- NOTE resident CedarProcessRegistry: PACKED ARRAY PSB.PsbIndex OF BOOL _ ALL[FALSE]; nCedarProcesses: CARDINAL _ 0; maxCedarPSBI: PSB.PsbIndex _ 0; CedarFrameChainRegistry: ARRAY [0..CedarFrameChainRegistrySize) OF DESCRIPTOR FOR ARRAY OF POINTER TO PrincOps.FrameHandle; CedarFrameChainRegistrySize: CARDINAL = 20; fchNext: CARDINAL _ 0; -- ************ Process registry maintenance (Begin) UnregisterCedarProcess: PUBLIC PROC[psbi: PSB.PsbIndex] = { IF DoUnregisterCedarProcess[psbi] AND rtProcessStarted THEN RTProcessPrivate.InvalidateCedarProcess[psbi]}; DoUnregisterCedarProcess: ENTRY PROC[psbi: PSB.PsbIndex] RETURNS[deregistered: BOOL] = { ENABLE UNWIND => NULL; IF CedarProcessRegistry[psbi] THEN {CedarProcessRegistry[psbi] _ FALSE; IF psbi = maxCedarPSBI THEN maxCedarPSBI _ maxCedarPSBI - 1; nCedarProcesses _ nCedarProcesses - 1; RETURN[TRUE]} ELSE RETURN[FALSE]}; RegisterCedarProcess: PUBLIC PROC[psbi: PSB.PsbIndex] = {IF DoRegisterCedarProcess[psbi].found THEN RETURN; IF rtProcessStarted THEN RTProcessPrivate.NewCedarProcessRegistered[psbi]}; RealCL: INTERNAL PROC[cl: PrincOps.ControlLink, psbi: PSB.PsbIndex] RETURNS[PrincOps.ControlLink] = INLINE {IF RTSD.SD[RTSD.sFreezer] # 0 THEN RETURN[AMProcessBasic.LocalLink[cl, psbi]] ELSE RETURN[cl]}; DoRegisterCedarProcess: ENTRY PROC[psbi: PSB.PsbIndex] RETURNS[found: BOOL] = { ENABLE UNWIND => NULL; IF CedarProcessRegistry[psbi] THEN RETURN[TRUE]; -- awreddy registered. -- whiz up the dynamic call chain until I find the top -- and stuff RTOS.End there FOR root: PrincOps.FrameHandle _ RTOS.MyLocalFrame[], RealCL[root.returnlink, psbi].frame DO IF root.returnlink.proc THEN {root.returnlink _ LOOPHOLE[RTOS.End]; EXIT} ENDLOOP; -- now register it. CedarProcessRegistry[psbi] _ TRUE; IF psbi > maxCedarPSBI THEN maxCedarPSBI _ psbi; nCedarProcesses _ nCedarProcesses + 1; RETURN[FALSE]}; RegisterFrameChains: PUBLIC ENTRY PROC[d: DESCRIPTOR FOR ARRAY OF POINTER TO PrincOps.FrameHandle] = { ENABLE UNWIND => NULL; FOR i: CARDINAL IN [0..fchNext) DO IF CedarFrameChainRegistry[i] = DESCRIPTOR[NIL, 0] THEN {CedarFrameChainRegistry[i] _ d; RETURN}; -- found an empty slot ENDLOOP; -- not enough slots; here to extend the registry (someday) IF fchNext > CedarFrameChainRegistrySize THEN ERROR; -- ERROR TooManyCedarFrameChains; CedarFrameChainRegistry[fchNext] _ d; fchNext _ fchNext + 1}; UnregisterFrameChains: PUBLIC ENTRY PROC[d: DESCRIPTOR FOR ARRAY OF POINTER TO PrincOps.FrameHandle] = { ENABLE UNWIND => NULL; FOR i: CARDINAL IN [0..fchNext) DO IF CedarFrameChainRegistry[i] = d THEN {CedarFrameChainRegistry[i] _ DESCRIPTOR[NIL, 0]; RETURN}; -- found it ENDLOOP; ERROR}; -- ************ Process registry maintenance (End) --**************Stoppable process stuff (Begin) -- After this returns there will be no cedar client activity until ReleaseProcesses returns -- StopProcesses can't use FrameImpl for its return -- (i.e it must be an inline), because someone at a -- lower priority may be in FrameImpl, holding the lock StopProcesses: PROC RETURNS[oldPriority: Process.Priority] = INLINE { oldPriority _ Process.GetPriority[]; -- remember the caller's priority IF oldPriority >= RTSponge.spongePriority THEN ERROR; Process.SetPriority[RTSponge.spongePriority]; RTSponge.StartSponge[]; RETURN[oldPriority]}; Stopped: PROC[ph: PSB.PsbHandle] RETURNS[BOOL] = INLINE {RETURN[PSB.PDA[ph].link.priority < RTSponge.spongePriority]}; ReleaseProcesses: PROC[oldPriority: Process.Priority] = INLINE { -- allow cedar client processes to continue RTSponge.StopSponge[]; Process.SetPriority[oldPriority]}; --**************Stoppable process stuff (End) -- Collector invariant guarantees that only one guy at a time will be in here. SnapshotTheFrameHeap: PUBLIC ENTRY PROC = { ENABLE UNWIND => NULL; myPriority: Process.Priority; success: BOOL; SpecialSpace.MakeResident[frameBodyBufferSpace]; fbpNext _ fbp; -- If fbp storage is too small, FrameCopySpaceTooSmall will be raised AFTER -- ReleaseProcesses is done LockThisCode[]; myPriority _ StopProcesses[]; -- an INLINE. No use of FrameImpl for return, cause -- someone at a lower priority may be in it, holding its lock. success _ DoSnapshotTheFrameHeap[]; ReleaseProcesses[myPriority]; UnLockThisCode[]; IF NOT success THEN {Space.Kill[frameBodyBufferSpace]; SpecialSpace.MakeSwappable[frameBodyBufferSpace]; ERROR FrameCopySpaceTooSmall}; SpecialSpace.MakeSwappable[frameBodyBufferSpace]}; NewDoSnapshotTheFrameHeap: INTERNAL PROC RETURNS[success: BOOL _ TRUE] = INLINE { -- turn off interrupts -- copy state vector bodies -- for each state vector -- { svh: PSB.StateVectorHandle = XXX; -- IF NOT CopyFrameBody[LOOPHOLE[@PSB.PDA[svh].stk, LONG POINTER], -- MIN[PSB.PDA[svh].stkptr + 1, PrincOps.stackDepth]] -- ....stkptr + 1 because one word of a REF may have been popped -- THEN {turn on interrupts; RETURN[FALSE]}}; -- initialize framePageMap -- FramePageMapArray: TYPE = ARRAY [0..256) OF LONG POINTER; -- framePageMap: LONG POINTER TO FramePageMapArray _ fbpNext; -- RTMicrocode.LONGZERO[framePageMap, SIZE[FramePageMapArray]]; -- fbpNext _ fbpNext + SIZE[FramePageMapArray]; -- copy the frame heap, building a map of MDS page # -> frameBodyBuffer offset -- for each frame heap page ... -- { framePage: POINTER = XXX; -- framePageMap[framePage/Environment.wordsPerPage] _ fbpNext -- IF NOT CopyFrameBody[LONG[framePage], Environment.wordsPerPage] -- THEN {turn on interrupts; RETURN[FALSE]}}; -- copy the frame free list headers -- freeListHeaders _ fbpNext -- IF NOT CopyFrameBody[XXX, XXX] -- THEN {turn on interrupts; RETURN[FALSE]}; -- turn on interrupts -- for each frame free list, whiz thru corresponding copied frames, clearing their bodies to 0 -- for each frame free list (flp) -- FOR f: LONG POINTER TO PrincOps.Frame -- _ framePageMap[flp/Environment.wordsPerPage] -- + flp MOD Environment.wordsPerPage -- , framePageMap[f.XXX/Environment.wordsPerPage] -- + f.XXX MOD Environment.wordsPerPage -- UNTIL XXX -- DO -- RTMicrocode.LONGZERO[@f.local, GetXFrameSize[f]-SIZE[local PrincOps.Frame]]; -- ENDLOOP; -- (OPTIONAL) whiz thru the GFT. For each entry, if it points into the frame heap, clear -- that frame's body to 0. -- Parse the frame heap: clear frame headers to 0 while (OPTIONALLY) compactifying the -- frameBodyBuffer }; GetXFrameSize: PROC[f: LONG POINTER TO PrincOps.Frame] RETURNS [CARDINAL] = INLINE { FramePrefix: TYPE = MACHINE DEPENDENT RECORD[size: CARDINAL, fsi: CARDINAL]; prefix: LONG POINTER TO FramePrefix = LOOPHOLE[f - SIZE[FramePrefix]]; RETURN[IF prefix.fsi = PrincOps.LargeReturnSlot THEN prefix.size - 1 -- the fsi word is included in the size ELSE PrincOps.FrameVec[prefix.fsi]]}; DoSnapshotTheFrameHeap: INTERNAL PROC RETURNS[success: BOOL] = INLINE { myPSBI: PSB.PsbIndex = RTOS.GetCurrent[]; FOR i: CARDINAL IN [0..fchNext) DO FOR j: CARDINAL IN [0..LENGTH[CedarFrameChainRegistry[i]]) DO IF NOT WalkForCopy[CedarFrameChainRegistry[i][j]^, myPSBI] -- NOTE XXX ARGH THEN RETURN[FALSE] ENDLOOP; ENDLOOP; FOR psbi: PSB.PsbIndex IN [1..maxCedarPSBI] DO IF CedarProcessRegistry[psbi] THEN { ph: PSB.PsbHandle = ProcessOperations.IndexToHandle[psbi]; f: PrincOps.FrameHandle _ NIL; IF myPSBI # psbi THEN UNTIL Stopped[ph] DO Yield[] ENDLOOP; -- here with control, which is retained AT THIS PRIORITY til end of FOR iteration IF myPSBI = psbi THEN f _ RealCL[RTOS.MyLocalFrame[].returnlink, myPSBI].frame -- caller of SnapshotTheFrameHeap ELSE IF PSB.PDA[ph].link.vector THEN -- there's a state vector here { svh: PSB.StateVectorHandle = PSB.PDA[ph].context.state; IF NOT CopyFrameBody[LOOPHOLE[@PSB.PDA[svh].stk, LONG POINTER TO RTBasic.Address], MIN[PSB.PDA[svh].stkptr + 1, PrincOps.stackDepth]] THEN RETURN[FALSE]; -- + 1: one word of a REF may have been popped f _ PSB.PDA[svh].frame} ELSE f _ PSB.PDA[ph].context.frame; IF NOT WalkForCopy[f, psbi] THEN RETURN[FALSE]; };-- end IF CedarProcessRegistry[psbi] THEN ENDLOOP; RETURN[TRUE]}; CheckForModuleReplacement: PUBLIC ENTRY PROC[gfh: PrincOps.GlobalFrameHandle] RETURNS[ok: BOOL] = { ENABLE UNWIND => NULL; myPriority: Process.Priority; IF gfh.copied OR gfh.shared THEN RETURN[FALSE]; LockThisCode[]; myPriority _ StopProcesses[]; -- an INLINE. No use of FrameImpl for return ok _ LookForGFH[gfh]; ReleaseProcesses[myPriority]; UnLockThisCode[]}; WalkForCopy: INTERNAL PROC[f: PrincOps.FrameHandle, psbi: PSB.PsbIndex] RETURNS[success: BOOL _ TRUE] = INLINE {WHILE ValidFrame[f] DO IF NOT CopyFrameBody[LOOPHOLE[LONG[@f.local]], GetFrameSize[f]-SIZE[local PrincOps.Frame]] THEN RETURN[FALSE]; f _ RealCL[f.returnlink, psbi].frame; ENDLOOP}; WalkForLook: INTERNAL PROC[f: PrincOps.FrameHandle, gfh: PrincOps.GlobalFrameHandle, psbi: PSB.PsbIndex] RETURNS[found: BOOL _ FALSE] = INLINE {WHILE ValidFrame[f] DO IF f.accesslink = gfh THEN RETURN[TRUE]; f _ RealCL[f.returnlink, psbi].frame; ENDLOOP}; LookForGFH: INTERNAL PROC[gfh: PrincOps.GlobalFrameHandle] RETURNS[notFound: BOOL _ TRUE] = INLINE { myPSBI: PSB.PsbIndex = RTOS.GetCurrent[]; FOR i: CARDINAL IN [0..fchNext) DO FOR j: CARDINAL IN [0..LENGTH[CedarFrameChainRegistry[i]]) DO IF WalkForLook[CedarFrameChainRegistry[i][j]^, gfh, myPSBI] -- NOTE XXX ARGH THEN RETURN[FALSE] ENDLOOP; ENDLOOP; FOR psbi: PSB.PsbIndex IN [1..maxCedarPSBI] DO IF CedarProcessRegistry[psbi] THEN { ph: PSB.PsbHandle = ProcessOperations.IndexToHandle[psbi]; f: PrincOps.FrameHandle _ NIL; IF myPSBI # psbi THEN UNTIL Stopped[ph] DO Yield[] ENDLOOP; -- here with control, which is retained AT THIS PRIORITY til end of FOR iteration IF myPSBI = psbi THEN f _ RealCL[RTOS.MyLocalFrame[].returnlink, myPSBI].frame -- caller of SnapshotTheFrameHeap ELSE IF PSB.PDA[ph].link.vector THEN -- there's a state vector here { svh: PSB.StateVectorHandle = PSB.PDA[ph].context.state; f _ PSB.PDA[svh].frame} ELSE f _ PSB.PDA[ph].context.frame; IF WalkForLook[f, gfh, psbi] THEN RETURN[FALSE]}; ENDLOOP}; LockThisCode: INTERNAL PROC = INLINE {SpecialSpace.MakeGlobalFrameResident[RTProcessPrivateImpl]; SpecialSpace.MakeCodeResident[thisModule]}; UnLockThisCode: INTERNAL PROC = INLINE {SpecialSpace.MakeCodeSwappable[thisModule]; --SpecialSpace.MakeGlobalFrameSwappable[RTProcessPrivateImpl]--}; MapRCFrameBodies: PUBLIC PROC[conservativeScanner: PROC[pa: LONG POINTER TO RTBasic.Address, nWords: CARDINAL]] = {conservativeScanner [fbp, RTCommon.ShortenLongCardinal[LOOPHOLE[fbpNext, LONG CARDINAL] - LOOPHOLE[fbp, LONG CARDINAL]]]; Space.Kill[frameBodyBufferSpace]; }; -- called by the collector: only one guy at a time can be in -- here, and exclusive of SnapshotTheFrameHeap AllocateFrameBodyBuffer: PUBLIC PROC[nPages: CARDINAL] = { IF frameBodyBufferSpace # Space.nullHandle THEN Space.Delete[frameBodyBufferSpace]; IF nPages > frameBodyMasterPages THEN { frameBodyMasterPages _ nPages; Space.Delete[frameBodyMasterSpace]; frameBodyMasterSpace _ Space.Create[size: frameBodyMasterPages, parent: Space.virtualMemory]}; frameBodyBufferSpace _ Space.Create[nPages, frameBodyMasterSpace]; Space.Map[frameBodyBufferSpace]; fbp _ fbpNext _ Space.LongPointer[frameBodyBufferSpace]; fbpMaxNext _ fbp + nPages * PageSize - 1}; CopyFrameBody: INTERNAL PROC[pa: LONG POINTER, nWords: CARDINAL] RETURNS[success: BOOL] = INLINE { dest: LONG POINTER = fbpNext; fbpNext _ fbpNext + nWords; IF LOOPHOLE[fbpNext, LONG CARDINAL] > LOOPHOLE[fbpMaxNext, LONG CARDINAL] THEN RETURN[FALSE] ELSE {Inline.LongCOPY[pa, nWords, dest]; RETURN[TRUE]}}; GetFrameSize: PROC[f: PrincOps.FrameHandle] RETURNS [CARDINAL] = INLINE { FramePrefix: TYPE = MACHINE DEPENDENT RECORD[ size: CARDINAL, fsi: CARDINAL]; prefix: POINTER TO FramePrefix = LOOPHOLE[f - SIZE[FramePrefix]]; RETURN[IF prefix.fsi = PrincOps.LargeReturnSlot THEN prefix.size - 1 -- the fsi word is included in the size ELSE PrincOps.FrameVec[prefix.fsi]]}; ValidFrame: PROC[f: PrincOps.FrameHandle] RETURNS[BOOL] = INLINE {RETURN[f # PrincOps.NullFrame AND LOOPHOLE[f, CARDINAL] MOD 4 = 0]}; InvalidProcess: PROC[px: PSB.PsbIndex] RETURNS[BOOL] = { Process.ValidateProcess[px ! Process.InvalidProcess => GOTO ng]; RETURN[FALSE]; EXITS ng => RETURN[TRUE]}; PageFromLongPointer: PROC[lp: LONG POINTER] RETURNS [page: Space.PageNumber] = INLINE {OPEN LOOPHOLE[lp, num Environment.Long]; RETURN[highbits*256+lowbits/256]}; Yield: PROC = INLINE { ProcessInternal.DisableInterrupts[]; -- (to cancel subsequent enable) ProcessOperations.EnableAndRequeue[@PSB.PDA.ready, @PSB.PDA.ready, ProcessOperations.ReadPSB[]] }; RTProcessStarted: PUBLIC ENTRY PROC = {ENABLE UNWIND => NULL; rtProcessStarted _ TRUE; FOR psbi: PSB.PsbIndex IN [1..maxCedarPSBI] DO IF CedarProcessRegistry[psbi] THEN RTProcessPrivate.NewCedarProcessRegistered[psbi]; ENDLOOP}; -- START HERE -- pre-allocate space for the frameheap snapshot 'cause collection maybe for VMExhausted frameBodyMasterSpace _ Space.Create[size: frameBodyMasterPages, parent: Space.virtualMemory]; END. Κ X– "Mesa" style˜IprocšŒ ΟcUœΟk œžœžœ!žœžœ‰žœ[žœ+žœ[žœžœžœ"žœ!žœCžœžœžœ%žœžœžœžœ7žœžœ}žœuœžœ'œžœ^žœ&žœžœžœžœžœœžœžœžœžœžœžœ œ/œ žœžœžœ žœžœžœBœžœžœžœžœžœžœ‰žœ1œžœžœžœ žœžœžœžœžœžœ+žœ"žœž œžœžœžœžœžœ6žœžœ5œΟnœžœžœžœžœ žœžœ4Ÿœžœžœžœžœžœ žœžœžœžœ#žœžœ–žœžœ žœžœžœŸœžœžœžœžœ$žœžœžœžœ;Ÿœžœžœ!žœžœžœžœžœžœžœžœžœ+žœžœŸœžœžœžœ žœžœ žœžœžœžœžœžœžœœ 7œœžœžœ<žœžœžœžœžœžœžœ œ#žœlžœžœŸœžœžœžœž œžœžœžœžœžœžœžœžœžœžœžœžœžœž œžœžœ"žœœžœ ;œžœ'žœžœ"œNŸœžœžœžœž œžœžœžœžœžœžœžœžœžœžœžœžœžœ,žœž œžœžœ œžœžœ3œ0œ\œ4œ4œ8œŸ œžœžœ$žœ-"œžœ(žœžœZžœŸœžœžœ žœžœžœžœžœžœ3Ÿœžœ$žœ,œG.œOœŸœžœžœžœ žœžœžœ5žœ_Lœ œ:›œlžœžœžœxžœVŸœžœžœžœ ž œžœ œœœ/œMœ]œNœ9œœBœ:ΟiœEœ  œOœ%œ'œ@ œMœ9œ$œ œ&œ2œœ_œ&œ•œZœœYœœWœœ Ÿ œžœžœžœžœžœžœžœžœžœž œžœžœžœžœžœžœžœžœžœžœ8žœ(œžœ%Ÿœžœžœžœ žœžœžœ žœžœžœžœžœžœžœžœžœ+žœžœžœ5œžœžœžœžœ žœžœžœ žœžœžœžœžœ\žœžœžœžœ žœ žœRœžœžœ žœ>"œžœžœžœžœ"žœœžœžœžœ(žœžœžœžœžœIžœžœžœDžœžœžœ=žœžœžœ0œžœžœžœžœžœ"žœžœžœžœžœ*œžœžœžœŸœžœžœžœ(žœžœ žœžœžœ,žœ žœ žœžœžœ=-œ\Ÿ œžœžœ žœžœ žœžœžœžœžœžœžœžœžœAžœ žœžœžœ6žœ Ÿ œžœžœ‘žœžœžœžœžœžœžœžœžœžœžœ:žœ Ÿ œžœžœ(žœ žœžœžœžœ žœžœžœžœžœžœžœžœžœ+žœžœ:œžœžœžœžœ žœžœžœ žœžœžœžœžœ\žœžœžœžœ žœ žœRœžœ žœ žœ?"œžœžœžœžœ"žœœžœžœžœ,žœžœžœžœžœ"žœžœžœžœ žœŸ œžœžœžœzŸœžœžœžœ7?œ ŸœžœžœIžœžœžœžœTžœVžœ žœžœ6žœžœžœ8=œ/œŸœžœžœ žœ žœ)žœ+žœžœήŸ œžœžœžœžœ žœ žœ žœžœžœžœ6žœžœ žœžœžœ žœžœ žœžœžœ žœ%žœžœŸ œžœžœžœžœžœžœž œžœžœžœžœžœžœžœžœžœ5žœ(œžœ%Ÿ œžœ"žœžœžœžœžœžœžœžœ Ÿœžœžœ žœžœAžœ žœžœ žœžœžœŸœžœžœžœ žœžœžœžœžœ Ÿœžœžœ-!œ*žœžœ2žœžœTŸœžœžœžœžœžœžœžœžœžœ žœžœžœžœ8žœœYœ_žœ˜ΒŒ—…—FDP’