-- RTProcessPrivateImpl.Mesa -- last edited December 6, 1982 12:49 pm by Paul Rovner DIRECTORY Environment USING[Long, wordsPerPage], Inline USING[LongCOPY], PrincOps USING [FrameHandle, GlobalFrameHandle, Frame, LargeReturnSlot, FrameVec, NullFrame, stackDepth], 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], 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 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: BOOLEAN _ 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: BOOLEAN] = { 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]}; 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[], root.returnlink.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[BOOLEAN] = 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: BOOLEAN; 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]}; DoSnapshotTheFrameHeap: INTERNAL PROC RETURNS[success: BOOLEAN] = 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]^] 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 _ RTOS.MyLocalFrame[].returnlink.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] THEN RETURN[FALSE]; };-- end IF CedarProcessRegistry[psbi] THEN ENDLOOP; RETURN[TRUE]}; CheckForModuleReplacement: PUBLIC ENTRY PROC[gfh: PrincOps.GlobalFrameHandle] RETURNS[ok: BOOLEAN] = { 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] RETURNS[success: BOOLEAN _ TRUE] = INLINE {WHILE ValidFrame[f] DO IF NOT CopyFrameBody[LOOPHOLE[LONG[@f.local]], GetFrameSize[f]-SIZE[local PrincOps.Frame]] THEN RETURN[FALSE]; f _ f.returnlink.frame; ENDLOOP}; WalkForLook: INTERNAL PROC[f: PrincOps.FrameHandle, gfh: PrincOps.GlobalFrameHandle] RETURNS[found: BOOLEAN _ FALSE] = INLINE {WHILE ValidFrame[f] DO IF f.accesslink = gfh THEN RETURN[TRUE]; f _ f.returnlink.frame; ENDLOOP}; LookForGFH: INTERNAL PROC[gfh: PrincOps.GlobalFrameHandle] RETURNS[notFound: BOOLEAN _ 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] 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 _ RTOS.MyLocalFrame[].returnlink.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] 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: BOOLEAN] = 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[BOOLEAN] = INLINE {RETURN[f # PrincOps.NullFrame AND LOOPHOLE[f, CARDINAL] MOD 4 = 0]}; InvalidProcess: PROC[px: PSB.PsbIndex] RETURNS[BOOLEAN] = { 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.